Commit bf5672c5 by Suma Shivaprasad

ATLAS-171 Ability to update type definition(shwethags via sumasai)

parent 919120f6
...@@ -34,7 +34,7 @@ import org.apache.atlas.typesystem.types.Multiplicity; ...@@ -34,7 +34,7 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructType; import org.apache.atlas.typesystem.types.StructType;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeUtils; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -102,7 +102,7 @@ public class HiveDataModelGenerator { ...@@ -102,7 +102,7 @@ public class HiveDataModelGenerator {
} }
public TypesDef getTypesDef() { public TypesDef getTypesDef() {
return TypeUtils.getTypesDef(getEnumTypeDefinitions(), getStructTypeDefinitions(), getTraitTypeDefinitions(), return TypesUtil.getTypesDef(getEnumTypeDefinitions(), getStructTypeDefinitions(), getTraitTypeDefinitions(),
getClassTypeDefinitions()); getClassTypeDefinitions());
} }
......
...@@ -25,7 +25,9 @@ import com.sun.jersey.api.client.config.DefaultClientConfig; ...@@ -25,7 +25,9 @@ import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import org.apache.atlas.security.SecureClientUtils; import org.apache.atlas.security.SecureClientUtils;
import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.json.InstanceSerialization; import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.atlas.typesystem.json.TypesSerialization;
import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation;
...@@ -132,6 +134,7 @@ public class AtlasClient { ...@@ -132,6 +134,7 @@ public class AtlasClient {
//Type operations //Type operations
CREATE_TYPE(BASE_URI + TYPES, HttpMethod.POST), CREATE_TYPE(BASE_URI + TYPES, HttpMethod.POST),
UPDATE_TYPE(BASE_URI + TYPES, HttpMethod.PUT),
GET_TYPE(BASE_URI + TYPES, HttpMethod.GET), GET_TYPE(BASE_URI + TYPES, HttpMethod.GET),
LIST_TYPES(BASE_URI + TYPES, HttpMethod.GET), LIST_TYPES(BASE_URI + TYPES, HttpMethod.GET),
LIST_TRAIT_TYPES(BASE_URI + TYPES + "?type=trait", HttpMethod.GET), LIST_TRAIT_TYPES(BASE_URI + TYPES + "?type=trait", HttpMethod.GET),
...@@ -181,13 +184,45 @@ public class AtlasClient { ...@@ -181,13 +184,45 @@ public class AtlasClient {
* @return result json object * @return result json object
* @throws AtlasServiceException * @throws AtlasServiceException
*/ */
public JSONObject createType(String typeAsJson) throws AtlasServiceException { public List<String> createType(String typeAsJson) throws AtlasServiceException {
return callAPI(API.CREATE_TYPE, typeAsJson); JSONObject response = callAPI(API.CREATE_TYPE, typeAsJson);
return extractResults(response, AtlasClient.TYPES);
}
/**
* Register the given type(meta model)
* @param typeDef type definition
* @return result json object
* @throws AtlasServiceException
*/
public List<String> createType(TypesDef typeDef) throws AtlasServiceException {
return createType(TypesSerialization.toJson(typeDef));
}
/**
* Register the given type(meta model)
* @param typeAsJson type definition a jaon
* @return result json object
* @throws AtlasServiceException
*/
public List<String> updateType(String typeAsJson) throws AtlasServiceException {
JSONObject response = callAPI(API.UPDATE_TYPE, typeAsJson);
return extractResults(response, AtlasClient.TYPES);
}
/**
* Register the given type(meta model)
* @param typeDef type definition
* @return result json object
* @throws AtlasServiceException
*/
public List<String> updateType(TypesDef typeDef) throws AtlasServiceException {
return updateType(TypesSerialization.toJson(typeDef));
} }
public List<String> listTypes() throws AtlasServiceException { public List<String> listTypes() throws AtlasServiceException {
final JSONObject jsonObject = callAPI(API.LIST_TYPES, null); final JSONObject jsonObject = callAPI(API.LIST_TYPES, null);
return extractResults(jsonObject); return extractResults(jsonObject, AtlasClient.RESULTS);
} }
public String getType(String typeName) throws AtlasServiceException { public String getType(String typeName) throws AtlasServiceException {
...@@ -230,6 +265,14 @@ public class AtlasClient { ...@@ -230,6 +265,14 @@ public class AtlasClient {
return createEntity(new JSONArray(Arrays.asList(entitiesAsJson))); return createEntity(new JSONArray(Arrays.asList(entitiesAsJson)));
} }
public JSONArray createEntity(Referenceable... entities) throws AtlasServiceException {
JSONArray entityArray = new JSONArray(entities.length);
for (Referenceable entity : entities) {
entityArray.put(InstanceSerialization.toJson(entity, true));
}
return createEntity(entityArray);
}
/** /**
* Get an entity given the entity id * Get an entity given the entity id
* @param guid entity id * @param guid entity id
...@@ -286,15 +329,20 @@ public class AtlasClient { ...@@ -286,15 +329,20 @@ public class AtlasClient {
WebResource resource = getResource(API.LIST_ENTITIES); WebResource resource = getResource(API.LIST_ENTITIES);
resource = resource.queryParam(TYPE, entityType); resource = resource.queryParam(TYPE, entityType);
JSONObject jsonResponse = callAPIWithResource(API.LIST_ENTITIES, resource); JSONObject jsonResponse = callAPIWithResource(API.LIST_ENTITIES, resource);
return extractResults(jsonResponse); return extractResults(jsonResponse, AtlasClient.RESULTS);
} }
private List<String> extractResults(JSONObject jsonResponse) throws AtlasServiceException { private List<String> extractResults(JSONObject jsonResponse, String key) throws AtlasServiceException {
try { try {
JSONArray results = jsonResponse.getJSONArray(AtlasClient.RESULTS); JSONArray results = jsonResponse.getJSONArray(key);
ArrayList<String> resultsList = new ArrayList<>(); ArrayList<String> resultsList = new ArrayList<>();
for (int index = 0; index < results.length(); index++) { for (int index = 0; index < results.length(); index++) {
resultsList.add(results.getString(index)); Object element = results.get(index);
if (element instanceof String) {
resultsList.add((String) element);
} else if (element instanceof JSONObject) {
resultsList.add(((JSONObject) element).getString(AtlasClient.NAME));
}
} }
return resultsList; return resultsList;
} catch (JSONException e) { } catch (JSONException e) {
......
...@@ -44,6 +44,6 @@ public interface TypesChangeListener { ...@@ -44,6 +44,6 @@ public interface TypesChangeListener {
*/ */
// void onRemove(String typeName) throws MetadataException; // void onRemove(String typeName) throws MetadataException;
// This is upon updating an existing type to the store //This is upon updating an existing type to the store
// void onChange() throws MetadataException; void onChange(Collection<? extends IDataType> dataTypes) throws AtlasException;
} }
...@@ -1426,6 +1426,7 @@ ...@@ -1426,6 +1426,7 @@
<reuseForks>false</reuseForks> <reuseForks>false</reuseForks>
<forkCount>1</forkCount> <forkCount>1</forkCount>
<threadCount>5</threadCount> <threadCount>5</threadCount>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
......
...@@ -9,6 +9,7 @@ ATLAS-54 Rename configs in hive hook (shwethags) ...@@ -9,6 +9,7 @@ ATLAS-54 Rename configs in hive hook (shwethags)
ATLAS-3 Mixed Index creation fails with Date types (sumasai via shwethags) ATLAS-3 Mixed Index creation fails with Date types (sumasai via shwethags)
ALL CHANGES: ALL CHANGES:
ATLAS-171 Ability to update type definition(shwethags via sumasai)
ATLAS-352 Improve write performance on type and entity creation with Hbase (sumasai) ATLAS-352 Improve write performance on type and entity creation with Hbase (sumasai)
ATLAS-350 Document jaas config details for atlas (tbeerbower via shwethags) ATLAS-350 Document jaas config details for atlas (tbeerbower via shwethags)
ATLAS-344 Document HBase permissions for secure cluster (tbeerbower via shwethags) ATLAS-344 Document HBase permissions for secure cluster (tbeerbower via shwethags)
......
...@@ -161,6 +161,11 @@ public class GraphBackedSearchIndexer implements SearchIndexer { ...@@ -161,6 +161,11 @@ public class GraphBackedSearchIndexer implements SearchIndexer {
commit(); commit();
} }
@Override
public void onChange(Collection<? extends IDataType> dataTypes) throws AtlasException {
onAdd(dataTypes);
}
private void addIndexForType(IDataType dataType) { private void addIndexForType(IDataType dataType) {
switch (dataType.getTypeCategory()) { switch (dataType.getTypeCategory()) {
case PRIMITIVE: case PRIMITIVE:
......
...@@ -45,6 +45,7 @@ import org.apache.atlas.typesystem.types.StructTypeDefinition; ...@@ -45,6 +45,7 @@ import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem; import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.TypeUtils; import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -253,7 +254,7 @@ public class GraphBackedTypeStore implements ITypeStore { ...@@ -253,7 +254,7 @@ public class GraphBackedTypeStore implements ITypeStore {
throw new IllegalArgumentException("Unhandled type category " + typeCategory); throw new IllegalArgumentException("Unhandled type category " + typeCategory);
} }
} }
return TypeUtils.getTypesDef(enums.build(), structs.build(), traits.build(), classTypes.build()); return TypesUtil.getTypesDef(enums.build(), structs.build(), traits.build(), classTypes.build());
} }
private EnumTypeDefinition getEnumType(Vertex vertex) { private EnumTypeDefinition getEnumType(Vertex vertex) {
......
...@@ -50,7 +50,6 @@ import org.apache.atlas.typesystem.types.Multiplicity; ...@@ -50,7 +50,6 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem; import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.ValueConversionException; import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONArray;
...@@ -148,8 +147,7 @@ public class DefaultMetadataService implements MetadataService { ...@@ -148,8 +147,7 @@ public class DefaultMetadataService implements MetadataService {
private void createType(HierarchicalTypeDefinition<ClassType> type) throws AtlasException { private void createType(HierarchicalTypeDefinition<ClassType> type) throws AtlasException {
if (!typeSystem.isRegistered(type.typeName)) { if (!typeSystem.isRegistered(type.typeName)) {
TypesDef typesDef = TypeUtils TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of(type)); ImmutableList.of(type));
createType(TypesSerialization.toJson(typesDef)); createType(TypesSerialization.toJson(typesDef));
...@@ -191,6 +189,34 @@ public class DefaultMetadataService implements MetadataService { ...@@ -191,6 +189,34 @@ public class DefaultMetadataService implements MetadataService {
} }
} }
@Override
public JSONObject updateType(String typeDefinition) throws AtlasException {
ParamChecker.notEmpty(typeDefinition, "type definition cannot be empty");
TypesDef typesDef = validateTypeDefinition(typeDefinition);
try {
final Map<String, IDataType> typesAdded = typeSystem.updateTypes(typesDef);
try {
/* Create indexes first so that if index creation fails then we rollback
the typesystem and also do not persist the graph
*/
onTypesUpdated(typesAdded);
typeStore.store(typeSystem, ImmutableList.copyOf(typesAdded.keySet()));
} catch (Throwable t) {
typeSystem.removeTypes(typesAdded.keySet());
throw new AtlasException("Unable to persist types ", t);
}
return new JSONObject() {{
put(AtlasClient.TYPES, typesAdded.keySet());
}};
} catch (JSONException e) {
LOG.error("Unable to create response for types={}", typeDefinition, e);
throw new AtlasException("Unable to create response ", e);
}
}
private TypesDef validateTypeDefinition(String typeDefinition) { private TypesDef validateTypeDefinition(String typeDefinition) {
try { try {
TypesDef typesDef = TypesSerialization.fromJson(typeDefinition); TypesDef typesDef = TypesSerialization.fromJson(typeDefinition);
...@@ -343,7 +369,7 @@ public class DefaultMetadataService implements MetadataService { ...@@ -343,7 +369,7 @@ public class DefaultMetadataService implements MetadataService {
repository.updateEntity(guid, property, value); repository.updateEntity(guid, property, value);
onEntityUpdated(repository.getEntityDefinition(guid), property, value); onEntityUpdated(repository.getEntityDefinition(guid));
} }
private void validateTypeExists(String entityType) throws AtlasException { private void validateTypeExists(String entityType) throws AtlasException {
...@@ -466,7 +492,24 @@ public class DefaultMetadataService implements MetadataService { ...@@ -466,7 +492,24 @@ public class DefaultMetadataService implements MetadataService {
} }
} }
private void onEntityUpdated(ITypedReferenceableInstance entity, String property, String value) private void onTypesUpdated(Map<String, IDataType> typesUpdated) throws AtlasException {
Map<TypesChangeListener, Throwable> caughtExceptions = new HashMap<>();
for (Provider<TypesChangeListener> indexerProvider : typeChangeListeners) {
final TypesChangeListener listener = indexerProvider.get();
try {
listener.onChange(typesUpdated.values());
} catch (IndexCreationException ice) {
LOG.error("Index creation for listener {} failed ", indexerProvider, ice);
caughtExceptions.put(listener, ice);
}
}
if (caughtExceptions.size() > 0) {
throw new IndexCreationException("Index creation failed for types " + typesUpdated.keySet() + ". Aborting");
}
}
private void onEntityUpdated(ITypedReferenceableInstance entity)
throws AtlasException { throws AtlasException {
for (EntityChangeListener listener : entityChangeListeners) { for (EntityChangeListener listener : entityChangeListeners) {
listener.onEntityUpdated(entity); listener.onEntityUpdated(entity);
......
...@@ -40,6 +40,14 @@ public interface MetadataService { ...@@ -40,6 +40,14 @@ public interface MetadataService {
JSONObject createType(String typeDefinition) throws AtlasException; JSONObject createType(String typeDefinition) throws AtlasException;
/** /**
* Updates the given types in the type definition
* @param typeDefinition
* @return
* @throws AtlasException
*/
JSONObject updateType(String typeDefinition) throws AtlasException;
/**
* Return the definition for the given type. * Return the definition for the given type.
* *
* @param typeName name for this type, must be unique * @param typeName name for this type, must be unique
......
...@@ -28,7 +28,6 @@ import org.apache.atlas.services.DefaultMetadataService; ...@@ -28,7 +28,6 @@ import org.apache.atlas.services.DefaultMetadataService;
import org.apache.atlas.typesystem.ITypedReferenceableInstance; import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.TypesDef; import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.atlas.typesystem.json.TypesSerialization; import org.apache.atlas.typesystem.json.TypesSerialization;
import org.apache.atlas.typesystem.persistence.Id; import org.apache.atlas.typesystem.persistence.Id;
import org.apache.atlas.typesystem.types.AttributeDefinition; import org.apache.atlas.typesystem.types.AttributeDefinition;
...@@ -41,10 +40,7 @@ import org.apache.atlas.typesystem.types.Multiplicity; ...@@ -41,10 +40,7 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem; import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Guice; import org.testng.annotations.Guice;
import javax.inject.Inject; import javax.inject.Inject;
...@@ -170,7 +166,7 @@ public class BaseHiveRepositoryTest { ...@@ -170,7 +166,7 @@ public class BaseHiveRepositoryTest {
HierarchicalTypeDefinition<TraitType> jdbcTraitDef = TypesUtil.createTraitTypeDef("JdbcAccess", null); HierarchicalTypeDefinition<TraitType> jdbcTraitDef = TypesUtil.createTraitTypeDef("JdbcAccess", null);
return TypeUtils.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.of(dimTraitDef, factTraitDef, piiTraitDef, metricTraitDef, etlTraitDef, jdbcTraitDef), ImmutableList.of(dimTraitDef, factTraitDef, piiTraitDef, metricTraitDef, etlTraitDef, jdbcTraitDef),
ImmutableList.of(dbClsDef, storageDescClsDef, columnClsDef, tblClsDef, loadProcessClsDef, viewClsDef, partClsDef)); ImmutableList.of(dbClsDef, storageDescClsDef, columnClsDef, tblClsDef, loadProcessClsDef, viewClsDef, partClsDef));
} }
......
...@@ -38,7 +38,6 @@ import org.apache.atlas.typesystem.types.Multiplicity; ...@@ -38,7 +38,6 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem; import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.RandomStringUtils;
import org.testng.Assert; import org.testng.Assert;
...@@ -272,7 +271,7 @@ public final class TestUtils { ...@@ -272,7 +271,7 @@ public final class TestUtils {
createTraitTypeDef("fetl" + CLASSIFICATION, ImmutableList.of(CLASSIFICATION), createTraitTypeDef("fetl" + CLASSIFICATION, ImmutableList.of(CLASSIFICATION),
createRequiredAttrDef("tag", DataTypes.STRING_TYPE)); createRequiredAttrDef("tag", DataTypes.STRING_TYPE));
return TypeUtils.getTypesDef(ImmutableList.of(enumTypeDefinition), return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition),
ImmutableList.of(structTypeDefinition, partitionDefinition), ImmutableList.of(structTypeDefinition, partitionDefinition),
ImmutableList.of(classificationTypeDefinition, fetlClassificationTypeDefinition, piiTypeDefinition), ImmutableList.of(classificationTypeDefinition, fetlClassificationTypeDefinition, piiTypeDefinition),
ImmutableList.of(superTypeDefinition, databaseTypeDefinition, columnsDefinition, tableTypeDefinition)); ImmutableList.of(superTypeDefinition, databaseTypeDefinition, columnsDefinition, tableTypeDefinition));
......
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
package org.apache.atlas.repository.typestore; package org.apache.atlas.repository.typestore;
import com.google.common.collect.ImmutableList;
import com.thinkaurelius.titan.core.TitanGraph; import com.thinkaurelius.titan.core.TitanGraph;
import com.thinkaurelius.titan.core.util.TitanCleanup; import com.thinkaurelius.titan.core.util.TitanCleanup;
import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.blueprints.Vertex;
import org.apache.atlas.AtlasException; import org.apache.atlas.AtlasException;
import org.apache.atlas.GraphTransaction;
import org.apache.atlas.RepositoryMetadataModule; import org.apache.atlas.RepositoryMetadataModule;
import org.apache.atlas.TestUtils; import org.apache.atlas.TestUtils;
import org.apache.atlas.repository.graph.GraphHelper; import org.apache.atlas.repository.graph.GraphHelper;
...@@ -33,21 +33,30 @@ import org.apache.atlas.typesystem.TypesDef; ...@@ -33,21 +33,30 @@ import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.AttributeDefinition; import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.ClassType; import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes; import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.EnumType;
import org.apache.atlas.typesystem.types.EnumTypeDefinition; import org.apache.atlas.typesystem.types.EnumTypeDefinition;
import org.apache.atlas.typesystem.types.EnumValue; import org.apache.atlas.typesystem.types.EnumValue;
import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition; import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition;
import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructType;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem; import org.apache.atlas.typesystem.types.TypeSystem;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Guice; import org.testng.annotations.Guice;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.testng.Assert;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List; import java.util.List;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createClassTypeDef;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createOptionalAttrDef;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createRequiredAttrDef;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createStructTypeDef;
@Guice(modules = RepositoryMetadataModule.class) @Guice(modules = RepositoryMetadataModule.class)
public class GraphBackedTypeStoreTest { public class GraphBackedTypeStoreTest {
@Inject @Inject
...@@ -77,7 +86,6 @@ public class GraphBackedTypeStoreTest { ...@@ -77,7 +86,6 @@ public class GraphBackedTypeStoreTest {
} }
@Test @Test
@GraphTransaction
public void testStore() throws AtlasException { public void testStore() throws AtlasException {
typeStore.store(ts); typeStore.store(ts);
dumpGraph(); dumpGraph();
...@@ -137,4 +145,54 @@ public class GraphBackedTypeStoreTest { ...@@ -137,4 +145,54 @@ public class GraphBackedTypeStoreTest {
ts.reset(); ts.reset();
ts.defineTypes(types); ts.defineTypes(types);
} }
@Test(dependsOnMethods = "testStore")
public void testTypeUpdate() throws Exception {
//Add enum value
EnumTypeDefinition orgLevelEnum = new EnumTypeDefinition("OrgLevel", new EnumValue("L1", 1),
new EnumValue("L2", 2), new EnumValue("L3", 3));
//Add attribute
StructTypeDefinition addressDetails =
createStructTypeDef("Address", createRequiredAttrDef("street", DataTypes.STRING_TYPE),
createRequiredAttrDef("city", DataTypes.STRING_TYPE),
createOptionalAttrDef("state", DataTypes.STRING_TYPE));
//Add supertype
HierarchicalTypeDefinition<ClassType> superTypeDef = createClassTypeDef("Division", ImmutableList.<String>of(),
createOptionalAttrDef("dname", DataTypes.STRING_TYPE));
HierarchicalTypeDefinition<ClassType> deptTypeDef = createClassTypeDef("Department",
ImmutableList.of(superTypeDef.typeName), createRequiredAttrDef("name", DataTypes.STRING_TYPE),
new AttributeDefinition("employees", String.format("array<%s>", "Person"), Multiplicity.COLLECTION,
true, "department"));
TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.of(orgLevelEnum), ImmutableList.of(addressDetails),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of(deptTypeDef, superTypeDef));
ts.updateTypes(typesDef);
typeStore.store(ts, ImmutableList.of(orgLevelEnum.name, addressDetails.typeName, superTypeDef.typeName,
deptTypeDef.typeName));
//Validate the updated types
TypesDef types = typeStore.restore();
ts.reset();
ts.defineTypes(types);
//Assert new enum value
EnumType orgLevel = ts.getDataType(EnumType.class, orgLevelEnum.name);
Assert.assertEquals(orgLevel.name, orgLevelEnum.name);
Assert.assertEquals(orgLevel.values().size(), orgLevelEnum.enumValues.length);
Assert.assertEquals(orgLevel.fromValue("L3").ordinal, 3);
//Assert new attribute
StructType addressType = ts.getDataType(StructType.class, addressDetails.typeName);
Assert.assertEquals(addressType.numFields, 3);
Assert.assertEquals(addressType.fieldMapping.fields.get("state").dataType(), DataTypes.STRING_TYPE);
//Assert new super type
ClassType deptType = ts.getDataType(ClassType.class, deptTypeDef.typeName);
Assert.assertTrue(deptType.superTypes.contains(superTypeDef.typeName));
Assert.assertNotNull(ts.getDataType(ClassType.class, superTypeDef.typeName));
}
} }
...@@ -40,7 +40,17 @@ abstract class AbstractDataType<T> implements IDataType<T> { ...@@ -40,7 +40,17 @@ abstract class AbstractDataType<T> implements IDataType<T> {
} else { } else {
TypeUtils.outputVal(val == null ? "<null>" : val.toString(), buf, prefix); TypeUtils.outputVal(val == null ? "<null>" : val.toString(), buf, prefix);
} }
}
/**
* Validate that current definition can be updated with the new definition
* @param newType
*/
@Override
public void validateUpdate(IDataType newType) throws TypeUpdateException {
if (!getName().equals(newType.getName()) || !getClass().getName().equals(newType.getClass().getName())) {
throw new TypeUpdateException(newType);
}
} }
} }
...@@ -71,6 +71,43 @@ public class AttributeInfo { ...@@ -71,6 +71,43 @@ public class AttributeInfo {
'}'; '}';
} }
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AttributeInfo that = (AttributeInfo) o;
if (isComposite != that.isComposite) {
return false;
}
if (isUnique != that.isUnique) {
return false;
}
if (isIndexable != that.isIndexable) {
return false;
}
if (!dataType.getName().equals(that.dataType.getName())) {
return false;
}
if (!multiplicity.equals(that.multiplicity)) {
return false;
}
if (!name.equals(that.name)) {
return false;
}
if (reverseAttributeName != null ? !reverseAttributeName.equals(that.reverseAttributeName) :
that.reverseAttributeName != null) {
return false;
}
return true;
}
public String toJson() throws JSONException { public String toJson() throws JSONException {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("name", name); json.put("name", name);
......
...@@ -76,6 +76,26 @@ public class EnumType extends AbstractDataType<EnumValue> { ...@@ -76,6 +76,26 @@ public class EnumType extends AbstractDataType<EnumValue> {
return DataTypes.TypeCategory.ENUM; return DataTypes.TypeCategory.ENUM;
} }
@Override
public void validateUpdate(IDataType newType) throws TypeUpdateException {
super.validateUpdate(newType);
EnumType enumType = (EnumType)newType;
for (EnumValue enumValue : values()) {
//The old enum value should be part of new enum definition as well
if (!enumType.valueMap.containsKey(enumValue.value)) {
throw new TypeUpdateException("Value " + enumValue.value + " is missing in new type");
}
//The ordinal for old enum value can't change
EnumValue newEnumValue = enumType.valueMap.get(enumValue.value);
if (enumValue.ordinal != newEnumValue.ordinal) {
throw new TypeUpdateException(String.format("Ordinal mismatch %s(%s) != %s(%s)", enumValue.value,
enumValue.ordinal, newEnumValue.value, newEnumValue.ordinal));
}
}
}
public EnumValue fromOrdinal(int o) { public EnumValue fromOrdinal(int o) {
return ordinalMap.get(o); return ordinalMap.get(o);
} }
......
...@@ -105,6 +105,30 @@ public abstract class HierarchicalType<ST extends HierarchicalType, T> extends A ...@@ -105,6 +105,30 @@ public abstract class HierarchicalType<ST extends HierarchicalType, T> extends A
return (cType == this || cType.superTypePaths.containsKey(getName())); return (cType == this || cType.superTypePaths.containsKey(getName()));
} }
/**
* Validate that current definition can be updated with the new definition
* @param newType
* @return true if the current definition can be updated with the new definition, else false
*/
@Override
public void validateUpdate(IDataType newType) throws TypeUpdateException {
super.validateUpdate(newType);
HierarchicalType newHierarchicalType = (HierarchicalType) newType;
//validate on supertypes
if (!newHierarchicalType.superTypes.containsAll(superTypes)) {
throw new TypeUpdateException(newType, "New type doesn't contain all super types of old type");
}
//validate on fields
try {
TypeUtils.validateUpdate(fieldMapping, newHierarchicalType.fieldMapping);
} catch (TypeUpdateException e) {
throw new TypeUpdateException(newType, e);
}
}
protected void setupSuperTypesGraph() throws AtlasException { protected void setupSuperTypesGraph() throws AtlasException {
setupSuperTypesGraph(superTypes); setupSuperTypesGraph(superTypes);
} }
...@@ -147,9 +171,9 @@ public abstract class HierarchicalType<ST extends HierarchicalType, T> extends A ...@@ -147,9 +171,9 @@ public abstract class HierarchicalType<ST extends HierarchicalType, T> extends A
protected Pair<FieldMapping, ImmutableMap<String, String>> constructFieldMapping(ImmutableList<String> superTypes, protected Pair<FieldMapping, ImmutableMap<String, String>> constructFieldMapping(ImmutableList<String> superTypes,
AttributeInfo... fields) throws AtlasException { AttributeInfo... fields) throws AtlasException {
Map<String, AttributeInfo> fieldsMap = new LinkedHashMap<String, AttributeInfo>(); Map<String, AttributeInfo> fieldsMap = new LinkedHashMap();
Map<String, Integer> fieldPos = new HashMap<String, Integer>(); Map<String, Integer> fieldPos = new HashMap();
Map<String, Integer> fieldNullPos = new HashMap<String, Integer>(); Map<String, Integer> fieldNullPos = new HashMap();
Map<String, String> attributeNameToType = new HashMap<>(); Map<String, String> attributeNameToType = new HashMap<>();
int numBools = 0; int numBools = 0;
......
...@@ -28,4 +28,7 @@ public interface IDataType<T> { ...@@ -28,4 +28,7 @@ public interface IDataType<T> {
DataTypes.TypeCategory getTypeCategory(); DataTypes.TypeCategory getTypeCategory();
void output(T val, Appendable buf, String prefix) throws AtlasException; void output(T val, Appendable buf, String prefix) throws AtlasException;
void validateUpdate(IDataType newType) throws TypeUpdateException;
} }
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
package org.apache.atlas.typesystem.types; package org.apache.atlas.typesystem.types;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.AtlasException; import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.IStruct; import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.ITypedStruct; import org.apache.atlas.typesystem.ITypedStruct;
...@@ -49,11 +48,11 @@ public class StructType extends AbstractDataType<IStruct> implements IConstructa ...@@ -49,11 +48,11 @@ public class StructType extends AbstractDataType<IStruct> implements IConstructa
this.handler = null; this.handler = null;
} }
protected StructType(TypeSystem typeSystem, String name, ImmutableList<String> superTypes, AttributeInfo... fields) protected StructType(TypeSystem typeSystem, String name, AttributeInfo... fields)
throws AtlasException { throws AtlasException {
this.typeSystem = typeSystem; this.typeSystem = typeSystem;
this.name = name; this.name = name;
this.fieldMapping = constructFieldMapping(superTypes, fields); this.fieldMapping = constructFieldMapping(fields);
infoToNameMap = TypeUtils.buildAttrInfoToNameMap(this.fieldMapping); infoToNameMap = TypeUtils.buildAttrInfoToNameMap(this.fieldMapping);
this.numFields = this.fieldMapping.fields.size(); this.numFields = this.fieldMapping.fields.size();
this.handler = new TypedStructHandler(this); this.handler = new TypedStructHandler(this);
...@@ -68,7 +67,24 @@ public class StructType extends AbstractDataType<IStruct> implements IConstructa ...@@ -68,7 +67,24 @@ public class StructType extends AbstractDataType<IStruct> implements IConstructa
return name; return name;
} }
protected FieldMapping constructFieldMapping(ImmutableList<String> superTypes, AttributeInfo... fields) /**
* Validate that current definition can be updated with the new definition
* @param newType
* @return true if the current definition can be updated with the new definition, else false
*/
@Override
public void validateUpdate(IDataType newType) throws TypeUpdateException {
super.validateUpdate(newType);
StructType newStructType = (StructType) newType;
try {
TypeUtils.validateUpdate(fieldMapping, newStructType.fieldMapping);
} catch (TypeUpdateException e) {
throw new TypeUpdateException(newType, e);
}
}
protected FieldMapping constructFieldMapping(AttributeInfo... fields)
throws AtlasException { throws AtlasException {
Map<String, AttributeInfo> fieldsMap = new LinkedHashMap<String, AttributeInfo>(); Map<String, AttributeInfo> fieldsMap = new LinkedHashMap<String, AttributeInfo>();
......
/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.typesystem.types;
import org.apache.atlas.AtlasException;
public class TypeUpdateException extends AtlasException {
public TypeUpdateException(IDataType newType) {
super(newType.getName() + " can't be updated");
}
public TypeUpdateException(IDataType newType, Exception e) {
super(newType.getName() + " can't be updated - " + e.getMessage(), e);
}
public TypeUpdateException(String message) {
super(message);
}
public TypeUpdateException(IDataType newType, String message) {
super(newType.getName() + " can't be updated - " + message);
}
}
...@@ -19,16 +19,15 @@ ...@@ -19,16 +19,15 @@
package org.apache.atlas.typesystem.types; package org.apache.atlas.typesystem.types;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.atlas.AtlasException; import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.TypesDef;
import scala.collection.JavaConversions;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -59,23 +58,16 @@ public class TypeUtils { ...@@ -59,23 +58,16 @@ public class TypeUtils {
} }
public static Map<AttributeInfo, List<String>> buildAttrInfoToNameMap(FieldMapping f) { public static Map<AttributeInfo, List<String>> buildAttrInfoToNameMap(FieldMapping f) {
Map<AttributeInfo, List<String>> b = new HashMap<AttributeInfo, List<String>>(); Map<AttributeInfo, List<String>> b = new HashMap();
for (Map.Entry<String, AttributeInfo> e : f.fields.entrySet()) { for (Map.Entry<String, AttributeInfo> e : f.fields.entrySet()) {
List<String> names = b.get(e.getValue()); List<String> names = b.get(e.getValue());
if (names == null) { if (names == null) {
names = new ArrayList<String>(); names = new ArrayList<>();
b.put(e.getValue(), names); b.put(e.getValue(), names);
} }
names.add(e.getKey()); names.add(e.getKey());
} }
return ImmutableMap.copyOf(b); return b;
}
public static TypesDef getTypesDef(ImmutableList<EnumTypeDefinition> enums,
ImmutableList<StructTypeDefinition> structs, ImmutableList<HierarchicalTypeDefinition<TraitType>> traits,
ImmutableList<HierarchicalTypeDefinition<ClassType>> classes) {
return new TypesDef(JavaConversions.asScalaBuffer(enums), JavaConversions.asScalaBuffer(structs),
JavaConversions.asScalaBuffer(traits), JavaConversions.asScalaBuffer(classes));
} }
protected static class Pair<L, R> { protected static class Pair<L, R> {
...@@ -87,4 +79,43 @@ public class TypeUtils { ...@@ -87,4 +79,43 @@ public class TypeUtils {
this.right = right; this.right = right;
} }
} }
/**
* Validates that the old field mapping can be replaced with new field mapping
* @param oldFieldMapping
* @param newFieldMapping
*/
public static void validateUpdate(FieldMapping oldFieldMapping, FieldMapping newFieldMapping)
throws TypeUpdateException {
Map<String, AttributeInfo> newFields = newFieldMapping.fields;
for (AttributeInfo attribute : oldFieldMapping.fields.values()) {
if (newFields.containsKey(attribute.name)) {
AttributeInfo newAttribute = newFields.get(attribute.name);
//If old attribute is also in new definition, only allowed change is multiplicity change from REQUIRED to OPTIONAL
if (!newAttribute.equals(attribute)) {
if (attribute.multiplicity == Multiplicity.REQUIRED
&& newAttribute.multiplicity == Multiplicity.OPTIONAL) {
continue;
} else {
throw new TypeUpdateException("Attribute " + attribute.name + " can't be updated");
}
}
} else {
//If old attribute is missing in new definition, return false as attributes can't be deleted
throw new TypeUpdateException("Old Attribute " + attribute.name + " is missing");
}
}
//Only new attributes
Set<String> newAttributes = new HashSet<>(ImmutableList.copyOf(newFields.keySet()));
newAttributes.removeAll(oldFieldMapping.fields.keySet());
for (String attributeName : newAttributes) {
AttributeInfo newAttribute = newFields.get(attributeName);
//New required attribute can't be added
if (newAttribute.multiplicity == Multiplicity.REQUIRED) {
throw new TypeUpdateException("Can't add required attribute " + attributeName);
}
}
}
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
package org.apache.atlas.typesystem.types.utils; package org.apache.atlas.typesystem.types.utils;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.AttributeDefinition; import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.ClassType; import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.EnumTypeDefinition; import org.apache.atlas.typesystem.types.EnumTypeDefinition;
...@@ -28,6 +29,7 @@ import org.apache.atlas.typesystem.types.IDataType; ...@@ -28,6 +29,7 @@ import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.Multiplicity; import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import scala.collection.JavaConversions;
/** /**
* Types utilities class. * Types utilities class.
...@@ -74,4 +76,11 @@ public class TypesUtil { ...@@ -74,4 +76,11 @@ public class TypesUtil {
ImmutableList<String> superTypes, AttributeDefinition... attrDefs) { ImmutableList<String> superTypes, AttributeDefinition... attrDefs) {
return new HierarchicalTypeDefinition<>(ClassType.class, name, superTypes, attrDefs); return new HierarchicalTypeDefinition<>(ClassType.class, name, superTypes, attrDefs);
} }
public static TypesDef getTypesDef(ImmutableList<EnumTypeDefinition> enums,
ImmutableList<StructTypeDefinition> structs, ImmutableList<HierarchicalTypeDefinition<TraitType>> traits,
ImmutableList<HierarchicalTypeDefinition<ClassType>> classes) {
return new TypesDef(JavaConversions.asScalaBuffer(enums), JavaConversions.asScalaBuffer(structs),
JavaConversions.asScalaBuffer(traits), JavaConversions.asScalaBuffer(classes));
}
} }
...@@ -25,6 +25,7 @@ import org.apache.atlas.AtlasException; ...@@ -25,6 +25,7 @@ import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.Struct; import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.commons.lang.RandomStringUtils;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import java.math.BigDecimal; import java.math.BigDecimal;
...@@ -96,8 +97,8 @@ public abstract class BaseTest { ...@@ -96,8 +97,8 @@ public abstract class BaseTest {
System.out.println("defined recursiveStructType = " + recursiveStructType); System.out.println("defined recursiveStructType = " + recursiveStructType);
} }
protected Map<String, IDataType> defineTraits(HierarchicalTypeDefinition... tDefs) throws AtlasException { protected Map<String, IDataType> defineTraits(HierarchicalTypeDefinition<TraitType>... tDefs)
throws AtlasException {
return getTypeSystem().defineTraitTypes(tDefs); return getTypeSystem().defineTraitTypes(tDefs);
} }
...@@ -168,4 +169,8 @@ public abstract class BaseTest { ...@@ -168,4 +169,8 @@ public abstract class BaseTest {
return hrDept; return hrDept;
} }
protected String newName() {
return RandomStringUtils.randomAlphanumeric(10);
}
} }
...@@ -18,14 +18,17 @@ ...@@ -18,14 +18,17 @@
package org.apache.atlas.typesystem.types; package org.apache.atlas.typesystem.types;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.AtlasException; import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.ITypedReferenceableInstance; import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ClassTest extends BaseTest { public class ClassTest extends HierarchicalTypeTest<ClassType> {
@BeforeMethod @BeforeMethod
public void setup() throws Exception { public void setup() throws Exception {
...@@ -67,6 +70,29 @@ public class ClassTest extends BaseTest { ...@@ -67,6 +70,29 @@ public class ClassTest extends BaseTest {
"\t\tlevel : \t\t1\n" + "\t\tlevel : \t\t1\n" +
"\t}}]\n" + "\t}}]\n" +
"}"); "}");
}
@Override
protected HierarchicalTypeDefinition<ClassType> getTypeDefinition(String name, AttributeDefinition... attributes) {
return new HierarchicalTypeDefinition(ClassType.class, name, null, attributes);
}
@Override
protected HierarchicalTypeDefinition<ClassType> getTypeDefinition(String name, ImmutableList<String> superTypes,
AttributeDefinition... attributes) {
return new HierarchicalTypeDefinition(ClassType.class, name, superTypes, attributes);
}
@Override
protected TypesDef getTypesDef(StructTypeDefinition typeDefinition) {
return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of((HierarchicalTypeDefinition<ClassType>) typeDefinition));
}
@Override
protected TypesDef getTypesDef(HierarchicalTypeDefinition<ClassType>... typeDefinitions) {
return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.copyOf(typeDefinitions));
} }
} }
...@@ -27,9 +27,11 @@ import org.apache.atlas.typesystem.ITypedReferenceableInstance; ...@@ -27,9 +27,11 @@ import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.ITypedStruct; import org.apache.atlas.typesystem.ITypedStruct;
import org.apache.atlas.typesystem.Referenceable; import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.Struct; import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
...@@ -59,7 +61,47 @@ public class EnumTest extends BaseTest { ...@@ -59,7 +61,47 @@ public class EnumTest extends BaseTest {
ts.defineEnumType("LockLevel", new EnumValue("DB", 1), new EnumValue("TABLE", 2), ts.defineEnumType("LockLevel", new EnumValue("DB", 1), new EnumValue("TABLE", 2),
new EnumValue("PARTITION", 3)); new EnumValue("PARTITION", 3));
}
@Test
public void testTypeUpdate() throws Exception {
TypeSystem ts = getTypeSystem();
EnumTypeDefinition etd = new EnumTypeDefinition(newName(), new EnumValue("A", 1));
TypesDef typesDef = getTypesDef(etd);
ts.defineTypes(typesDef);
//Allow adding new enum
etd = new EnumTypeDefinition(etd.name, new EnumValue("A", 1), new EnumValue("B", 2));
typesDef = getTypesDef(etd);
ts.updateTypes(typesDef);
//Don't allow deleting enum
etd = new EnumTypeDefinition(etd.name, new EnumValue("A", 1));
typesDef = getTypesDef(etd);
try {
ts.updateTypes(typesDef);
Assert.fail("Expected TypeUpdateException");
} catch (TypeUpdateException e) {
//assert that type is not updated when validation fails
EnumType enumType = ts.getDataType(EnumType.class, etd.name);
Assert.assertEquals(enumType.values().size(), 2);
}
//Don't allow changing ordinal of existing enum value
etd = new EnumTypeDefinition(etd.name, new EnumValue("A", 2));
typesDef = getTypesDef(etd);
try {
ts.updateTypes(typesDef);
Assert.fail("Expected TypeUpdateException");
} catch (TypeUpdateException e) {
//expected
}
}
private TypesDef getTypesDef(EnumTypeDefinition enumTypeDefinition) {
return TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.<HierarchicalTypeDefinition<ClassType>>of());
} }
protected void fillStruct(Struct s) throws AtlasException { protected void fillStruct(Struct s) throws AtlasException {
......
/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.typesystem.types;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert;
import org.testng.annotations.Test;
public abstract class HierarchicalTypeTest<T extends HierarchicalType> extends TypeUpdateBaseTest {
@Test(enabled = false)
public void testTypeUpdate() throws Exception {
testTypeUpdateForAttributes();
//Test super types
HierarchicalTypeDefinition classType =
getTypeDefinition(newName(), TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE));
TypeSystem ts = getTypeSystem();
ts.defineTypes(getTypesDef(classType));
//Add super type with optional attribute
HierarchicalTypeDefinition superType =
getTypeDefinition(newName(), TypesUtil.createOptionalAttrDef("s", DataTypes.INT_TYPE));
classType = getTypeDefinition(classType.typeName, ImmutableList.of(superType.typeName),
TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE));
ts.updateTypes(getTypesDef(superType, classType));
//Add super type with required attribute should fail
HierarchicalTypeDefinition superTypeRequired =
getTypeDefinition(newName(), TypesUtil.createRequiredAttrDef("s", DataTypes.INT_TYPE));
classType = getTypeDefinition(classType.typeName,
ImmutableList.of(superTypeRequired.typeName, superType.typeName),
TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE));
try {
ts.updateTypes(getTypesDef(superTypeRequired, classType));
Assert.fail("Expected TypeUpdateException");
} catch (TypeUpdateException e) {
//expected
}
//Deleting super type should fail
classType = getTypeDefinition(classType.typeName, TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE));
try {
ts.updateTypes(getTypesDef(superType, classType));
Assert.fail("Expected TypeUpdateException");
} catch (TypeUpdateException e) {
//expected
}
}
@Override
protected abstract HierarchicalTypeDefinition<T> getTypeDefinition(String name, AttributeDefinition... attributes);
protected abstract HierarchicalTypeDefinition<T> getTypeDefinition(String name, ImmutableList<String> superTypes,
AttributeDefinition... attributes);
@Override
protected abstract TypesDef getTypesDef(StructTypeDefinition typeDefinition);
protected abstract TypesDef getTypesDef(HierarchicalTypeDefinition<T>... typeDefinitions);
@Override
protected int getNumberOfFields(TypeSystem ts, String typeName) throws Exception {
return ts.getDataType(HierarchicalType.class, typeName).numFields;
}
}
\ No newline at end of file
...@@ -18,14 +18,17 @@ ...@@ -18,14 +18,17 @@
package org.apache.atlas.typesystem.types; package org.apache.atlas.typesystem.types;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.AtlasException; import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.ITypedStruct; import org.apache.atlas.typesystem.ITypedStruct;
import org.apache.atlas.typesystem.Struct; import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class StructTest extends BaseTest { public class StructTest extends TypeUpdateBaseTest {
StructType structType; StructType structType;
StructType recursiveStructType; StructType recursiveStructType;
...@@ -78,4 +81,25 @@ public class StructTest extends BaseTest { ...@@ -78,4 +81,25 @@ public class StructTest extends BaseTest {
"}"); "}");
} }
@Test
public void testTypeUpdate() throws Exception {
testTypeUpdateForAttributes();
}
@Override
protected int getNumberOfFields(TypeSystem ts, String typeName) throws Exception {
return ts.getDataType(StructType.class, typeName).numFields;
}
@Override
protected StructTypeDefinition getTypeDefinition(String name, AttributeDefinition... attributes) {
return new StructTypeDefinition(name, attributes);
}
@Override
protected TypesDef getTypesDef(StructTypeDefinition typeDefinition) {
return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.of(typeDefinition),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.<HierarchicalTypeDefinition<ClassType>>of());
}
} }
...@@ -23,9 +23,12 @@ import org.apache.atlas.AtlasException; ...@@ -23,9 +23,12 @@ import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.IStruct; import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.ITypedStruct; import org.apache.atlas.typesystem.ITypedStruct;
import org.apache.atlas.typesystem.Struct; import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert; import org.testng.Assert;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -33,7 +36,7 @@ import static org.apache.atlas.typesystem.types.utils.TypesUtil.createOptionalAt ...@@ -33,7 +36,7 @@ import static org.apache.atlas.typesystem.types.utils.TypesUtil.createOptionalAt
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createRequiredAttrDef; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createRequiredAttrDef;
import static org.apache.atlas.typesystem.types.utils.TypesUtil.createTraitTypeDef; import static org.apache.atlas.typesystem.types.utils.TypesUtil.createTraitTypeDef;
public class TraitTest extends BaseTest { public class TraitTest extends HierarchicalTypeTest<TraitType> {
@BeforeMethod @BeforeMethod
...@@ -213,8 +216,30 @@ public class TraitTest extends BaseTest { ...@@ -213,8 +216,30 @@ public class TraitTest extends BaseTest {
"\tA.C.D.c : \t3\n" + "\tA.C.D.c : \t3\n" +
"\tA.C.D.d : \t3\n" + "\tA.C.D.d : \t3\n" +
"}"); "}");
}
@Override
protected HierarchicalTypeDefinition<TraitType> getTypeDefinition(String name, AttributeDefinition... attributes) {
return new HierarchicalTypeDefinition(TraitType.class, name, null, attributes);
}
@Override
protected HierarchicalTypeDefinition<TraitType> getTypeDefinition(String name, ImmutableList<String> superTypes,
AttributeDefinition... attributes) {
return new HierarchicalTypeDefinition(TraitType.class, name, superTypes, attributes);
} }
@Override
protected TypesDef getTypesDef(StructTypeDefinition typeDefinition) {
return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.of((HierarchicalTypeDefinition<TraitType>) typeDefinition),
ImmutableList.<HierarchicalTypeDefinition<ClassType>>of());
}
@Override
protected TypesDef getTypesDef(HierarchicalTypeDefinition<TraitType>... typeDefinitions) {
return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.copyOf(typeDefinitions), ImmutableList.<HierarchicalTypeDefinition<ClassType>>of());
}
} }
/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.typesystem.types;
import org.apache.atlas.typesystem.TypesDef;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert;
public abstract class TypeUpdateBaseTest extends BaseTest {
protected void testTypeUpdateForAttributes() throws Exception {
StructTypeDefinition typeDefinition =
getTypeDefinition(newName(), TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE));
TypeSystem ts = getTypeSystem();
TypesDef typesDef = getTypesDef(typeDefinition);
ts.defineTypes(typesDef);
String typeName = typeDefinition.typeName;
//Allow modifying required to optional attribute
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE));
ts.updateTypes(getTypesDef(typeDefinition));
//Allow adding new optional attribute
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE),
TypesUtil.createOptionalAttrDef("b", DataTypes.INT_TYPE));
ts.updateTypes(getTypesDef(typeDefinition));
//Don't allow adding required attribute
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE),
TypesUtil.createOptionalAttrDef("b", DataTypes.INT_TYPE),
TypesUtil.createRequiredAttrDef("c", DataTypes.INT_TYPE));
try {
ts.updateTypes(getTypesDef(typeDefinition));
Assert.fail("Expected TypeUpdateException");
} catch (TypeUpdateException e) {
//assert that type is not updated when validation fails
Assert.assertEquals(getNumberOfFields(ts, typeDefinition.typeName), 2);
}
//Don't allow removing attribute
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE));
try {
ts.updateTypes(getTypesDef(typeDefinition));
} catch (TypeUpdateException e) {
//expected
}
//Don't allow modifying other fields of attribute definition - optional to required
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE),
TypesUtil.createRequiredAttrDef("b", DataTypes.INT_TYPE));
try {
ts.updateTypes(getTypesDef(typeDefinition));
} catch (TypeUpdateException e) {
//expected
}
//Don't allow modifying other fields of attribute definition - attribute type change
typeDefinition = getTypeDefinition(typeName, TypesUtil.createOptionalAttrDef("a", DataTypes.INT_TYPE),
TypesUtil.createOptionalAttrDef("b", DataTypes.STRING_TYPE));
try {
ts.updateTypes(getTypesDef(typeDefinition));
} catch (TypeUpdateException e) {
//expected
}
//Don't allow modifying other fields of attribute definition - attribute type change
typeDefinition = getTypeDefinition(typeName, TypesUtil.createRequiredAttrDef("a", DataTypes.INT_TYPE),
new AttributeDefinition("b", DataTypes.arrayTypeName(DataTypes.STRING_TYPE.getName()),
Multiplicity.COLLECTION, false, null));
try {
ts.updateTypes(getTypesDef(typeDefinition));
} catch (TypeUpdateException e) {
//expected
}
}
protected abstract int getNumberOfFields(TypeSystem ts, String typeName) throws Exception;
protected abstract TypesDef getTypesDef(StructTypeDefinition typeDefinition);
protected abstract StructTypeDefinition getTypeDefinition(String typeName,
AttributeDefinition... attributeDefinitions);
}
...@@ -35,7 +35,6 @@ import org.apache.atlas.typesystem.types.IDataType; ...@@ -35,7 +35,6 @@ import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.Multiplicity; import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONArray;
...@@ -153,7 +152,7 @@ public class QuickStart { ...@@ -153,7 +152,7 @@ public class QuickStart {
HierarchicalTypeDefinition<TraitType> jdbcTraitDef = TypesUtil.createTraitTypeDef("JdbcAccess", null); HierarchicalTypeDefinition<TraitType> jdbcTraitDef = TypesUtil.createTraitTypeDef("JdbcAccess", null);
return TypeUtils.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), return TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.of(dimTraitDef, factTraitDef, piiTraitDef, metricTraitDef, etlTraitDef, jdbcTraitDef), ImmutableList.of(dimTraitDef, factTraitDef, piiTraitDef, metricTraitDef, etlTraitDef, jdbcTraitDef),
ImmutableList.of(dbClsDef, storageDescClsDef, columnClsDef, tblClsDef, loadProcessClsDef, viewClsDef)); ImmutableList.of(dbClsDef, storageDescClsDef, columnClsDef, tblClsDef, loadProcessClsDef, viewClsDef));
} }
......
...@@ -38,6 +38,7 @@ import javax.ws.rs.Consumes; ...@@ -38,6 +38,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
...@@ -110,6 +111,50 @@ public class TypesResource { ...@@ -110,6 +111,50 @@ public class TypesResource {
} }
/** /**
* Update of existing types - if the given type doesn't exist, creates new type
* Allowed updates are:
* 1. Add optional attribute
* 2. Change required to optional attribute
* 3. Add super types - super types shouldn't contain any required attributes
* @param request
* @return
*/
@PUT
@Consumes(Servlets.JSON_MEDIA_TYPE)
@Produces(Servlets.JSON_MEDIA_TYPE)
public Response update(@Context HttpServletRequest request) {
try {
final String typeDefinition = Servlets.getRequestPayload(request);
LOG.debug("Updating type with definition {} ", typeDefinition);
JSONObject typesJson = metadataService.updateType(typeDefinition);
final JSONArray typesJsonArray = typesJson.getJSONArray(AtlasClient.TYPES);
JSONArray typesResponse = new JSONArray();
for (int i = 0; i < typesJsonArray.length(); i++) {
final String name = typesJsonArray.getString(i);
typesResponse.put(new JSONObject() {{
put(AtlasClient.NAME, name);
}});
}
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
response.put(AtlasClient.TYPES, typesResponse);
return Response.ok().entity(response).build();
} catch (TypeExistsException e) {
LOG.error("Type already exists", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.CONFLICT));
} catch (AtlasException | IllegalArgumentException e) {
LOG.error("Unable to persist types", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (Throwable e) {
LOG.error("Unable to persist types", e);
throw new WebApplicationException(Servlets.getErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
}
/**
* Fetch the complete definition of a given type name which is unique. * Fetch the complete definition of a given type name which is unique.
* *
* @param typeName name of a type which is unique. * @param typeName name of a type which is unique.
......
...@@ -41,7 +41,6 @@ import org.apache.atlas.typesystem.types.IDataType; ...@@ -41,7 +41,6 @@ import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.Multiplicity; import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.web.util.Servlets; import org.apache.atlas.web.util.Servlets;
import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.Configuration;
...@@ -188,7 +187,7 @@ public abstract class BaseResourceIT { ...@@ -188,7 +187,7 @@ public abstract class BaseResourceIT {
HierarchicalTypeDefinition<TraitType> etlTraitDef = TypesUtil.createTraitTypeDef("ETL", null); HierarchicalTypeDefinition<TraitType> etlTraitDef = TypesUtil.createTraitTypeDef("ETL", null);
TypesDef typesDef = TypeUtils.getTypesDef(ImmutableList.of(enumTypeDefinition), TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.of(enumTypeDefinition),
ImmutableList.of(structTypeDefinition), ImmutableList.of(structTypeDefinition),
ImmutableList.of(classificationTrait, piiTrait, phiTrait, pciTrait, soxTrait, secTrait, financeTrait, ImmutableList.of(classificationTrait, piiTrait, phiTrait, pciTrait, soxTrait, secTrait, financeTrait,
dimTraitDef, factTraitDef, metricTraitDef, etlTraitDef), dimTraitDef, factTraitDef, metricTraitDef, etlTraitDef),
......
...@@ -38,7 +38,6 @@ import org.apache.atlas.typesystem.types.EnumTypeDefinition; ...@@ -38,7 +38,6 @@ import org.apache.atlas.typesystem.types.EnumTypeDefinition;
import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition; import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.web.util.Servlets; import org.apache.atlas.web.util.Servlets;
import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.RandomStringUtils;
...@@ -112,6 +111,34 @@ public class EntityJerseyResourceIT extends BaseResourceIT { ...@@ -112,6 +111,34 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Assert.assertNotNull(response.get(AtlasClient.GUID)); Assert.assertNotNull(response.get(AtlasClient.GUID));
} }
@Test
public void testEntityDefinitionAcrossTypeUpdate() throws Exception {
//create type
HierarchicalTypeDefinition<ClassType> typeDefinition = TypesUtil
.createClassTypeDef(randomString(), ImmutableList.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("name", DataTypes.STRING_TYPE));
serviceClient.createType(TypesSerialization.toJson(typeDefinition, false));
//create entity for the type
Referenceable instance = new Referenceable(typeDefinition.typeName);
instance.set("name", randomString());
String guid = serviceClient.createEntity(instance).getString(0);
//update type - add attribute
typeDefinition = TypesUtil.createClassTypeDef(typeDefinition.typeName, ImmutableList.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("name", DataTypes.STRING_TYPE),
TypesUtil.createOptionalAttrDef("description", DataTypes.STRING_TYPE));
TypesDef typeDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(),
ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of(typeDefinition));
serviceClient.updateType(typeDef);
//Get definition after type update - new attributes should be null
Referenceable entity = serviceClient.getEntity(guid);
Assert.assertNull(entity.get("description"));
Assert.assertEquals(entity.get("name"), instance.get("name"));
}
@DataProvider @DataProvider
public Object[][] invalidAttrValues() { public Object[][] invalidAttrValues() {
return new Object[][]{{null}, {""}}; return new Object[][]{{null}, {""}};
...@@ -506,8 +533,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT { ...@@ -506,8 +533,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
HierarchicalTypeDefinition<ClassType> classTypeDefinition = TypesUtil HierarchicalTypeDefinition<ClassType> classTypeDefinition = TypesUtil
.createClassTypeDef(classType, ImmutableList.<String>of(), .createClassTypeDef(classType, ImmutableList.<String>of(),
TypesUtil.createUniqueRequiredAttrDef(attrName, DataTypes.STRING_TYPE)); TypesUtil.createUniqueRequiredAttrDef(attrName, DataTypes.STRING_TYPE));
TypesDef typesDef = TypeUtils TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of(classTypeDefinition)); ImmutableList.of(classTypeDefinition));
createType(typesDef); createType(typesDef);
......
...@@ -32,7 +32,6 @@ import org.apache.atlas.typesystem.types.EnumTypeDefinition; ...@@ -32,7 +32,6 @@ import org.apache.atlas.typesystem.types.EnumTypeDefinition;
import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition; import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition;
import org.apache.atlas.typesystem.types.StructTypeDefinition; import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.web.util.Servlets; import org.apache.atlas.web.util.Servlets;
import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONArray;
...@@ -176,8 +175,7 @@ public class MetadataDiscoveryJerseyResourceIT extends BaseResourceIT { ...@@ -176,8 +175,7 @@ public class MetadataDiscoveryJerseyResourceIT extends BaseResourceIT {
HierarchicalTypeDefinition<TraitType> financeTrait = HierarchicalTypeDefinition<TraitType> financeTrait =
TypesUtil.createTraitTypeDef("Finance", ImmutableList.<String>of()); TypesUtil.createTraitTypeDef("Finance", ImmutableList.<String>of());
TypesDef typesDef = TypeUtils TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(),
ImmutableList ImmutableList
.of(classificationTraitDefinition, piiTrait, phiTrait, pciTrait, soxTrait, secTrait, .of(classificationTraitDefinition, piiTrait, phiTrait, pciTrait, soxTrait, secTrait,
financeTrait), ImmutableList.of(dslTestTypeDefinition)); financeTrait), ImmutableList.of(dslTestTypeDefinition));
......
...@@ -28,8 +28,10 @@ import org.apache.atlas.typesystem.json.TypesSerialization$; ...@@ -28,8 +28,10 @@ import org.apache.atlas.typesystem.json.TypesSerialization$;
import org.apache.atlas.typesystem.types.AttributeDefinition; import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.ClassType; import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes; import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.EnumTypeDefinition;
import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition; import org.apache.atlas.typesystem.types.HierarchicalTypeDefinition;
import org.apache.atlas.typesystem.types.Multiplicity; import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType; import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.utils.TypesUtil; import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.web.util.Servlets; import org.apache.atlas.web.util.Servlets;
...@@ -87,6 +89,33 @@ public class TypesJerseyResourceIT extends BaseResourceIT { ...@@ -87,6 +89,33 @@ public class TypesJerseyResourceIT extends BaseResourceIT {
} }
} }
@Test
public void testUpdate() throws Exception {
HierarchicalTypeDefinition<ClassType> typeDefinition = TypesUtil
.createClassTypeDef(randomString(), ImmutableList.<String>of(),
TypesUtil.createUniqueRequiredAttrDef("name", DataTypes.STRING_TYPE));
List<String> typesCreated = serviceClient.createType(TypesSerialization.toJson(typeDefinition, false));
Assert.assertEquals(typesCreated.size(), 1);
Assert.assertEquals(typesCreated.get(0), typeDefinition.typeName);
//Add super type
HierarchicalTypeDefinition<ClassType> superTypeDefinition = TypesUtil
.createClassTypeDef(randomString(), ImmutableList.<String>of(),
TypesUtil.createOptionalAttrDef("sname", DataTypes.STRING_TYPE));
typeDefinition = TypesUtil.createClassTypeDef(typeDefinition.typeName,
ImmutableList.of(superTypeDefinition.typeName),
TypesUtil.createUniqueRequiredAttrDef("name", DataTypes.STRING_TYPE),
TypesUtil.createOptionalAttrDef("description", DataTypes.STRING_TYPE));
TypesDef typeDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(),
ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(),
ImmutableList.of(superTypeDefinition, typeDefinition));
List<String> typesUpdated = serviceClient.updateType(typeDef);
Assert.assertEquals(typesUpdated.size(), 2);
Assert.assertTrue(typesUpdated.contains(superTypeDefinition.typeName));
Assert.assertTrue(typesUpdated.contains(typeDefinition.typeName));
}
@Test(dependsOnMethods = "testSubmit") @Test(dependsOnMethods = "testSubmit")
public void testGetDefinition() throws Exception { public void testGetDefinition() throws Exception {
for (HierarchicalTypeDefinition typeDefinition : typeDefinitions) { for (HierarchicalTypeDefinition typeDefinition : typeDefinitions) {
......
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