blob: 9b0aa4c0215cfeffce57ba401a2de734592d5a95 [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.discovery.graph;
import java.util.List;
import javax.inject.Inject;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RequestContext;
import org.apache.atlas.groovy.GroovyExpression;
import org.apache.atlas.query.GraphPersistenceStrategies;
import org.apache.atlas.query.GraphPersistenceStrategies$class;
import org.apache.atlas.query.TypeUtils;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.MetadataRepository;
import org.apache.atlas.repository.RepositoryException;
import org.apache.atlas.repository.graph.GraphBackedMetadataRepository;
import org.apache.atlas.repository.graph.GraphHelper;
import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.graphdb.GremlinVersion;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.ITypedStruct;
import org.apache.atlas.typesystem.persistence.Id;
import org.apache.atlas.typesystem.types.AttributeInfo;
import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructType;
import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
/**
* Default implementation of GraphPersistenceStrategy.
*/
public class DefaultGraphPersistenceStrategy implements GraphPersistenceStrategies {
private static final Logger LOG = LoggerFactory.getLogger(DefaultGraphPersistenceStrategy.class);
private final GraphBackedMetadataRepository metadataRepository;
@Inject
public DefaultGraphPersistenceStrategy(MetadataRepository metadataRepository) {
this.metadataRepository = (GraphBackedMetadataRepository) metadataRepository;
}
@Override
public String typeAttributeName() {
return metadataRepository.getTypeAttributeName();
}
@Override
public String superTypeAttributeName() {
return metadataRepository.getSuperTypeAttributeName();
}
@Override
public String edgeLabel(IDataType<?> dataType, AttributeInfo aInfo) {
try {
return metadataRepository.getEdgeLabel(dataType, aInfo);
} catch (AtlasException e) {
throw new RuntimeException(e);
}
}
@Override
public String traitLabel(IDataType<?> dataType, String traitName) {
return metadataRepository.getTraitLabel(dataType, traitName);
}
@Override
public String fieldNameInVertex(IDataType<?> dataType, AttributeInfo aInfo) {
try {
return metadataRepository.getFieldNameInVertex(dataType, aInfo);
} catch (AtlasException e) {
throw new RuntimeException(e);
}
}
@Override
public List<String> traitNames(AtlasVertex AtlasVertex) {
return GraphHelper.getTraitNames(AtlasVertex);
}
@Override
public Id getIdFromVertex(String dataTypeName, AtlasVertex vertex) {
return GraphHelper.getIdFromVertex(dataTypeName, vertex);
}
@Override
public ITypedReferenceableInstance constructClassInstanceId(ClassType classType, Object value) {
try {
AtlasVertex classVertex = (AtlasVertex) value;
ITypedReferenceableInstance classInstance = classType.createInstance(GraphHelper.getIdFromVertex(classVertex),
new String[0]);
return classType.convert(classInstance, Multiplicity.OPTIONAL);
} catch (AtlasException e) {
LOG.error("error while constructing an instance", e);
}
return null;
}
@Override
public <U> U constructInstance(IDataType<U> dataType, Object value) {
try {
switch (dataType.getTypeCategory()) {
case PRIMITIVE:
case ENUM:
return dataType.convert(value, Multiplicity.OPTIONAL);
case ARRAY:
DataTypes.ArrayType arrType = (DataTypes.ArrayType) dataType;
IDataType<?> elemType = arrType.getElemType();
ImmutableCollection.Builder result = ImmutableList.builder();
List list = (List) value;
for(Object listElement : list) {
Object collectionEntry = constructCollectionEntry(elemType, listElement);
if(collectionEntry != null) {
result.add(collectionEntry);
}
}
return (U)result.build();
case MAP:
// todo
break;
case STRUCT:
AtlasVertex structVertex = (AtlasVertex) value;
StructType structType = (StructType) dataType;
ITypedStruct structInstance = structType.createInstance();
TypeSystem.IdType idType = TypeSystem.getInstance().getIdType();
if (dataType.getName().equals(idType.getName())) {
structInstance.set(idType.typeNameAttrName(), GraphHelper.getSingleValuedProperty(structVertex, typeAttributeName(), String.class));
structInstance.set(idType.idAttrName(), GraphHelper.getSingleValuedProperty(structVertex, idAttributeName(), String.class));
String stateValue = GraphHelper.getSingleValuedProperty(structVertex, stateAttributeName(), String.class);
if (stateValue != null) {
structInstance.set(idType.stateAttrName(), stateValue);
}
structInstance.set(idType.versionAttrName(), structVertex.getProperty(versionAttributeName(), Integer.class));
} else {
metadataRepository.getGraphToInstanceMapper()
.mapVertexToInstance(structVertex, structInstance, structType.fieldMapping().fields);
}
return dataType.convert(structInstance, Multiplicity.OPTIONAL);
case TRAIT:
AtlasVertex traitVertex = (AtlasVertex) value;
TraitType traitType = (TraitType) dataType;
ITypedStruct traitInstance = traitType.createInstance();
// todo - this is not right, we should load the Instance associated with this
// trait. for now just loading the trait struct.
// metadataRepository.getGraphToInstanceMapper().mapVertexToTraitInstance(
// traitVertex, dataType.getName(), , traitType, traitInstance);
metadataRepository.getGraphToInstanceMapper()
.mapVertexToInstance(traitVertex, traitInstance, traitType.fieldMapping().fields);
break;
case CLASS:
AtlasVertex classVertex = (AtlasVertex) value;
String guid = classVertex.getProperty(Constants.GUID_PROPERTY_KEY, String.class);
// Check if the instance we need was previously loaded.
ITypedReferenceableInstance classInstance = RequestContext.get().getInstanceV1(guid);
if (classInstance == null) {
classInstance = metadataRepository.getGraphToInstanceMapper().mapGraphToTypedInstance(guid, classVertex);
}
return dataType.convert(classInstance, Multiplicity.OPTIONAL);
default:
throw new UnsupportedOperationException("Load for type " + dataType + "is not supported");
}
} catch (AtlasException e) {
LOG.error("error while constructing an instance", e);
}
return null;
}
public <U> U constructCollectionEntry(IDataType<U> elementType, Object value) throws AtlasException {
switch (elementType.getTypeCategory()) {
case PRIMITIVE:
case ENUM:
return constructInstance(elementType, value);
//The array values in case of STRUCT, CLASS contain the edgeId if the outgoing edge which links to the STRUCT, CLASS vertex referenced
case STRUCT:
case CLASS:
String edgeId = (String) value;
return (U) metadataRepository.getGraphToInstanceMapper().getReferredEntity(edgeId, elementType);
case ARRAY:
case MAP:
case TRAIT:
return null;
default:
throw new UnsupportedOperationException("Load for type " + elementType + " in collections is not supported");
}
}
@Override
public String edgeLabel(TypeUtils.FieldInfo fInfo) {
return fInfo.reverseDataType() == null ? edgeLabel(fInfo.dataType(), fInfo.attrInfo()) :
edgeLabel(fInfo.reverseDataType(), fInfo.attrInfo());
}
@Override
public AtlasEdgeDirection instanceToTraitEdgeDirection() {
return AtlasEdgeDirection.OUT;
}
@Override
public AtlasEdgeDirection traitToInstanceEdgeDirection() {
return AtlasEdgeDirection.IN;
}
@Override
public String idAttributeName() {
return metadataRepository.getIdAttributeName();
}
@Override
public String stateAttributeName() {
return metadataRepository.getStateAttributeName();
}
@Override
public String versionAttributeName() {
return metadataRepository.getVersionAttributeName();
}
@Override
public boolean collectTypeInstancesIntoVar() {
return GraphPersistenceStrategies$class.collectTypeInstancesIntoVar(this);
}
@Override
public boolean filterBySubTypes() {
return GraphPersistenceStrategies$class.filterBySubTypes(this);
}
@Override
public boolean addGraphVertexPrefix(scala.collection.Traversable<GroovyExpression> preStatements) {
return GraphPersistenceStrategies$class.addGraphVertexPrefix(this, preStatements);
}
@Override
public GremlinVersion getSupportedGremlinVersion() {
return GraphPersistenceStrategies$class.getSupportedGremlinVersion(this);
}
@Override
public GroovyExpression generatePersisentToLogicalConversionExpression(GroovyExpression expr, IDataType<?> t) {
return GraphPersistenceStrategies$class.generatePersisentToLogicalConversionExpression(this,expr, t);
}
@Override
public GroovyExpression addInitialQueryCondition(GroovyExpression expr) {
return GraphPersistenceStrategies$class.addInitialQueryCondition(this, expr);
}
@Override
public boolean isPropertyValueConversionNeeded(IDataType<?> t) {
return GraphPersistenceStrategies$class.isPropertyValueConversionNeeded(this, t);
}
@Override
public AtlasGraph getGraph() throws RepositoryException {
return metadataRepository.getGraph();
}
}