blob: 732c55719d5398f8b5c6f0baa992e9dd1b51caab [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.atlas.utils;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult;
import org.apache.atlas.model.notification.EntityNotification;
import org.apache.atlas.model.notification.EntityNotification.EntityNotificationType;
import org.apache.atlas.model.notification.EntityNotification.EntityNotificationV2;
import org.apache.atlas.model.notification.HookNotification;
import org.apache.atlas.model.notification.HookNotification.HookNotificationType;
import org.apache.atlas.model.notification.HookNotification.EntityCreateRequestV2;
import org.apache.atlas.model.notification.HookNotification.EntityDeleteRequestV2;
import org.apache.atlas.model.notification.HookNotification.EntityPartialUpdateRequestV2;
import org.apache.atlas.model.notification.HookNotification.EntityUpdateRequestV2;
import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import org.apache.atlas.v1.model.instance.AtlasSystemAttributes;
import org.apache.atlas.v1.model.instance.Id;
import org.apache.atlas.v1.model.instance.Referenceable;
import org.apache.atlas.v1.model.instance.Struct;
import org.apache.atlas.v1.model.notification.EntityNotificationV1;
import org.apache.atlas.v1.model.notification.HookNotificationV1.*;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class AtlasJson {
private static final Logger LOG = LoggerFactory.getLogger(AtlasJson.class);
private static final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
private static final ObjectMapper mapperV1 = new ObjectMapper()
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
private static final ObjectMapper mapperV1Search = new ObjectMapper()
.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
static {
SimpleModule atlasSerDeModule = new SimpleModule("AtlasSerDe", new Version(1, 0, 0, null));
atlasSerDeModule.addSerializer(Referenceable.class, new ReferenceableSerializer());
atlasSerDeModule.addDeserializer(Referenceable.class, new ReferenceableDeserializer());
atlasSerDeModule.addSerializer(Struct.class, new StructSerializer());
atlasSerDeModule.addDeserializer(Struct.class, new StructDeserializer());
atlasSerDeModule.addSerializer(Id.class, new IdSerializer());
atlasSerDeModule.addDeserializer(Id.class, new IdDeserializer());
atlasSerDeModule.addDeserializer(HookNotification.class, new HookNotificationDeserializer());
atlasSerDeModule.addDeserializer(EntityNotification.class, new EntityNotificationDeserializer());
mapper.registerModule(atlasSerDeModule);
SimpleModule atlasSerDeV1Module = new SimpleModule("AtlasSerDeV1", new Version(1, 0, 0, null));
atlasSerDeV1Module.addSerializer(Date.class, new DateSerializer());
atlasSerDeV1Module.addDeserializer(Date.class, new DateDeserializer());
mapperV1.registerModule(atlasSerDeV1Module);
SimpleModule searchResultV1SerDeModule = new SimpleModule("SearchResultV1SerDe", new Version(1, 0, 0, null));
searchResultV1SerDeModule.addSerializer(Referenceable.class, new V1SearchReferenceableSerializer());
searchResultV1SerDeModule.addSerializer(Struct.class, new V1SearchStructSerializer());
searchResultV1SerDeModule.addSerializer(Id.class, new V1SearchIdSerializer());
searchResultV1SerDeModule.addSerializer(AtlasSystemAttributes.class, new V1SearchSystemAttributesSerializer());
searchResultV1SerDeModule.addSerializer(AtlasFullTextResult.class, new V1SearchFullTextResultSerializer());
searchResultV1SerDeModule.addSerializer(Date.class, new DateSerializer());
mapperV1Search.registerModule(searchResultV1SerDeModule);
}
public static String toJson(Object obj) {
String ret;
try {
if (obj instanceof JsonNode && ((JsonNode) obj).isTextual()) {
ret = ((JsonNode) obj).textValue();
} else {
ret = mapper.writeValueAsString(obj);
}
}catch (IOException e){
LOG.error("AtlasJson.toJson()", e);
ret = null;
}
return ret;
}
public static <T> T fromLinkedHashMap(Object linkedHashMap, Class<T> type) {
T ret = null;
if (linkedHashMap != null) {
ret = mapper.convertValue(linkedHashMap, type);
if (ret instanceof Struct) {
((Struct) ret).normalize();
}
}
return ret;
}
public static <T> T fromJson(String jsonStr, Class<T> type) {
T ret = null;
if (jsonStr != null) {
try {
ret = mapper.readValue(jsonStr, type);
if (ret instanceof Struct) {
((Struct) ret).normalize();
}
} catch (IOException e) {
LOG.error("AtlasType.fromJson()", e);
ret = null;
}
}
return ret;
}
public static <T> T fromJson(String jsonStr, TypeReference<T> type) {
T ret = null;
if (jsonStr != null) {
try {
ret = mapper.readValue(jsonStr, type);
if (ret instanceof Struct) {
((Struct) ret).normalize();
}
} catch (IOException e) {
LOG.error("AtlasType.fromJson()", e);
ret = null;
}
}
return ret;
}
public static <T> T fromJson(InputStream inputStream, Class<T> type) throws IOException {
T ret = null;
if (inputStream != null) {
ret = mapper.readValue(inputStream, type);
if (ret instanceof Struct) {
((Struct) ret).normalize();
}
}
return ret;
}
public static String toV1Json(Object obj) {
return toJson(obj);
}
public static <T> T fromV1Json(String jsonStr, Class<T> type) {
return fromJson(jsonStr, type);
}
public static <T> T fromV1Json(String jsonStr, TypeReference<T> type) {
return fromJson(jsonStr, type);
}
public static String toV1SearchJson(Object obj) {
String ret;
try {
ret = mapperV1Search.writeValueAsString(obj);
}catch (IOException e){
LOG.error("AtlasType.toV1Json()", e);
ret = null;
}
return ret;
}
public static ObjectNode createV1ObjectNode() {
return mapperV1.createObjectNode();
}
public static ObjectNode createV1ObjectNode(String key, Object value) {
ObjectNode ret = mapperV1.createObjectNode();
ret.putPOJO(key, value);
return ret;
}
public static ArrayNode createV1ArrayNode() {
return mapperV1.createArrayNode();
}
public static ArrayNode createV1ArrayNode(Collection<?> array) {
ArrayNode ret = mapper.createArrayNode();
for (Object elem : array) {
ret.addPOJO(elem);
}
return ret;
}
public static JsonNode parseToV1JsonNode(String json) throws IOException {
JsonNode jsonNode = mapper.readTree(json);
return jsonNode;
}
public static ArrayNode parseToV1ArrayNode(String json) throws IOException {
JsonNode jsonNode = mapper.readTree(json);
if (jsonNode instanceof ArrayNode) {
return (ArrayNode)jsonNode;
}
throw new IOException("not an array");
}
public static ArrayNode parseToV1ArrayNode(Collection<String> jsonStrings) throws IOException {
ArrayNode ret = createV1ArrayNode();
for (String json : jsonStrings) {
JsonNode jsonNode = mapper.readTree(json);
ret.add(jsonNode);
}
return ret;
}
public static ObjectCodec getMapper() {
return mapper;
}
static class DateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (value != null) {
jgen.writeString(AtlasBaseTypeDef.getDateFormatter().format(value));
}
}
}
static class DateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Date ret = null;
String value = parser.readValueAs(String.class);
if (value != null) {
try {
ret = AtlasBaseTypeDef.getDateFormatter().parse(value);
} catch (ParseException excp) {
}
}
return ret;
}
}
static class ReferenceableSerializer extends JsonSerializer<Referenceable> {
@Override
public void serialize(Referenceable value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (value != null) {
mapperV1.writeValue(jgen, value);
}
}
}
static class ReferenceableDeserializer extends JsonDeserializer<Referenceable> {
@Override
public Referenceable deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Referenceable ret = mapperV1.readValue(parser, Referenceable.class);
return ret;
}
}
static class StructSerializer extends JsonSerializer<Struct> {
@Override
public void serialize(Struct value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (value != null) {
mapperV1.writeValue(jgen, value);
}
}
}
static class StructDeserializer extends JsonDeserializer<Struct> {
@Override
public Struct deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Struct ret = mapperV1.readValue(parser, Struct.class);
return ret;
}
}
static class IdSerializer extends JsonSerializer<Id> {
@Override
public void serialize(Id value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (value != null) {
mapperV1.writeValue(jgen, value);
}
}
}
static class IdDeserializer extends JsonDeserializer<Id> {
@Override
public Id deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Id ret = mapperV1.readValue(parser, Id.class);
return ret;
}
}
static class HookNotificationDeserializer extends JsonDeserializer<HookNotification> {
@Override
public HookNotification deserialize(JsonParser parser, DeserializationContext context) throws IOException {
HookNotification ret = null;
ObjectCodec mapper = parser.getCodec();
TreeNode root = mapper.readTree(parser);
JsonNode typeNode = root != null ? (JsonNode) root.get("type") : null;
String strType = typeNode != null ? typeNode.asText() : null;
HookNotificationType notificationType = strType != null ? HookNotificationType.valueOf(strType) : null;
if (notificationType != null) {
switch (notificationType) {
case TYPE_CREATE:
case TYPE_UPDATE:
ret = mapper.treeToValue(root, TypeRequest.class);
break;
case ENTITY_CREATE:
ret = mapper.treeToValue(root, EntityCreateRequest.class);
break;
case ENTITY_PARTIAL_UPDATE:
ret = mapper.treeToValue(root, EntityPartialUpdateRequest.class);
break;
case ENTITY_FULL_UPDATE:
ret = mapper.treeToValue(root, EntityUpdateRequest.class);
break;
case ENTITY_DELETE:
ret = mapper.treeToValue(root, EntityDeleteRequest.class);
break;
case ENTITY_CREATE_V2:
ret = mapper.treeToValue(root, EntityCreateRequestV2.class);
break;
case ENTITY_PARTIAL_UPDATE_V2:
ret = mapper.treeToValue(root, EntityPartialUpdateRequestV2.class);
break;
case ENTITY_FULL_UPDATE_V2:
ret = mapper.treeToValue(root, EntityUpdateRequestV2.class);
break;
case ENTITY_DELETE_V2:
ret = mapper.treeToValue(root, EntityDeleteRequestV2.class);
break;
}
}
return ret;
}
}
static class EntityNotificationDeserializer extends JsonDeserializer<EntityNotification> {
@Override
public EntityNotification deserialize(JsonParser parser, DeserializationContext context) throws IOException {
EntityNotification ret = null;
ObjectCodec mapper = parser.getCodec();
TreeNode root = mapper.readTree(parser);
JsonNode typeNode = root != null ? (JsonNode) root.get("type") : null;
String strType = typeNode != null ? typeNode.asText() : null;
EntityNotificationType notificationType = strType != null ? EntityNotificationType.valueOf(strType) : EntityNotificationType.ENTITY_NOTIFICATION_V1;
if (root != null) {
switch (notificationType) {
case ENTITY_NOTIFICATION_V1:
ret = mapper.treeToValue(root, EntityNotificationV1.class);
break;
case ENTITY_NOTIFICATION_V2:
ret = mapper.treeToValue(root, EntityNotificationV2.class);
break;
}
}
return ret;
}
}
private static final String V1_KEY_$TYPENAME = "$typeName$";
private static final String V1_KEY_$ID = "$id$";
private static final String V1_KEY_$SYSTEM_ATTRIBUTES = "$systemAttributes$";
private static final String V1_KEY_$TRAITS = "$traits$";
private static final String V1_KEY_TYPENAME = "typeName";
private static final String V1_KEY_ID = "id";
private static final String V1_KEY_GUID = "guid";
private static final String V1_KEY_SCORE = "score";
private static final String V1_KEY_VERSION = "version";
private static final String V1_KEY_STATE = "state";
private static final String V1_KEY_CREATED_BY = "createdBy";
private static final String V1_KEY_MODIFIED_BY = "modifiedBy";
private static final String V1_KEY_CREATED_TIME = "createdTime";
private static final String V1_KEY_MODIFIED_TIME = "modifiedTime";
static class V1SearchReferenceableSerializer extends JsonSerializer<Referenceable> {
@Override
public void serialize(Referenceable entity, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (entity != null) {
Map<String, Object> valueMap = entity.getValues() != null ? new HashMap<>(entity.getValues()) : new HashMap<>();
if (entity.getTypeName() != null) {
valueMap.put(V1_KEY_$TYPENAME, entity.getTypeName());
}
if (entity.getId() != null) {
valueMap.put(V1_KEY_$ID, entity.getId());
}
if (entity.getSystemAttributes() != null) {
valueMap.put(V1_KEY_$SYSTEM_ATTRIBUTES, entity.getSystemAttributes());
}
if (MapUtils.isNotEmpty(entity.getTraits())) {
valueMap.put(V1_KEY_$TRAITS, entity.getTraits());
}
jgen.writeObject(valueMap);
}
}
}
static class V1SearchStructSerializer extends JsonSerializer<Struct> {
@Override
public void serialize(Struct struct, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (struct != null) {
Map<String, Object> valueMap = struct.getValues() != null ? new HashMap<>(struct.getValues()) : new HashMap<>();
valueMap.put(V1_KEY_$TYPENAME, struct.getTypeName());
jgen.writeObject(valueMap);
}
}
}
static class V1SearchIdSerializer extends JsonSerializer<Id> {
@Override
public void serialize(Id id, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (id != null) {
Map<String, Object> valueMap = new HashMap<>();
valueMap.put(V1_KEY_ID, id._getId());
valueMap.put(V1_KEY_$TYPENAME, id.getTypeName());
valueMap.put(V1_KEY_VERSION, id.getVersion());
if (id.getState() != null) {
valueMap.put(V1_KEY_STATE, id.getState().toString());
}
jgen.writeObject(valueMap);
}
}
}
static class V1SearchSystemAttributesSerializer extends JsonSerializer<AtlasSystemAttributes> {
private static final ThreadLocal<DateFormat> V1_SEARCH_RESULT_DATE_FORMAT = new ThreadLocal<DateFormat>() {
@Override
public DateFormat initialValue() {
DateFormat ret = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
return ret;
}
};
@Override
public void serialize(AtlasSystemAttributes systemAttributes, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (systemAttributes != null) {
Map<String, Object> valueMap = new HashMap<>();
valueMap.put(V1_KEY_CREATED_BY, systemAttributes.getCreatedBy());
valueMap.put(V1_KEY_MODIFIED_BY, systemAttributes.getModifiedBy());
if (systemAttributes.getCreatedTime() != null) {
valueMap.put(V1_KEY_CREATED_TIME, V1_SEARCH_RESULT_DATE_FORMAT.get().format(systemAttributes.getCreatedTime()));
}
if (systemAttributes.getModifiedTime() != null) {
valueMap.put(V1_KEY_MODIFIED_TIME, V1_SEARCH_RESULT_DATE_FORMAT.get().format(systemAttributes.getModifiedTime()));
}
jgen.writeObject(valueMap);
}
}
}
static class V1SearchFullTextResultSerializer extends JsonSerializer<AtlasFullTextResult> {
@Override
public void serialize(AtlasFullTextResult result, JsonGenerator jgen, SerializerProvider provider) throws IOException {
if (result != null && result.getEntity() != null) {
Map<String, Object> valueMap = new HashMap<>();
valueMap.put(V1_KEY_GUID, result.getEntity().getGuid());
valueMap.put(V1_KEY_TYPENAME, result.getEntity().getTypeName());
valueMap.put(V1_KEY_SCORE, result.getScore());
jgen.writeObject(valueMap);
}
}
}
}