/** * 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; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.inject.Provider; import org.apache.atlas.listener.EntityChangeListener; import org.apache.atlas.listener.TypesChangeListener; import org.apache.atlas.repository.MetadataRepository; import org.apache.atlas.repository.graph.AtlasGraphProvider; import org.apache.atlas.repository.graph.GraphBackedMetadataRepository; import org.apache.atlas.repository.graph.GraphBackedSearchIndexer; import org.apache.atlas.repository.graph.GraphHelper; import org.apache.atlas.repository.graphdb.AtlasGraph; import org.apache.atlas.repository.graphdb.GremlinVersion; import org.apache.atlas.repository.typestore.GraphBackedTypeStore; import org.apache.atlas.repository.typestore.ITypeStore; import org.apache.atlas.services.DefaultMetadataService; import org.apache.atlas.services.MetadataService; import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.atlas.typesystem.IInstance; import org.apache.atlas.typesystem.ITypedReferenceableInstance; import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.TypesDef; import org.apache.atlas.typesystem.json.InstanceSerialization; import org.apache.atlas.typesystem.persistence.Id; import org.apache.atlas.typesystem.types.*; import org.apache.atlas.typesystem.types.DataTypes.TypeCategory; import org.apache.atlas.typesystem.types.cache.DefaultTypeCache; import org.apache.atlas.typesystem.types.cache.TypeCache; import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.util.AtlasRepositoryConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.RandomStringUtils; import org.codehaus.jettison.json.JSONArray; import org.testng.Assert; import org.testng.SkipException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static org.apache.atlas.typesystem.types.utils.TypesUtil.*; import static org.testng.Assert.assertEquals; /** * Test utility class. */ public final class TestUtils { public static final long TEST_DATE_IN_LONG = 1418265358440L; public static final String EMPLOYEES_ATTR = "employees"; public static final String DEPARTMENT_ATTR = "department"; public static final String ASSETS_ATTR = "assets"; public static final String POSITIONS_ATTR = "positions"; public static final String ASSET_TYPE = "TestAsset"; public static final String DATABASE_TYPE = "hive_database"; public static final String DATABASE_NAME = "foo"; public static final String TABLE_TYPE = "hive_table"; public static final String PROCESS_TYPE = "hive_process"; public static final String COLUMN_TYPE = "column_type"; public static final String TABLE_NAME = "bar"; public static final String CLASSIFICATION = "classification"; public static final String PII = "PII"; public static final String SUPER_TYPE_NAME = "Base"; public static final String STORAGE_DESC_TYPE = "hive_storagedesc"; public static final String PARTITION_STRUCT_TYPE = "partition_struct_type"; public static final String PARTITION_CLASS_TYPE = "partition_class_type"; public static final String SERDE_TYPE = "serdeType"; public static final String COLUMNS_MAP = "columnsMap"; public static final String COLUMNS_ATTR_NAME = "columns"; public static final String NAME = "name"; private TestUtils() { } /** * Dumps the graph in GSON format in the path returned. * * @param graph handle to graph * @return path to the dump file * @throws Exception */ public static String dumpGraph(AtlasGraph<?,?> graph) throws Exception { File tempFile = File.createTempFile("graph", ".gson"); System.out.println("tempFile.getPath() = " + tempFile.getPath()); GraphHelper.dumpToLog(graph); FileOutputStream os = null; try { os = new FileOutputStream(tempFile); graph.exportToGson(os); } finally { if(os != null) { try { os.close(); } catch(IOException e) { e.printStackTrace(); } } } return tempFile.getPath(); } /** * Class Hierarchy is: * Department(name : String, employees : Array[Person]) * Person(name : String, department : Department, manager : Manager) * Manager(subordinates : Array[Person]) extends Person * <p/> * Persons can have SecurityClearance(level : Int) clearance. */ public static void defineDeptEmployeeTypes(TypeSystem ts) throws AtlasException { String _description = "_description"; EnumTypeDefinition orgLevelEnum = new EnumTypeDefinition("OrgLevel", "OrgLevel"+_description, new EnumValue("L1", 1), new EnumValue("L2", 2)); StructTypeDefinition addressDetails = createStructTypeDef("Address", "Address"+_description, createRequiredAttrDef("street", DataTypes.STRING_TYPE), createRequiredAttrDef("city", DataTypes.STRING_TYPE)); HierarchicalTypeDefinition<ClassType> deptTypeDef = createClassTypeDef(DEPARTMENT_TYPE, "Department"+_description, ImmutableSet.<String>of(), createRequiredAttrDef(NAME, DataTypes.STRING_TYPE), new AttributeDefinition(EMPLOYEES_ATTR, String.format("array<%s>", "Person"), Multiplicity.OPTIONAL, true, DEPARTMENT_ATTR), new AttributeDefinition(POSITIONS_ATTR, String.format("map<%s,%s>", DataTypes.STRING_TYPE.getName(), "Person"), Multiplicity.OPTIONAL, false, null) ); HierarchicalTypeDefinition<ClassType> personTypeDef = createClassTypeDef("Person", "Person"+_description, ImmutableSet.<String>of(), createRequiredAttrDef(NAME, DataTypes.STRING_TYPE), createOptionalAttrDef("orgLevel", "OrgLevel"), createOptionalAttrDef("address", "Address"), new AttributeDefinition(DEPARTMENT_ATTR, "Department", Multiplicity.REQUIRED, false, EMPLOYEES_ATTR), new AttributeDefinition("manager", "Manager", Multiplicity.OPTIONAL, false, "subordinates"), new AttributeDefinition("mentor", "Person", Multiplicity.OPTIONAL, false, null), new AttributeDefinition(ASSETS_ATTR, String.format("array<%s>", ASSET_TYPE) , Multiplicity.OPTIONAL, false, null), createOptionalAttrDef("birthday", DataTypes.DATE_TYPE), createOptionalAttrDef("hasPets", DataTypes.BOOLEAN_TYPE), createOptionalAttrDef("numberOfCars", DataTypes.BYTE_TYPE), createOptionalAttrDef("houseNumber", DataTypes.SHORT_TYPE), createOptionalAttrDef("carMileage", DataTypes.INT_TYPE), createOptionalAttrDef("shares", DataTypes.LONG_TYPE), createOptionalAttrDef("salary", DataTypes.DOUBLE_TYPE), createOptionalAttrDef("age", DataTypes.FLOAT_TYPE), createOptionalAttrDef("numberOfStarsEstimate", DataTypes.BIGINTEGER_TYPE), createOptionalAttrDef("approximationOfPi", DataTypes.BIGDECIMAL_TYPE), createOptionalAttrDef("isOrganDonor", DataTypes.BOOLEAN_TYPE) ); HierarchicalTypeDefinition<ClassType> assetTypeDef = createClassTypeDef(ASSET_TYPE, "Asset"+_description, ImmutableSet.<String>of(), createRequiredAttrDef(NAME, DataTypes.STRING_TYPE), new AttributeDefinition("childAssets", String.format("array<%s>", ASSET_TYPE) , Multiplicity.OPTIONAL, false, null) ); HierarchicalTypeDefinition<ClassType> managerTypeDef = createClassTypeDef("Manager", "Manager"+_description, ImmutableSet.of("Person"), new AttributeDefinition("subordinates", String.format("array<%s>", "Person"), Multiplicity.COLLECTION, false, "manager")); HierarchicalTypeDefinition<TraitType> securityClearanceTypeDef = createTraitTypeDef("SecurityClearance", "SecurityClearance"+_description, ImmutableSet.<String>of(), createRequiredAttrDef("level", DataTypes.INT_TYPE)); ts.defineTypes(ImmutableList.of(orgLevelEnum), ImmutableList.of(addressDetails), ImmutableList.of(securityClearanceTypeDef), ImmutableList.of(deptTypeDef, personTypeDef, managerTypeDef, assetTypeDef)); } public static final String DEPARTMENT_TYPE = "Department"; public static final String PERSON_TYPE = "Person"; public static ITypedReferenceableInstance createDeptEg1(TypeSystem ts) throws AtlasException { Referenceable hrDept = new Referenceable(DEPARTMENT_TYPE); Referenceable john = new Referenceable(PERSON_TYPE); Referenceable jane = new Referenceable("Manager", "SecurityClearance"); Referenceable johnAddr = new Referenceable("Address"); Referenceable janeAddr = new Referenceable("Address"); Referenceable julius = new Referenceable("Manager"); Referenceable juliusAddr = new Referenceable("Address"); Referenceable max = new Referenceable("Person"); Referenceable maxAddr = new Referenceable("Address"); hrDept.set(NAME, "hr"); john.set(NAME, "John"); john.set(DEPARTMENT_ATTR, hrDept); johnAddr.set("street", "Stewart Drive"); johnAddr.set("city", "Sunnyvale"); john.set("address", johnAddr); john.set("birthday",new Date(1950, 5, 15)); john.set("isOrganDonor", true); john.set("hasPets", true); john.set("numberOfCars", 1); john.set("houseNumber", 153); john.set("carMileage", 13364); john.set("shares", 15000); john.set("salary", 123345.678); john.set("age", 50); john.set("numberOfStarsEstimate", new BigInteger("1000000000000000000000")); john.set("approximationOfPi", new BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286")); jane.set(NAME, "Jane"); jane.set(DEPARTMENT_ATTR, hrDept); janeAddr.set("street", "Great America Parkway"); janeAddr.set("city", "Santa Clara"); jane.set("address", janeAddr); janeAddr.set("street", "Great America Parkway"); julius.set(NAME, "Julius"); julius.set(DEPARTMENT_ATTR, hrDept); juliusAddr.set("street", "Madison Ave"); juliusAddr.set("city", "Newtonville"); julius.set("address", juliusAddr); julius.set("subordinates", ImmutableList.<Referenceable>of()); max.set(NAME, "Max"); max.set(DEPARTMENT_ATTR, hrDept); maxAddr.set("street", "Ripley St"); maxAddr.set("city", "Newton"); max.set("address", maxAddr); max.set("manager", jane); max.set("mentor", julius); max.set("birthday",new Date(1979, 3, 15)); max.set("isOrganDonor", true); max.set("hasPets", true); max.set("age", 36); max.set("numberOfCars", 2); max.set("houseNumber", 17); max.set("carMileage", 13); max.set("shares", Long.MAX_VALUE); max.set("salary", Double.MAX_VALUE); max.set("numberOfStarsEstimate", new BigInteger("1000000000000000000000000000000")); max.set("approximationOfPi", new BigDecimal("3.1415926535897932")); john.set("manager", jane); john.set("mentor", max); hrDept.set(EMPLOYEES_ATTR, ImmutableList.of(john, jane, julius, max)); jane.set("subordinates", ImmutableList.of(john, max)); jane.getTrait("SecurityClearance").set("level", 1); ClassType deptType = ts.getDataType(ClassType.class, "Department"); ITypedReferenceableInstance hrDept2 = deptType.convert(hrDept, Multiplicity.REQUIRED); Assert.assertNotNull(hrDept2); return hrDept2; } public static TypesDef simpleType(){ HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef("h_type", ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE)); StructTypeDefinition structTypeDefinition = new StructTypeDefinition("s_type", "structType", new AttributeDefinition[]{createRequiredAttrDef(NAME, DataTypes.STRING_TYPE)}); HierarchicalTypeDefinition<TraitType> traitTypeDefinition = createTraitTypeDef("t_type", "traitType", ImmutableSet.<String>of()); EnumValue values[] = {new EnumValue("ONE", 1),}; EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("e_type", "enumType", values); return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.of(structTypeDefinition), ImmutableList.of(traitTypeDefinition), ImmutableList.of(superTypeDefinition)); } public static TypesDef simpleTypeUpdated(){ HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef("h_type", ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE)); HierarchicalTypeDefinition<ClassType> newSuperTypeDefinition = createClassTypeDef("new_h_type", ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE)); StructTypeDefinition structTypeDefinition = new StructTypeDefinition("s_type", "structType", new AttributeDefinition[]{createRequiredAttrDef(NAME, DataTypes.STRING_TYPE)}); HierarchicalTypeDefinition<TraitType> traitTypeDefinition = createTraitTypeDef("t_type", "traitType", ImmutableSet.<String>of()); EnumValue values[] = {new EnumValue("ONE", 1),}; EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("e_type", "enumType", values); return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.of(structTypeDefinition), ImmutableList.of(traitTypeDefinition), ImmutableList.of(superTypeDefinition, newSuperTypeDefinition)); } public static TypesDef simpleTypeUpdatedDiff() { HierarchicalTypeDefinition<ClassType> newSuperTypeDefinition = createClassTypeDef("new_h_type", ImmutableSet.<String>of(), createOptionalAttrDef("attr", DataTypes.STRING_TYPE)); return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.of(newSuperTypeDefinition)); } public static TypesDef defineHiveTypes() { String _description = "_description"; HierarchicalTypeDefinition<ClassType> superTypeDefinition = createClassTypeDef(SUPER_TYPE_NAME, ImmutableSet.<String>of(), createOptionalAttrDef("namespace", DataTypes.STRING_TYPE), createOptionalAttrDef("cluster", DataTypes.STRING_TYPE), createOptionalAttrDef("colo", DataTypes.STRING_TYPE)); HierarchicalTypeDefinition<ClassType> databaseTypeDefinition = createClassTypeDef(DATABASE_TYPE, DATABASE_TYPE + _description,ImmutableSet.of(SUPER_TYPE_NAME), TypesUtil.createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE), createOptionalAttrDef("created", DataTypes.DATE_TYPE), createOptionalAttrDef("isReplicated", DataTypes.BOOLEAN_TYPE), new AttributeDefinition("parameters", new DataTypes.MapType(DataTypes.STRING_TYPE, DataTypes.STRING_TYPE).getName(), Multiplicity.OPTIONAL, false, null), createRequiredAttrDef("description", DataTypes.STRING_TYPE)); StructTypeDefinition structTypeDefinition = new StructTypeDefinition("serdeType", "serdeType" + _description, new AttributeDefinition[]{createRequiredAttrDef(NAME, DataTypes.STRING_TYPE), createRequiredAttrDef("serde", DataTypes.STRING_TYPE), createOptionalAttrDef("description", DataTypes.STRING_TYPE)}); EnumValue values[] = {new EnumValue("MANAGED", 1), new EnumValue("EXTERNAL", 2),}; EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition("tableType", "tableType" + _description, values); HierarchicalTypeDefinition<ClassType> columnsDefinition = createClassTypeDef(COLUMN_TYPE, ImmutableSet.<String>of(), createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE), createRequiredAttrDef("type", DataTypes.STRING_TYPE)); StructTypeDefinition partitionDefinition = new StructTypeDefinition("partition_struct_type", "partition_struct_type" + _description, new AttributeDefinition[]{createRequiredAttrDef(NAME, DataTypes.STRING_TYPE),}); AttributeDefinition[] attributeDefinitions = new AttributeDefinition[]{ new AttributeDefinition("location", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("inputFormat", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("outputFormat", DataTypes.STRING_TYPE.getName(), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("compressed", DataTypes.BOOLEAN_TYPE.getName(), Multiplicity.REQUIRED, false, null), new AttributeDefinition("numBuckets", DataTypes.INT_TYPE.getName(), Multiplicity.OPTIONAL, false, null), }; HierarchicalTypeDefinition<ClassType> storageDescClsDef = new HierarchicalTypeDefinition<>(ClassType.class, STORAGE_DESC_TYPE, STORAGE_DESC_TYPE + _description, ImmutableSet.of(SUPER_TYPE_NAME), attributeDefinitions); AttributeDefinition[] partClsAttributes = new AttributeDefinition[]{ new AttributeDefinition("values", DataTypes.arrayTypeName(DataTypes.STRING_TYPE.getName()), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("table", TABLE_TYPE, Multiplicity.REQUIRED, false, null), new AttributeDefinition("createTime", DataTypes.LONG_TYPE.getName(), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("lastAccessTime", DataTypes.LONG_TYPE.getName(), Multiplicity.OPTIONAL, false, null), new AttributeDefinition("sd", STORAGE_DESC_TYPE, Multiplicity.REQUIRED, true, null), new AttributeDefinition("columns", DataTypes.arrayTypeName(COLUMN_TYPE), Multiplicity.OPTIONAL, true, null), new AttributeDefinition("parameters", new DataTypes.MapType(DataTypes.STRING_TYPE, DataTypes.STRING_TYPE).getName(), Multiplicity.OPTIONAL, false, null),}; HierarchicalTypeDefinition<ClassType> partClsDef = new HierarchicalTypeDefinition<>(ClassType.class, "partition_class_type", "partition_class_type" + _description, ImmutableSet.of(SUPER_TYPE_NAME), partClsAttributes); HierarchicalTypeDefinition<ClassType> processClsType = new HierarchicalTypeDefinition<>(ClassType.class, PROCESS_TYPE, PROCESS_TYPE + _description, ImmutableSet.<String>of(), new AttributeDefinition[]{ new AttributeDefinition("outputs", "array<" + TABLE_TYPE + ">", Multiplicity.OPTIONAL, false, null) }); HierarchicalTypeDefinition<ClassType> tableTypeDefinition = createClassTypeDef(TABLE_TYPE, TABLE_TYPE + _description, ImmutableSet.of(SUPER_TYPE_NAME), TypesUtil.createUniqueRequiredAttrDef(NAME, DataTypes.STRING_TYPE), createRequiredAttrDef("description", DataTypes.STRING_TYPE), createRequiredAttrDef("type", DataTypes.STRING_TYPE), createOptionalAttrDef("created", DataTypes.DATE_TYPE), // enum new AttributeDefinition("tableType", "tableType", Multiplicity.REQUIRED, false, null), // array of strings new AttributeDefinition("columnNames", String.format("array<%s>", DataTypes.STRING_TYPE.getName()), Multiplicity.OPTIONAL, false, null), // array of classes new AttributeDefinition("columns", String.format("array<%s>", COLUMN_TYPE), Multiplicity.OPTIONAL, true, null), // array of structs new AttributeDefinition("partitions", String.format("array<%s>", "partition_struct_type"), Multiplicity.OPTIONAL, true, null), // map of primitives new AttributeDefinition("parametersMap", DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), DataTypes.STRING_TYPE.getName()), Multiplicity.OPTIONAL, true, null), //map of classes - new AttributeDefinition(COLUMNS_MAP, DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), COLUMN_TYPE), Multiplicity.OPTIONAL, true, null), //map of structs new AttributeDefinition("partitionsMap", DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), "partition_struct_type"), Multiplicity.OPTIONAL, true, null), // struct reference new AttributeDefinition("serde1", "serdeType", Multiplicity.OPTIONAL, false, null), new AttributeDefinition("serde2", "serdeType", Multiplicity.OPTIONAL, false, null), // class reference new AttributeDefinition("database", DATABASE_TYPE, Multiplicity.REQUIRED, false, null), //class reference as composite new AttributeDefinition("databaseComposite", DATABASE_TYPE, Multiplicity.OPTIONAL, true, null)); HierarchicalTypeDefinition<TraitType> piiTypeDefinition = createTraitTypeDef(PII, PII + _description, ImmutableSet.<String>of()); HierarchicalTypeDefinition<TraitType> classificationTypeDefinition = createTraitTypeDef(CLASSIFICATION, CLASSIFICATION + _description, ImmutableSet.<String>of(), createRequiredAttrDef("tag", DataTypes.STRING_TYPE)); HierarchicalTypeDefinition<TraitType> fetlClassificationTypeDefinition = createTraitTypeDef("fetl" + CLASSIFICATION, "fetl" + CLASSIFICATION + _description, ImmutableSet.of(CLASSIFICATION), createRequiredAttrDef("tag", DataTypes.STRING_TYPE)); return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.of(structTypeDefinition, partitionDefinition), ImmutableList.of(classificationTypeDefinition, fetlClassificationTypeDefinition, piiTypeDefinition), ImmutableList.of(superTypeDefinition, databaseTypeDefinition, columnsDefinition, tableTypeDefinition, storageDescClsDef, partClsDef, processClsType)); } public static Collection<IDataType> createHiveTypes(TypeSystem typeSystem) throws Exception { if (!typeSystem.isRegistered(TABLE_TYPE)) { TypesDef typesDef = defineHiveTypes(); return typeSystem.defineTypes(typesDef).values(); } return new ArrayList<>(); } public static final String randomString() { return RandomStringUtils.randomAlphanumeric(10); } public static Referenceable createDBEntity() { Referenceable entity = new Referenceable(DATABASE_TYPE); String dbName = RandomStringUtils.randomAlphanumeric(10); entity.set(NAME, dbName); entity.set("description", "us db"); return entity; } public static Referenceable createTableEntity(String dbId) { Referenceable entity = new Referenceable(TABLE_TYPE); String tableName = RandomStringUtils.randomAlphanumeric(10); entity.set(NAME, tableName); entity.set("description", "random table"); entity.set("type", "type"); entity.set("tableType", "MANAGED"); entity.set("database", new Id(dbId, 0, DATABASE_TYPE)); entity.set("created", new Date()); return entity; } public static Referenceable createColumnEntity() { Referenceable entity = new Referenceable(COLUMN_TYPE); entity.set(NAME, RandomStringUtils.randomAlphanumeric(10)); entity.set("type", "VARCHAR(32)"); return entity; } /** * Creates an entity in the graph and does basic validation * of the GuidMapping that was created in the process. * */ public static String createInstance(MetadataService metadataService, Referenceable entity) throws Exception { RequestContext.createContext(); String entityjson = InstanceSerialization.toJson(entity, true); JSONArray entitiesJson = new JSONArray(); entitiesJson.put(entityjson); CreateUpdateEntitiesResult creationResult = metadataService.createEntities(entitiesJson.toString()); Map<String,String> guidMap = creationResult.getGuidMapping().getGuidAssignments(); Map<Id, Referenceable> referencedObjects = findReferencedObjects(entity); for(Map.Entry<Id,Referenceable> entry : referencedObjects.entrySet()) { Id foundId = entry.getKey(); if(foundId.isUnassigned()) { String guid = guidMap.get(entry.getKey()._getId()); Referenceable obj = entry.getValue(); loadAndDoSimpleValidation(guid,obj, metadataService); } } List<String> guids = creationResult.getCreatedEntities(); if (guids != null && guids.size() > 0) { return guids.get(guids.size() - 1); } return null; } private static Map<Id,Referenceable> findReferencedObjects(Referenceable ref) { Map<Id, Referenceable> result = new HashMap<>(); findReferencedObjects(ref, result); return result; } private static void findReferencedObjects(Referenceable ref, Map<Id, Referenceable> seen) { Id guid = ref.getId(); if(seen.containsKey(guid)) { return; } seen.put(guid, ref); for(Map.Entry<String, Object> attr : ref.getValuesMap().entrySet()) { Object value = attr.getValue(); if(value instanceof Referenceable) { findReferencedObjects((Referenceable)value, seen); } else if(value instanceof List) { for(Object o : (List)value) { if(o instanceof Referenceable) { findReferencedObjects((Referenceable)o, seen); } } } else if(value instanceof Map) { for(Object o : ((Map)value).values()) { if(o instanceof Referenceable) { findReferencedObjects((Referenceable)o, seen); } } } } } /** * Clears the state in the request context. * */ public static void resetRequestContext() { //reset the context while preserving the user String user = RequestContext.get().getUser(); RequestContext.createContext(); RequestContext.get().setUser(user); } /** * Triggers the Atlas initialization process using the specified MetadataRepository. * This causes the built-in types and their indices to be created. */ public static void setupGraphProvider(MetadataRepository repo) throws AtlasException { TypeCache typeCache = null; try { typeCache = AtlasRepositoryConfiguration.getTypeCache().newInstance(); } catch(Throwable t) { typeCache = new DefaultTypeCache(); } final GraphBackedSearchIndexer indexer = new GraphBackedSearchIndexer(new AtlasTypeRegistry()); Provider<TypesChangeListener> indexerProvider = new Provider<TypesChangeListener>() { @Override public TypesChangeListener get() { return indexer; } }; Configuration config = ApplicationProperties.get(); ITypeStore typeStore = new GraphBackedTypeStore(); DefaultMetadataService defaultMetadataService = new DefaultMetadataService(repo, typeStore, Collections.singletonList(indexerProvider), new ArrayList<Provider<EntityChangeListener>>(), TypeSystem.getInstance(), config, typeCache); //commit the created types getGraph().commit(); } public static AtlasGraph getGraph() { return AtlasGraphProvider.getGraphInstance(); } /** * Adds a proxy wrapper around the specified MetadataService that automatically * resets the request context before every call. * * @param delegate * @return */ public static MetadataService addSessionCleanupWrapper(final MetadataService delegate) { return (MetadataService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{MetadataService.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { resetRequestContext(); Object result = method.invoke(delegate, args); return result; } catch(InvocationTargetException e) { e.getCause().printStackTrace(); throw e.getCause(); } catch(Throwable t) { t.printStackTrace(); throw t; } } }); } /** * Adds a proxy wrapper around the specified MetadataRepository that automatically * resets the request context before every call and either commits or rolls * back the graph transaction after every call. * * @param delegate * @return */ public static MetadataRepository addTransactionWrapper(final MetadataRepository delegate) { return (MetadataRepository)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{MetadataRepository.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { boolean useTransaction = GraphBackedMetadataRepository.class.getMethod( method.getName(), method.getParameterTypes()) .isAnnotationPresent(GraphTransaction.class); try { resetRequestContext(); Object result = method.invoke(delegate, args); if(useTransaction) { System.out.println("Committing changes"); getGraph().commit(); System.out.println("Commit succeeded."); } return result; } catch(InvocationTargetException e) { e.getCause().printStackTrace(); if(useTransaction) { System.out.println("Rolling back changes due to exception."); getGraph().rollback(); } throw e.getCause(); } catch(Throwable t) { t.printStackTrace(); if(useTransaction) { System.out.println("Rolling back changes due to exception."); getGraph().rollback(); } throw t; } } }); } /** * Loads the entity and does sanity testing of the GuidMapping that was * created during the operation. * */ public static ITypedReferenceableInstance loadAndDoSimpleValidation(String guid, Referenceable original, MetadataRepository repositoryService) throws AtlasException { ITypedReferenceableInstance loaded = repositoryService.getEntityDefinition(guid); doSimpleValidation(original, loaded); return loaded; } /** * Loads the entity and does sanity testing of the GuidMapping that was * created during the operation. * */ public static ITypedReferenceableInstance loadAndDoSimpleValidation(String guid, Referenceable original, MetadataService repositoryService) throws AtlasException { ITypedReferenceableInstance loaded = repositoryService.getEntityDefinition(guid); doSimpleValidation(original, loaded); return loaded; } private static void doSimpleValidation(Referenceable original, IInstance loaded) throws AtlasException { assertEquals(loaded.getTypeName(), original.getTypeName()); ClassType ct = TypeSystem.getInstance().getDataType(ClassType.class, loaded.getTypeName()); //compare primitive fields for(AttributeInfo field : ct.fieldMapping.fields.values()) { if(field.dataType().getTypeCategory() == TypeCategory.PRIMITIVE) { if(original.get(field.name) != null) { Object rawLoadedValue = loaded.get(field.name); Object rawProvidedValue = original.get(field.name); Object convertedLoadedValue = field.dataType().convert(rawLoadedValue, Multiplicity.REQUIRED); Object convertedProvidedValue = field.dataType().convert(rawProvidedValue, Multiplicity.REQUIRED); assertEquals(convertedLoadedValue, convertedProvidedValue); } } } } /** * Validates that the two String Collections contain the same items, without * regard to order. * */ public static void assertContentsSame(Collection<String> actual, Collection<String> expected) { assertEquals(actual.size(), expected.size()); Set<String> checker = new HashSet<>(); checker.addAll(expected); checker.removeAll(actual); assertEquals(checker.size(), 0); } public static void skipForGremlin3EnabledGraphDb() throws SkipException { //ATLAS-1579 Currently, some tests are skipped for titan1 backened. As these tests are hard coded to use Gremlin2. See ATLAS-1579, ATLAS-1591 once it is fixed, please remove it. if (TestUtils.getGraph().getSupportedGremlinVersion() == GremlinVersion.THREE) { throw new SkipException ("This test requires Gremlin2. Skipping test "); } } }