Commit cef91eb8 by Madhan Neethiraj

ATLAS-2347: fix V1 REST API for search to keep the response consistent with…

ATLAS-2347: fix V1 REST API for search to keep the response consistent with earlier version of Atlas
parent c9303742
......@@ -24,21 +24,30 @@ 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.HookNotification;
import org.apache.atlas.model.notification.HookNotification.HookNotificationType;
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.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 {
......@@ -50,6 +59,9 @@ public class AtlasJson {
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));
......@@ -59,6 +71,17 @@ public class AtlasJson {
atlasSerDeModule.addDeserializer(EntityNotification.class, new EntityNotificationDeserializer());
mapperV1.registerModule(atlasSerDeModule);
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) {
......@@ -125,6 +148,18 @@ public class AtlasJson {
return ret;
}
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();
......@@ -268,4 +303,124 @@ public class AtlasJson {
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);
}
}
}
}
/**
* 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.v1.model.discovery;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.atlas.v1.model.instance.Referenceable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.*;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.ALWAYS)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class DSLSearchResult implements Serializable {
private static final long serialVersionUID = 1L;
private String requestId;
private String queryType;
private String query;
private String dataType;
private int count = 0;
private List<Referenceable> results;
public DSLSearchResult() {
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getQueryType() {
return queryType;
}
public void setQueryType(String queryType) {
this.queryType = queryType;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List<Referenceable> getResults() {
return results;
}
public void setResults(List<Referenceable> results) {
this.results = results;
}
public void addResult(Referenceable entity) {
if (this.results == null) {
this.results = new ArrayList<>();
}
this.results.add(entity);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DSLSearchResult obj = (DSLSearchResult) o;
return Objects.equals(requestId, obj.requestId) &&
Objects.equals(queryType, obj.queryType) &&
Objects.equals(query, obj.query) &&
Objects.equals(dataType, obj.dataType) &&
Objects.equals(count, obj.count) &&
Objects.equals(results, obj.results);
}
@Override
public int hashCode() {
return Objects.hash(requestId, queryType, query, dataType, count, results);
}
@Override
public String toString() {
return toString(new StringBuilder()).toString();
}
public StringBuilder toString(StringBuilder sb) {
if (sb == null) {
sb = new StringBuilder();
}
sb.append("FullTextSearchResult{")
.append("requestId=").append(requestId)
.append(", queryType=").append(queryType)
.append(", query=").append(query)
.append(", dataType=").append(dataType)
.append(", count=").append(count)
.append(", results=").append(results)
.append("}");
return sb;
}
}
/**
* 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.v1.model.discovery;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.*;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.PUBLIC_ONLY;
@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
@JsonSerialize(include=JsonSerialize.Inclusion.ALWAYS)
@JsonIgnoreProperties(ignoreUnknown=true)
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class FullTextSearchResult implements Serializable {
private static final long serialVersionUID = 1L;
private String requestId;
private String queryType;
private String query;
private String dataType;
private int count = 0;
private List<AtlasFullTextResult> results;
public FullTextSearchResult() {
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getQueryType() {
return queryType;
}
public void setQueryType(String queryType) {
this.queryType = queryType;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List<AtlasFullTextResult> getResults() {
return results;
}
public void setResults(List<AtlasFullTextResult> results) {
this.results = results;
}
public void addResult(AtlasFullTextResult result) {
if (this.results == null) {
this.results = new ArrayList<>();
}
this.results.add(result);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FullTextSearchResult obj = (FullTextSearchResult) o;
return Objects.equals(requestId, obj.requestId) &&
Objects.equals(queryType, obj.queryType) &&
Objects.equals(query, obj.query) &&
Objects.equals(dataType, obj.dataType) &&
Objects.equals(count, obj.count) &&
Objects.equals(results, obj.results);
}
@Override
public int hashCode() {
return Objects.hash(requestId, queryType, query, dataType, count, results);
}
@Override
public String toString() {
return toString(new StringBuilder()).toString();
}
public StringBuilder toString(StringBuilder sb) {
if (sb == null) {
sb = new StringBuilder();
}
sb.append("FullTextSearchResult{")
.append("requestId=").append(requestId)
.append(", queryType=").append(queryType)
.append(", query=").append(query)
.append(", dataType=").append(dataType)
.append(", count=").append(count)
.append(", results=").append(results)
.append("}");
return sb;
}
}
......@@ -117,14 +117,15 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
@Override
@GraphTransaction
public AtlasSearchResult searchUsingDslQuery(String dslQuery, int limit, int offset) throws AtlasBaseException {
AtlasSearchResult ret = new AtlasSearchResult(dslQuery, AtlasQueryType.DSL);
GremlinQuery gremlinQuery = toGremlinQuery(dslQuery, limit, offset);
AtlasSearchResult ret = new AtlasSearchResult(dslQuery, AtlasQueryType.DSL);
GremlinQuery gremlinQuery = toGremlinQuery(dslQuery, limit, offset);
String queryStr = gremlinQuery.queryStr();
if (LOG.isDebugEnabled()) {
LOG.debug("Executing DSL query: {}", dslQuery);
LOG.debug("Executing DSL: query={}, gremlinQuery={}", dslQuery, queryStr);
}
Object result = graph.executeGremlinScript(gremlinQuery.queryStr(), false);
Object result = graph.executeGremlinScript(queryStr, false);
if (result instanceof List && CollectionUtils.isNotEmpty((List)result)) {
List queryResult = (List) result;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment