You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/01/21 05:22:12 UTC
incubator-atlas git commit: ATLAS-1478: REST API to add
classification to multiple entities
Repository: incubator-atlas
Updated Branches:
refs/heads/master bda289ef7 -> 7f914ab9e
ATLAS-1478: REST API to add classification to multiple entities
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/7f914ab9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/7f914ab9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/7f914ab9
Branch: refs/heads/master
Commit: 7f914ab9eb3c4cb0ceccea090bed47db220c3780
Parents: bda289e
Author: Vimal Sharma <sv...@apache.org>
Authored: Fri Jan 20 10:37:06 2017 -0800
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Fri Jan 20 17:13:39 2017 -0800
----------------------------------------------------------------------
.../java/org/apache/atlas/AtlasErrorCode.java | 2 +
.../ClassificationAssociateRequest.java | 100 +++++++++++++++++++
release-log.txt | 1 +
.../atlas/repository/MetadataRepository.java | 8 ++
.../graph/GraphBackedMetadataRepository.java | 28 +++++-
.../atlas/services/DefaultMetadataService.java | 34 ++++++-
.../apache/atlas/services/MetadataService.java | 10 ++
.../org/apache/atlas/web/rest/EntitiesREST.java | 36 +++++++
.../atlas/web/adapters/TestEntitiesREST.java | 19 ++++
9 files changed, 236 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index f0aae0c..e4f3dfd 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -53,6 +53,8 @@ public enum AtlasErrorCode {
PATCH_FOR_UNKNOWN_TYPE(400, "ATLAS40023E", "{0} - patch references unknown type {1}"),
PATCH_INVALID_DATA(400, "ATLAS40024E", "{0} - patch data is invalid for type {1}"),
TYPE_NAME_INVALID_FORMAT(400, "ATLAS40025E", "{0}: invalid name for {1}. Names must consist of a letter followed by a sequence of letter, number, or '_' characters"),
+ INVALID_PARAMETERS(400, "ATLAS40025E", "invalid parameters: {0}"),
+ CLASSIFICATION_ALREADY_ASSOCIATED(400, "ATLAS40026E", "instance {0} already is associated with classification {1}"),
// All Not found enums go here
TYPE_NAME_NOT_FOUND(404, "ATLAS4041E", "Given typename {0} was invalid"),
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/intg/src/main/java/org/apache/atlas/model/instance/ClassificationAssociateRequest.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/instance/ClassificationAssociateRequest.java b/intg/src/main/java/org/apache/atlas/model/instance/ClassificationAssociateRequest.java
new file mode 100644
index 0000000..8d0fac6
--- /dev/null
+++ b/intg/src/main/java/org/apache/atlas/model/instance/ClassificationAssociateRequest.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.model.instance;
+
+import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE;
+import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.PUBLIC_ONLY;
+
+import java.util.List;
+import java.util.Objects;
+
+@JsonAutoDetect(getterVisibility=PUBLIC_ONLY, setterVisibility=PUBLIC_ONLY, fieldVisibility=NONE)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.PROPERTY)
+public class ClassificationAssociateRequest {
+ private AtlasClassification classification;
+ private List<String> entityGuids;
+
+ public ClassificationAssociateRequest() {
+ this(null, null);
+ }
+
+ public ClassificationAssociateRequest(List<String> entityGuids, AtlasClassification classification) {
+ setEntityGuids(entityGuids);
+ setClassification(classification);
+ }
+
+ public AtlasClassification getClassification() { return classification; }
+
+ public void setClassification(AtlasClassification classification) { this.classification = classification; }
+
+ public List<String> getEntityGuids() { return entityGuids; }
+
+ public void setEntityGuids(List<String> entityGuids) { this.entityGuids = entityGuids; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) { return true; }
+
+ if (o == null || getClass() != o.getClass()) { return false; }
+
+ ClassificationAssociateRequest that = (ClassificationAssociateRequest) o;
+
+ return Objects.equals(classification, that.classification) && Objects.equals(entityGuids, that.entityGuids);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(classification, entityGuids);
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if (sb == null) {
+ sb = new StringBuilder();
+ }
+
+ sb.append("ClassificationAssociateRequest{");
+ sb.append("classification='");
+ if (classification != null) {
+ classification.toString(sb);
+ }
+ sb.append(", entityGuids=[");
+ AtlasBaseTypeDef.dumpObjects(entityGuids, sb);
+ sb.append("]");
+ sb.append('}');
+
+ return sb;
+ }
+
+ @Override
+ public String toString() {
+ return toString(new StringBuilder()).toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 55ac3da..760f4c3 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -9,6 +9,7 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al
ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai)
ALL CHANGES:
+ATLAS-1478 REST API to add classification to multiple entities (svimal2106 via mneethiraj)
ATLAS-1490 added methods to get sub-types of entity and classification types (mneethiraj)
ATLAS-1437 UI update to disallow tag association changes to deleted entities (Kalyanikashikar via mneethiraj)
ATLAS-1352 fix for error in redirecting to Knox gateway URL (nixonrodrigues via mneethiraj)
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
index 886a8d1..1d61ea8 100755
--- a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
@@ -146,6 +146,14 @@ public interface MetadataRepository {
void addTrait(String guid, ITypedStruct traitInstance) throws RepositoryException;
/**
+ * Adds a new trait to a list of entities represented by their respective guids
+ * @param entityGuids list of globally unique identifier for the entities
+ * @param traitInstance trait instance that needs to be added to entities
+ * @throws RepositoryException
+ */
+ void addTrait(List<String> entityGuids, ITypedStruct traitInstance) throws RepositoryException;
+
+ /**
* Deletes a given trait from an existing entity represented by a guid.
*
* @param guid globally unique identifier for the entity
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
index b9671b2..0c80aed 100755
--- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
@@ -225,6 +225,26 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
return GraphHelper.getTraitNames(instanceVertex);
}
+ /**
+ * Adds a new trait to the list of entities represented by their respective guids
+ * @param entityGuids list of globally unique identifier for the entities
+ * @param traitInstance trait instance that needs to be added to entities
+ * @throws RepositoryException
+ */
+ @Override
+ @GraphTransaction
+ public void addTrait(List<String> entityGuids, ITypedStruct traitInstance) throws RepositoryException {
+ Preconditions.checkNotNull(entityGuids, "entityGuids list cannot be null");
+ Preconditions.checkNotNull(traitInstance, "Trait instance cannot be null");
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding a new trait={} for entities={}", traitInstance.getTypeName(), entityGuids);
+ }
+
+ for (String entityGuid : entityGuids) {
+ addTraitImpl(entityGuid, traitInstance);
+ }
+ }
/**
* Adds a new trait to an existing entity represented by a guid.
@@ -236,7 +256,13 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
@Override
@GraphTransaction
public void addTrait(String guid, ITypedStruct traitInstance) throws RepositoryException {
+ Preconditions.checkNotNull(guid, "guid cannot be null");
Preconditions.checkNotNull(traitInstance, "Trait instance cannot be null");
+
+ addTraitImpl(guid, traitInstance);
+ }
+
+ private void addTraitImpl(String guid, ITypedStruct traitInstance) throws RepositoryException {
final String traitName = traitInstance.getTypeName();
if (LOG.isDebugEnabled()) {
@@ -259,7 +285,7 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
GraphHelper.setProperty(instanceVertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY,
RequestContext.get().getRequestTime());
GraphHelper.setProperty(instanceVertex, Constants.MODIFIED_BY_KEY, RequestContext.get().getUser());
-
+
} catch (RepositoryException e) {
throw e;
} catch (Exception e) {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java b/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
index 8307835..35a489f 100755
--- a/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
+++ b/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
@@ -71,7 +71,6 @@ import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
@@ -568,6 +567,39 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
}
/**
+ * Adds a new trait to the list of existing entities represented by their respective guids
+ * @param entityGuids list of guids of entities
+ * @param traitInstance trait instance json that needs to be added to entities
+ * @throws AtlasException
+ */
+ @Override
+ public void addTrait(List<String> entityGuids, ITypedStruct traitInstance) throws AtlasException {
+ Preconditions.checkNotNull(entityGuids, "entityGuids list cannot be null");
+ Preconditions.checkNotNull(traitInstance, "Trait instance cannot be null");
+
+ final String traitName = traitInstance.getTypeName();
+
+ // ensure trait type is already registered with the TypeSystem
+ if (!typeSystem.isRegistered(traitName)) {
+ String msg = String.format("trait=%s should be defined in type system before it can be added", traitName);
+ LOG.error(msg);
+ throw new TypeNotFoundException(msg);
+ }
+
+ //ensure trait is not already registered with any of the given entities
+ for (String entityGuid : entityGuids) {
+ Preconditions.checkArgument(!getTraitNames(entityGuid).contains(traitName),
+ "trait=%s is already defined for entity=%s", traitName, entityGuid);
+ }
+
+ repository.addTrait(entityGuids, traitInstance);
+
+ for (String entityGuid : entityGuids) {
+ onTraitAddedToEntity(repository.getEntityDefinition(entityGuid), traitInstance);
+ }
+ }
+
+ /**
* Adds a new trait to an existing entity represented by a guid.
*
* @param guid globally unique identifier for the entity
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
----------------------------------------------------------------------
diff --git a/server-api/src/main/java/org/apache/atlas/services/MetadataService.java b/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
index e653184..d5d8d9b 100644
--- a/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
+++ b/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
@@ -28,6 +28,7 @@ import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.types.cache.TypeCache;
+import org.apache.atlas.utils.ParamChecker;
import org.codehaus.jettison.json.JSONObject;
import java.util.List;
@@ -221,6 +222,15 @@ public interface MetadataService {
*/
void addTrait(String guid, ITypedStruct traitInstance) throws AtlasException;
+
+ /**
+ * Adds a new trait to a list of existing entities represented by their respective guids
+ * @param entityGuids list of guids of entities
+ * @param traitInstance trait instance json that needs to be added to entities
+ * @throws AtlasException
+ */
+ void addTrait(List<String> entityGuids, ITypedStruct traitInstance) throws AtlasException;
+
/**
* Create a typed trait instance.
*
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java
index 21f8977..5107767 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java
@@ -22,15 +22,19 @@ import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.AtlasException;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.SearchFilter;
+import org.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.model.instance.ClassificationAssociateRequest;
import org.apache.atlas.model.instance.EntityMutationResponse;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
import org.apache.atlas.services.MetadataService;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.ITypedStruct;
import org.apache.atlas.web.adapters.AtlasInstanceRestAdapters;
import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +50,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
@@ -184,6 +189,37 @@ public class EntitiesREST {
return entityHeaders;
}
+ /**
+ * Bulk API to associate a tag to multiple entities
+ *
+ */
+ @POST
+ @Path("/classification")
+ @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ public void addClassification(ClassificationAssociateRequest request) throws AtlasBaseException {
+ AtlasClassification classification = request == null ? null : request.getClassification();
+ List<String> entityGuids = request == null ? null : request.getEntityGuids();
+
+ if (classification == null || StringUtils.isEmpty(classification.getTypeName())) {
+ throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "no classification");
+ }
+
+ if (CollectionUtils.isEmpty(entityGuids)) {
+ throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "empty entity list");
+ }
+
+ final ITypedStruct trait = restAdapters.getTrait(classification);
+
+ try {
+ metadataService.addTrait(entityGuids, trait);
+ } catch (IllegalArgumentException e) {
+ throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, e);
+ } catch (AtlasException e) {
+ throw toAtlasBaseException(e);
+ }
+ }
+
private SearchFilter getSearchFilter() {
SearchFilter searchFilter = new SearchFilter();
if (null != httpServletRequest && null != httpServletRequest.getParameterMap()) {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/7f914ab9/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
index 90a46f8..c55234c 100644
--- a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
+++ b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
@@ -23,9 +23,11 @@ import org.apache.atlas.AtlasClient;
import org.apache.atlas.RepositoryMetadataModule;
import org.apache.atlas.RequestContext;
import org.apache.atlas.TestUtilsV2;
+import org.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasStruct;
+import org.apache.atlas.model.instance.ClassificationAssociateRequest;
import org.apache.atlas.model.instance.EntityMutationResponse;
import org.apache.atlas.model.instance.EntityMutations;
import org.apache.atlas.model.typedef.AtlasTypesDef;
@@ -33,6 +35,7 @@ import org.apache.atlas.repository.graph.AtlasGraphProvider;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.apache.atlas.web.rest.EntitiesREST;
+import org.apache.atlas.web.rest.EntityREST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
@@ -45,6 +48,7 @@ import org.testng.annotations.Test;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -59,6 +63,9 @@ public class TestEntitiesREST {
@Inject
private EntitiesREST entitiesREST;
+ @Inject
+ private EntityREST entityREST;
+
private List<String> createdGuids = new ArrayList<>();
private AtlasEntity dbEntity;
@@ -106,6 +113,18 @@ public class TestEntitiesREST {
}
}
+ @Test(dependsOnMethods = "testCreateOrUpdateEntities")
+ public void testTagToMultipleEntities() throws Exception{
+ AtlasClassification tag = new AtlasClassification(TestUtilsV2.CLASSIFICATION, new HashMap<String, Object>() {{ put("tag", "tagName"); }});
+ ClassificationAssociateRequest classificationAssociateRequest = new ClassificationAssociateRequest(createdGuids, tag);
+ entitiesREST.addClassification(classificationAssociateRequest);
+ for (String guid : createdGuids) {
+ final AtlasClassification result_tag = entityREST.getClassification(guid, TestUtilsV2.CLASSIFICATION);
+ Assert.assertNotNull(result_tag);
+ Assert.assertEquals(result_tag, tag);
+ }
+ }
+
@Test
public void testUpdateWithSerializedEntities() throws Exception {
//Check with serialization and deserialization of entity attributes for the case