ATLAS-4125: JavaPatch to add new supertypes to existing entities
Signed-off-by: Madhan Neethiraj <madhan@apache.org>
diff --git a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/BaseHiveEvent.java b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/BaseHiveEvent.java
index 2b809a6..3b2bbe0 100644
--- a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/BaseHiveEvent.java
+++ b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/BaseHiveEvent.java
@@ -83,6 +83,7 @@
public static final String ATTRIBUTE_OWNER = "owner";
public static final String ATTRIBUTE_CLUSTER_NAME = "clusterName";
public static final String ATTRIBUTE_LOCATION = "location";
+ public static final String ATTRIBUTE_LOCATION_PATH = "locationPath";
public static final String ATTRIBUTE_PARAMETERS = "parameters";
public static final String ATTRIBUTE_OWNER_TYPE = "ownerType";
public static final String ATTRIBUTE_COMMENT = "comment";
@@ -94,6 +95,7 @@
public static final String ATTRIBUTE_TEMPORARY = "temporary";
public static final String ATTRIBUTE_RETENTION = "retention";
public static final String ATTRIBUTE_DB = "db";
+ public static final String ATTRIBUTE_HIVE_DB = "hiveDb";
public static final String ATTRIBUTE_STORAGEDESC = "sd";
public static final String ATTRIBUTE_PARTITION_KEYS = "partitionKeys";
public static final String ATTRIBUTE_COLUMNS = "columns";
@@ -151,6 +153,7 @@
public static final String RELATIONSHIP_HIVE_TABLE_STORAGE_DESC = "hive_table_storagedesc";
public static final String RELATIONSHIP_HIVE_PROCESS_PROCESS_EXE = "hive_process_process_executions";
public static final String RELATIONSHIP_HIVE_DB_DDL_QUERIES = "hive_db_ddl_queries";
+ public static final String RELATIONSHIP_HIVE_DB_LOCATION = "hive_db_location";
public static final String RELATIONSHIP_HIVE_TABLE_DDL_QUERIES = "hive_table_ddl_queries";
public static final String RELATIONSHIP_HBASE_TABLE_NAMESPACE = "hbase_table_namespace";
@@ -689,6 +692,33 @@
return hiveDDL;
}
+ protected AtlasEntity createHiveLocationEntity(AtlasEntity dbEntity, AtlasEntitiesWithExtInfo extInfoEntity) {
+ AtlasEntity ret = null;
+ String locationUri = (String)dbEntity.getAttribute(ATTRIBUTE_LOCATION);
+
+ if (StringUtils.isNotEmpty(locationUri)) {
+ Path path = null;
+
+ try {
+ path = new Path(locationUri);
+ } catch (IllegalArgumentException excp) {
+ LOG.warn("failed to create Path from locationUri {}", locationUri, excp);
+ }
+
+ if (path != null) {
+ ret = getPathEntity(path, extInfoEntity);
+
+ if (ret != null) {
+ AtlasRelatedObjectId dbRelatedObjectId = AtlasTypeUtil.getAtlasRelatedObjectId(dbEntity, RELATIONSHIP_HIVE_DB_LOCATION);
+
+ ret.setRelationshipAttribute(ATTRIBUTE_HIVE_DB, dbRelatedObjectId);
+ }
+ }
+ }
+
+ return ret;
+ }
+
protected String getMetadataNamespace() {
return context.getMetadataNamespace();
}
diff --git a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/CreateDatabase.java b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/CreateDatabase.java
index c8a9ce3..8305a44 100644
--- a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/CreateDatabase.java
+++ b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/hook/events/CreateDatabase.java
@@ -97,6 +97,11 @@
if (dbDDLEntity != null) {
ret.addEntity(dbDDLEntity);
}
+
+ AtlasEntity dbLocationEntity = createHiveLocationEntity(dbEntity, ret);
+ if (dbLocationEntity != null) {
+ ret.addEntity(dbLocationEntity);
+ }
} else {
LOG.error("CreateDatabase.getEntities(): failed to retrieve db");
}
diff --git a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
index 5c7777b..fccfc48 100755
--- a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
+++ b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
@@ -32,6 +32,7 @@
import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo;
import org.apache.atlas.model.lineage.AtlasLineageInfo;
import org.apache.atlas.model.typedef.AtlasClassificationDef;
+import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.commons.collections.CollectionUtils;
@@ -61,6 +62,7 @@
import static org.apache.atlas.AtlasClient.NAME;
import static org.apache.atlas.hive.hook.events.BaseHiveEvent.*;
import static org.testng.Assert.*;
+import static org.testng.AssertJUnit.assertEquals;
public class HiveHookIT extends HiveITBase {
private static final Logger LOG = LoggerFactory.getLogger(HiveHookIT.class);
@@ -118,6 +120,59 @@
}
@Test
+ public void testPathEntityDefAvailable() throws Exception {
+ //Check if Path entity definition created or not
+ AtlasEntityDef pathEntityDef = atlasClientV2.getEntityDefByName("Path");
+ assertNotNull(pathEntityDef);
+ }
+
+ @Test
+ public void testCreateDatabaseWithLocation() throws Exception {
+ String dbName = dbName();
+ String query = "CREATE DATABASE " + dbName;
+
+ runCommand(query);
+ String dbId = assertDatabaseIsRegistered(dbName);
+
+ //HDFS Location
+ String hdfsLocation = "hdfs://localhost:8020/warehouse/tablespace/external/hive/reports.db";
+ alterDatabaseLocation(dbName, hdfsLocation);
+ assertDatabaseLocationRelationship(dbId);
+
+ //AWS location
+ String s3Location = "s3://localhost:8020/warehouse/tablespace/external/hive/reports.db";
+ alterDatabaseLocation(dbName, s3Location);
+ assertDatabaseLocationRelationship(dbId);
+
+ //ABFS location
+ String abfsLocation = "abfs://localhost:8020/warehouse/tablespace/external/hive/reports.db";
+ alterDatabaseLocation(dbName, abfsLocation);
+ assertDatabaseLocationRelationship(dbId);
+ }
+
+ //alter database location
+ public void alterDatabaseLocation(String dbName, String location) throws Exception {
+ int timeDelay = 5000;
+ String query = String.format("ALTER DATABASE %s SET LOCATION \"%s\"", dbName, location);
+ runCommandWithDelay(query, timeDelay);
+ }
+
+ public void assertDatabaseLocationRelationship(String dbId) throws Exception {
+ AtlasEntity dbEntity = atlasClientV2.getEntityByGuid(dbId).getEntity();
+ AtlasEntityDef pathEntityDef = atlasClientV2.getEntityDefByName("Path");
+
+ //Check if dbEntity has location attribute
+ assertTrue(dbEntity.hasAttribute(ATTRIBUTE_LOCATION));
+ //Check if dbEntity has value for location attribute
+ assertNotNull(dbEntity.getAttribute(ATTRIBUTE_LOCATION));
+ //Check if dbEntity has location relationship attribute
+ assertEquals(((List) dbEntity.getRelationshipAttribute(ATTRIBUTE_LOCATION_PATH)).size(), 1);
+ AtlasObjectId locationEntityObject = toAtlasObjectId(dbEntity.getRelationshipAttribute(ATTRIBUTE_LOCATION_PATH));
+ //Check if location relationship attribute is subtype of "Path"
+ assertTrue(pathEntityDef.getSubTypes().contains(locationEntityObject.getTypeName()));
+ }
+
+ @Test
public void testCreateTable() throws Exception {
String tableName = tableName();
String dbName = createDatabase();
diff --git a/addons/models/0000-Area0/0010-base_model.json b/addons/models/0000-Area0/0010-base_model.json
index 78ba927..769d885 100644
--- a/addons/models/0000-Area0/0010-base_model.json
+++ b/addons/models/0000-Area0/0010-base_model.json
@@ -217,6 +217,14 @@
]
},
{
+ "name": "Path",
+ "superTypes": [
+ "DataSet"
+ ],
+ "serviceType": "atlas_core",
+ "typeVersion": "1.0"
+ },
+ {
"name": "AtlasServer",
"serviceType": "atlas_core",
"typeVersion": "1.0",
diff --git a/addons/models/1000-Hadoop/1020-fs_model.json b/addons/models/1000-Hadoop/1020-fs_model.json
index fc0e80d..6d7b95a 100644
--- a/addons/models/1000-Hadoop/1020-fs_model.json
+++ b/addons/models/1000-Hadoop/1020-fs_model.json
@@ -86,10 +86,11 @@
{
"name": "fs_path",
"superTypes": [
- "DataSet"
+ "DataSet",
+ "Path"
],
"serviceType": "file_system",
- "typeVersion": "1.0",
+ "typeVersion": "1.1",
"attributeDefs": [
{
"name": "path",
diff --git a/addons/models/1000-Hadoop/1030-hive_model.json b/addons/models/1000-Hadoop/1030-hive_model.json
index b44f724..79beee8 100644
--- a/addons/models/1000-Hadoop/1030-hive_model.json
+++ b/addons/models/1000-Hadoop/1030-hive_model.json
@@ -718,6 +718,23 @@
"cardinality": "SINGLE"
},
"propagateTags": "NONE"
+ },
+ {
+ "name": "hive_db_location",
+ "serviceType": "hive",
+ "typeVersion": "1.0",
+ "relationshipCategory": "ASSOCIATION",
+ "endDef1": {
+ "type": "hive_db",
+ "name": "locationPath",
+ "cardinality": "SINGLE"
+ },
+ "endDef2": {
+ "type": "Path",
+ "name": "hiveDb",
+ "cardinality": "SINGLE"
+ },
+ "propagateTags": "NONE"
}
]
}
diff --git a/addons/models/1000-Hadoop/patches/018-fs_path_add_supertypes.json b/addons/models/1000-Hadoop/patches/018-fs_path_add_supertypes.json
new file mode 100644
index 0000000..8923504
--- /dev/null
+++ b/addons/models/1000-Hadoop/patches/018-fs_path_add_supertypes.json
@@ -0,0 +1,16 @@
+{
+ "patches": [
+ {
+ "id": "TYPEDEF_PATCH_1000_018_001",
+ "description": "Add superTypes for fs_path",
+ "action": "ADD_SUPER_TYPES",
+ "typeName": "fs_path",
+ "applyToVersion": "1.0",
+ "updateToVersion": "1.1",
+ "params": null,
+ "superTypes": [
+ "Path"
+ ]
+ }
+ ]
+}
diff --git a/addons/models/3000-Cloud/3020-aws_s3_typedefs.json b/addons/models/3000-Cloud/3020-aws_s3_typedefs.json
index d41df92..5275c56 100644
--- a/addons/models/3000-Cloud/3020-aws_s3_typedefs.json
+++ b/addons/models/3000-Cloud/3020-aws_s3_typedefs.json
@@ -96,9 +96,9 @@
{
"name": "aws_s3_pseudo_dir",
"description": "Atlas Type representing a Pseudo-Directory (prefix) in an S3 Object Store Bucket",
- "superTypes": [ "DataSet" ],
+ "superTypes": [ "DataSet","Path" ],
"serviceType": "aws",
- "typeVersion": "1.0",
+ "typeVersion": "1.1",
"attributeDefs": [
{
"name": "objectPrefix",
diff --git a/addons/models/3000-Cloud/3030-aws_s3_v2_typedefs.json b/addons/models/3000-Cloud/3030-aws_s3_v2_typedefs.json
index 7236bc9..e656c31 100644
--- a/addons/models/3000-Cloud/3030-aws_s3_v2_typedefs.json
+++ b/addons/models/3000-Cloud/3030-aws_s3_v2_typedefs.json
@@ -146,10 +146,11 @@
"description": "Atlas Type representing a directory in an S3 Object Store",
"superTypes": [
"aws_s3_v2_object",
- "aws_s3_v2_container"
+ "aws_s3_v2_container",
+ "Path"
],
"serviceType": "aws",
- "typeVersion": "1.0",
+ "typeVersion": "1.1",
"attributeDefs": [
{
"name": "objectPrefix",
diff --git a/addons/models/3000-Cloud/3040-azure_adls_typedefs.json b/addons/models/3000-Cloud/3040-azure_adls_typedefs.json
index b297234..77c7494 100644
--- a/addons/models/3000-Cloud/3040-azure_adls_typedefs.json
+++ b/addons/models/3000-Cloud/3040-azure_adls_typedefs.json
@@ -317,10 +317,11 @@
"superTypes": [
"DataSet",
"adls_gen2_parent",
- "adls_gen2_child"
+ "adls_gen2_child",
+ "Path"
],
"serviceType": "azure",
- "typeVersion": "1.2",
+ "typeVersion": "1.3",
"attributeDefs": [
{
"name": "eTag",
diff --git a/addons/models/3000-Cloud/patches/006-cloud-model_add_supertypes.json b/addons/models/3000-Cloud/patches/006-cloud-model_add_supertypes.json
new file mode 100644
index 0000000..6e2ea57
--- /dev/null
+++ b/addons/models/3000-Cloud/patches/006-cloud-model_add_supertypes.json
@@ -0,0 +1,40 @@
+{
+ "patches": [
+ {
+ "id": "TYPEDEF_PATCH_3000_006_001",
+ "description": "Add superTypes for aws_s3_pseudo_dir",
+ "action": "ADD_SUPER_TYPES",
+ "typeName": "aws_s3_pseudo_dir",
+ "applyToVersion": "1.0",
+ "updateToVersion": "1.1",
+ "params": null,
+ "superTypes": [
+ "Path"
+ ]
+ },
+ {
+ "id": "TYPEDEF_PATCH_3000_006_002",
+ "description": "Add superTypes for aws_s3_v2_directory",
+ "action": "ADD_SUPER_TYPES",
+ "typeName": "aws_s3_v2_directory",
+ "applyToVersion": "1.0",
+ "updateToVersion": "1.1",
+ "params": null,
+ "superTypes": [
+ "Path"
+ ]
+ },
+ {
+ "id": "TYPEDEF_PATCH_3000_006_003",
+ "description": "Add superTypes for adls_gen2_directory",
+ "action": "ADD_SUPER_TYPES",
+ "typeName": "adls_gen2_directory",
+ "applyToVersion": "1.2",
+ "updateToVersion": "1.3",
+ "params": null,
+ "superTypes": [
+ "Path"
+ ]
+ }
+ ]
+}
diff --git a/repository/src/main/java/org/apache/atlas/repository/patches/AtlasPatchManager.java b/repository/src/main/java/org/apache/atlas/repository/patches/AtlasPatchManager.java
index 478376b..fae28c4 100644
--- a/repository/src/main/java/org/apache/atlas/repository/patches/AtlasPatchManager.java
+++ b/repository/src/main/java/org/apache/atlas/repository/patches/AtlasPatchManager.java
@@ -18,7 +18,7 @@
package org.apache.atlas.repository.patches;
-import org.apache.atlas.model.patches.AtlasPatch;
+import org.apache.atlas.model.patches.AtlasPatch.AtlasPatches;
import org.apache.atlas.model.patches.AtlasPatch.PatchStatus;
import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
import org.apache.atlas.repository.graphdb.AtlasGraph;
@@ -28,7 +28,10 @@
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
+import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
import static org.apache.atlas.model.patches.AtlasPatch.PatchStatus.APPLIED;
import static org.apache.atlas.model.patches.AtlasPatch.PatchStatus.SKIPPED;
@@ -37,26 +40,35 @@
public class AtlasPatchManager {
private static final Logger LOG = LoggerFactory.getLogger(AtlasPatchManager.class);
- private final PatchContext context;
+ private final PatchContext context;
+ private final List<AtlasPatchHandler> handlers = new ArrayList<>();
@Inject
public AtlasPatchManager(AtlasGraph atlasGraph, AtlasTypeRegistry typeRegistry, GraphBackedSearchIndexer indexer, EntityGraphMapper entityGraphMapper) {
this.context = new PatchContext(atlasGraph, typeRegistry, indexer, entityGraphMapper);
}
- public AtlasPatch.AtlasPatches getAllPatches() {
+ @PostConstruct
+ public void init() {
+ LOG.info("==> AtlasPatchManager.init()");
+
+ // register all java patches here
+ handlers.add(new UniqueAttributePatch(context));
+ handlers.add(new ClassificationTextPatch(context));
+ handlers.add(new FreeTextRequestHandlerPatch(context));
+ handlers.add(new SuggestionsRequestHandlerPatch(context));
+ handlers.add(new IndexConsistencyPatch(context));
+ handlers.add(new ReIndexPatch(context));
+
+ LOG.info("<== AtlasPatchManager.init()");
+ }
+
+ public AtlasPatches getAllPatches() {
return context.getPatchRegistry().getAllPatches();
}
public void applyAll() {
- final AtlasPatchHandler handlers[] = {
- new UniqueAttributePatch(context),
- new ClassificationTextPatch(context),
- new FreeTextRequestHandlerPatch(context),
- new SuggestionsRequestHandlerPatch(context),
- new IndexConsistencyPatch(context),
- new ReIndexPatch(context)
- };
+ LOG.info("==> AtlasPatchManager.applyAll()");
try {
for (AtlasPatchHandler handler : handlers) {
@@ -70,9 +82,18 @@
handler.apply();
}
}
- }
- catch (Exception ex) {
+ } catch (Exception ex) {
LOG.error("Error applying patches.", ex);
}
+
+ LOG.info("<== AtlasPatchManager.applyAll()");
+ }
+
+ public void addPatchHandler(AtlasPatchHandler patchHandler) {
+ handlers.add(patchHandler);
+ }
+
+ public PatchContext getContext() {
+ return this.context;
}
}
diff --git a/repository/src/main/java/org/apache/atlas/repository/patches/SuperTypesUpdatePatch.java b/repository/src/main/java/org/apache/atlas/repository/patches/SuperTypesUpdatePatch.java
new file mode 100644
index 0000000..a77ca70
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/patches/SuperTypesUpdatePatch.java
@@ -0,0 +1,129 @@
+/**
+ * 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.repository.patches;
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.pc.WorkItemManager;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.commons.collections.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+import static org.apache.atlas.model.patches.AtlasPatch.PatchStatus.APPLIED;
+import static org.apache.atlas.repository.Constants.ENTITY_TYPE_PROPERTY_KEY;
+import static org.apache.atlas.repository.Constants.SUPER_TYPES_PROPERTY_KEY;
+
+public class SuperTypesUpdatePatch extends AtlasPatchHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(SuperTypesUpdatePatch.class);
+ private static final String PATCH_ID = "JAVA_PATCH_0000_007";
+ private static final String PATCH_DESCRIPTION = "Update supertypes for all existing entities for given typeName";
+
+ private final PatchContext context;
+ private final String typeName;
+
+ public SuperTypesUpdatePatch(PatchContext context, String typeDefPatchId, String typeName) {
+ super(context.getPatchRegistry(), PATCH_ID + "_" + typeDefPatchId, PATCH_DESCRIPTION);
+
+ this.context = context;
+ this.typeName = typeName;
+ }
+
+ @Override
+ public void apply() throws AtlasBaseException {
+ LOG.info("==> SuperTypesUpdatePatch.apply(): patchId={}", getPatchId());
+
+ ConcurrentPatchProcessor patchProcessor = new SuperTypesUpdatePatchProcessor(context, typeName);
+
+ patchProcessor.apply();
+
+ setStatus(APPLIED);
+
+ LOG.info("<== SuperTypesUpdatePatch.apply(): patchId={}, status={}", getPatchId(), getStatus());
+ }
+
+ public static class SuperTypesUpdatePatchProcessor extends ConcurrentPatchProcessor {
+ private final String typeName;
+ private final Set<String> typeAndAllSubTypes;
+
+ public SuperTypesUpdatePatchProcessor(PatchContext context, String typeName) {
+ super(context);
+
+ AtlasEntityType entityType = getTypeRegistry().getEntityTypeByName(typeName);
+
+ this.typeName = typeName;
+ this.typeAndAllSubTypes = entityType != null ? entityType.getTypeAndAllSubTypes() : Collections.emptySet();
+ }
+
+ @Override
+ public void submitVerticesToUpdate(WorkItemManager manager) {
+ if (CollectionUtils.isNotEmpty(typeAndAllSubTypes)) {
+ LOG.info("Entity types to be updated with supertypes :{}", typeAndAllSubTypes.size());
+
+ for (String typeName : typeAndAllSubTypes) {
+ LOG.info("finding entities of type {}", typeName);
+
+ AtlasGraph graph = getGraph();
+ Iterable<Object> vertexIds = graph.query().has(ENTITY_TYPE_PROPERTY_KEY, typeName).vertexIds();
+ int count = 0;
+
+ for (Iterator<Object> iterator = vertexIds.iterator(); iterator.hasNext(); ) {
+ Object vertexId = iterator.next();
+
+ manager.checkProduce(vertexId);
+
+ count++;
+ }
+
+ LOG.info("found {} entities of type {}", count, typeName);
+ }
+ }
+ }
+
+ @Override
+ protected void processVertexItem(Long vertexId, AtlasVertex vertex, String typeName, AtlasEntityType entityType) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("processVertexItem(typeName={}, vertexId={})", typeName, vertexId);
+ }
+
+ Set<String> allSuperTypes = entityType.getAllSuperTypes();
+
+ if (allSuperTypes != null) {
+ // remove and update all entity super types
+ vertex.removeProperty(SUPER_TYPES_PROPERTY_KEY);
+
+ for (String superType : allSuperTypes) {
+ AtlasGraphUtilsV2.addEncodedProperty(vertex, SUPER_TYPES_PROPERTY_KEY, superType);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Updated superTypes for entity of typeName={}, vertexId={}): Done!", typeName, vertex.getId());
+ }
+ }
+ }
+
+ @Override
+ protected void prepareForExecution() {
+ //do nothing
+ }
+ }
+}
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AtlasTypeDefStoreInitializer.java b/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AtlasTypeDefStoreInitializer.java
index c29888f..676a0aa 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AtlasTypeDefStoreInitializer.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AtlasTypeDefStoreInitializer.java
@@ -43,6 +43,8 @@
import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.patches.SuperTypesUpdatePatch;
+import org.apache.atlas.repository.patches.AtlasPatchManager;
import org.apache.atlas.repository.patches.AtlasPatchRegistry;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.apache.atlas.type.AtlasEntityType;
@@ -94,14 +96,16 @@
private final AtlasTypeRegistry typeRegistry;
private final Configuration conf;
private final AtlasGraph graph;
+ private final AtlasPatchManager patchManager;
@Inject
public AtlasTypeDefStoreInitializer(AtlasTypeDefStore typeDefStore, AtlasTypeRegistry typeRegistry,
- AtlasGraph graph, Configuration conf) {
+ AtlasGraph graph, Configuration conf, AtlasPatchManager patchManager) {
this.typeDefStore = typeDefStore;
this.typeRegistry = typeRegistry;
this.conf = conf;
this.graph = graph;
+ this.patchManager = patchManager;
}
@PostConstruct
@@ -449,7 +453,8 @@
new RemoveLegacyRefAttributesPatchHandler(typeDefStore, typeRegistry),
new UpdateTypeDefOptionsPatchHandler(typeDefStore, typeRegistry),
new SetServiceTypePatchHandler(typeDefStore, typeRegistry),
- new UpdateAttributeMetadataHandler(typeDefStore, typeRegistry)
+ new UpdateAttributeMetadataHandler(typeDefStore, typeRegistry),
+ new AddSuperTypePatchHandler(typeDefStore, typeRegistry)
};
Map<String, PatchHandler> patchHandlerRegistry = new HashMap<>();
@@ -532,6 +537,7 @@
private Map<String, String> typeDefOptions;
private String serviceType;
private String attributeName;
+ private Set<String> superTypes;
public String getId() {
return id;
@@ -624,6 +630,14 @@
public String getAttributeName() { return attributeName; }
public void setAttributeName(String attributeName) { this.attributeName = attributeName; }
+
+ public Set<String> getSuperTypes() {
+ return superTypes;
+ }
+
+ public void setSuperTypes(Set<String> superTypes) {
+ this.superTypes = superTypes;
+ }
}
/**
@@ -1136,4 +1150,58 @@
}
}
}
+
+ class AddSuperTypePatchHandler extends PatchHandler {
+
+ public AddSuperTypePatchHandler(AtlasTypeDefStore typeDefStore, AtlasTypeRegistry typeRegistry) {
+ super(typeDefStore, typeRegistry, new String[] {"ADD_SUPER_TYPES"});
+ }
+
+ @Override
+ public PatchStatus applyPatch(TypeDefPatch patch) throws AtlasBaseException {
+ String typeName = patch.getTypeName();
+ AtlasBaseTypeDef typeDef = typeRegistry.getTypeDefByName(typeName);
+ PatchStatus ret;
+
+ if (typeDef == null) {
+ throw new AtlasBaseException(AtlasErrorCode.PATCH_FOR_UNKNOWN_TYPE, patch.getAction(), typeName);
+ }
+
+ Set<String> superTypesToBeAdded = patch.getSuperTypes();
+
+ if (CollectionUtils.isNotEmpty(superTypesToBeAdded) && isPatchApplicable(patch, typeDef)) {
+ if (typeDef.getClass().equals(AtlasEntityDef.class)) {
+ AtlasEntityDef updatedDef = new AtlasEntityDef((AtlasEntityDef)typeDef);
+
+ for (String superType : superTypesToBeAdded) {
+ updatedDef.addSuperType(superType);
+ }
+
+ updatedDef.setTypeVersion(patch.getUpdateToVersion());
+
+ typeDefStore.updateEntityDefByName(typeName, updatedDef);
+
+ LOG.info("Update entities of {} with new supertypes", typeName);
+
+ // add to java patch handlers to update entity supertypes
+ patchManager.addPatchHandler(new SuperTypesUpdatePatch(patchManager.getContext(), patch.getId(), typeName));
+
+ ret = APPLIED;
+ } else {
+ throw new AtlasBaseException(AtlasErrorCode.PATCH_NOT_APPLICABLE_FOR_TYPE, patch.getAction(), typeDef.getClass().getSimpleName());
+ }
+ } else {
+ if (CollectionUtils.isEmpty(superTypesToBeAdded)) {
+ LOG.info("patch skipped: No superTypes provided to add for typeName={}", patch.getTypeName());
+ } else {
+ LOG.info("patch skipped: typeName={}; applyToVersion={}; updateToVersion={}",
+ patch.getTypeName(), patch.getApplyToVersion(), patch.getUpdateToVersion());
+ }
+
+ ret = SKIPPED;
+ }
+
+ return ret;
+ }
+ }
}
diff --git a/test-tools/src/main/resources/solr/core-template/solrconfig.xml b/test-tools/src/main/resources/solr/core-template/solrconfig.xml
index 94f346f..4d7e444 100644
--- a/test-tools/src/main/resources/solr/core-template/solrconfig.xml
+++ b/test-tools/src/main/resources/solr/core-template/solrconfig.xml
@@ -432,9 +432,30 @@
<!-- default values for query parameters can be specified, these
will be overridden by parameters in the request
-->
+ <!--
+ 35x_t __guid
+ f0l_t __typeName
+ i6d_l __timestamp
+ jr9_t __state
+ lc5_t __classificationsText
+ mx1_t __classificationNames
+ iyt_l __modificationTimestamp
+ zk5_t __customAttributes
+ 1151_t __labels
+ ohx_t __propagatedClassificationNames
+ 3thh_s Asset.__s_name
+ 3z0l_s Asset.__s_owner
+ 3wn9_t Asset.description
+ 3v2d_s Asset.__s_displayName
+ 3xfp_s Asset.__s_userDescription
+ 3mdh_t Referenceable.qualifiedName
+ c45h_t hive_serde.name
+ cb9h_t hive_process.queryText
+ c83p_t hive_process.userName
+ -->
<lst name="defaults">
<str name="defType">edismax</str>
- <str name="qf">3ll1_t 35x_t f0l_t i6d_l 7f2d_t 7gn9_t 3sp1_s jr9_t 3vut_t lc5_t mx1_t 7dhh_t iyt_l 3j7p_t 7klh_t 7hfp_t 7i85_t ohx_t 7bwl_l 7cp1_l</str>
+ <str name="qf">35x_t f0l_t i6d_l jr9_t lc5_t mx1_t iyt_l zk5_t 1151_t ohx_t 3thh_s 3z0l_s 3wn9_t 3v2d_s 3xfp_s 3mdh_t c45h_t cb9h_t c83p_t</str>
<str name="hl.fl">*</str>
<bool name="hl.requireFieldMatch">true</bool>
<bool name="lowercaseOperators">true</bool>