Repository: incubator-atlas
Updated Branches:
  refs/heads/master 85afbefc0 -> c2356f8ef


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/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 a2c347d..13d20d8 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
@@ -19,6 +19,7 @@
 package org.apache.atlas.services;
 
 import org.apache.atlas.AtlasException;
+import org.apache.atlas.EntityAuditEvent;
 import org.apache.atlas.listener.EntityChangeListener;
 import org.apache.atlas.typesystem.Referenceable;
 import org.apache.atlas.typesystem.types.DataTypes;
@@ -207,4 +208,13 @@ public interface MetadataService {
      * @throws AtlasException
      */
     List<String> deleteEntityByUniqueAttribute(String typeName, String 
uniqueAttributeName, String attrValue) throws AtlasException;
+
+    /**
+     * Returns entity audit events for entity id in the decreasing order of 
timestamp
+     * @param guid entity id
+     * @param startKey key for the first event, used for pagination
+     * @param count number of events to be returned
+     * @return
+     */
+    List<EntityAuditEvent> getAuditEvents(String guid, String startKey, short 
count) throws AtlasException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/main/java/org/apache/atlas/web/listeners/GuiceServletConfig.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/listeners/GuiceServletConfig.java 
b/webapp/src/main/java/org/apache/atlas/web/listeners/GuiceServletConfig.java
index 6bfd780..1eca174 100755
--- 
a/webapp/src/main/java/org/apache/atlas/web/listeners/GuiceServletConfig.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/listeners/GuiceServletConfig.java
@@ -42,6 +42,7 @@ import org.apache.atlas.web.filters.ActiveServerFilter;
 import org.apache.atlas.web.filters.AtlasAuthenticationFilter;
 import org.apache.atlas.web.filters.AuditFilter;
 import org.apache.atlas.web.service.ActiveInstanceElectorModule;
+import org.apache.atlas.web.service.ServiceModule;
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
 import org.slf4j.Logger;
@@ -76,7 +77,7 @@ public class GuiceServletConfig extends 
GuiceServletContextListener {
             loginProcessor.login();
 
             injector = Guice.createInjector(getRepositoryModule(), new 
ActiveInstanceElectorModule(),
-                    new NotificationModule(), new JerseyServletModule() {
+                    new NotificationModule(), new ServiceModule(), new 
JerseyServletModule() {
 
                         private Configuration appConfiguration = null;
 

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java 
b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
index f39a80e..8e69378 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
@@ -21,12 +21,13 @@ package org.apache.atlas.web.resources;
 import com.google.common.base.Preconditions;
 import org.apache.atlas.AtlasClient;
 import org.apache.atlas.AtlasException;
+import org.apache.atlas.EntityAuditEvent;
 import org.apache.atlas.services.MetadataService;
 import org.apache.atlas.typesystem.Referenceable;
 import org.apache.atlas.typesystem.exception.EntityExistsException;
 import org.apache.atlas.typesystem.exception.EntityNotFoundException;
-import org.apache.atlas.typesystem.exception.TypeNotFoundException;
 import org.apache.atlas.typesystem.exception.TraitNotFoundException;
+import org.apache.atlas.typesystem.exception.TypeNotFoundException;
 import org.apache.atlas.typesystem.json.InstanceSerialization;
 import org.apache.atlas.typesystem.types.ValueConversionException;
 import org.apache.atlas.utils.ParamChecker;
@@ -43,6 +44,7 @@ import javax.inject.Singleton;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -52,11 +54,13 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 
@@ -95,7 +99,7 @@ public class EntityResource {
      * unique attribute for the give type.
      */
     @POST
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response submit(@Context HttpServletRequest request) {
         try {
@@ -150,7 +154,7 @@ public class EntityResource {
      * @return response payload as json
      */
     @PUT
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response updateEntities(@Context HttpServletRequest request) {
         try {
@@ -195,7 +199,7 @@ public class EntityResource {
      */
     @POST
     @Path("qualifiedName")
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response updateByUniqueAttribute(@QueryParam("type") String 
entityType,
                                             @QueryParam("property") String 
attribute,
@@ -242,7 +246,7 @@ public class EntityResource {
      */
     @POST
     @Path("{guid}")
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response updateEntityByGuid(@PathParam("guid") String guid, 
@QueryParam("property") String attribute,
                                        @Context HttpServletRequest request) {
@@ -327,7 +331,6 @@ public class EntityResource {
      * @return response payload as json - including guids of 
entities(including composite references from that entity) that were deleted
      */
     @DELETE
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response deleteEntities(@QueryParam("guid") List<String> guids,
         @QueryParam("type") String entityType,
@@ -439,6 +442,7 @@ public class EntityResource {
     }
 
     @GET
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response getEntity(@QueryParam("type") String entityType,
                               @QueryParam("property") String attribute,
@@ -537,7 +541,7 @@ public class EntityResource {
      */
     @POST
     @Path("{guid}/traits")
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response addTrait(@Context HttpServletRequest request, 
@PathParam("guid") String guid) {
         try {
@@ -573,7 +577,7 @@ public class EntityResource {
      */
     @DELETE
     @Path("{guid}/traits/{traitName}")
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response deleteTrait(@Context HttpServletRequest request, 
@PathParam("guid") String guid,
             @PathParam(TRAIT_NAME) String traitName) {
@@ -601,4 +605,45 @@ public class EntityResource {
             throw new WebApplicationException(Servlets.getErrorResponse(e, 
Response.Status.INTERNAL_SERVER_ERROR));
         }
     }
+
+    /**
+     * Returns the entity audit events for a given entity id. The events are 
returned in the decreasing order of timestamp.
+     * @param guid entity id
+     * @param startKey used for pagination. Startkey is inclusive, the 
returned results contain the event with the given startkey.
+     *                  First time getAuditEvents() is called for an entity, 
startKey should be null,
+     *                  with count = (number of events required + 1). Next 
time getAuditEvents() is called for the same entity,
+     *                  startKey should be equal to the entityKey of the last 
event returned in the previous call.
+     * @param count number of events required
+     * @return
+     */
+    @GET
+    @Path("{guid}/audit")
+    @Produces(Servlets.JSON_MEDIA_TYPE)
+    public Response getAuditEvents(@PathParam("guid") String guid, 
@QueryParam("startKey") String startKey,
+                                   @QueryParam("count") @DefaultValue("100") 
short count) {
+        LOG.debug("Audit events request for entity {}, start key {}, number of 
results required {}", guid, startKey,
+                count);
+        try {
+            List<EntityAuditEvent> events = 
metadataService.getAuditEvents(guid, startKey, count);
+
+            JSONObject response = new JSONObject();
+            response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
+            response.put(AtlasClient.EVENTS, getJSONArray(events));
+            return Response.ok(response).build();
+        } catch (AtlasException | IllegalArgumentException e) {
+            LOG.error("Unable to get audit events for entity {}", guid, e);
+            throw new WebApplicationException(Servlets.getErrorResponse(e, 
Response.Status.BAD_REQUEST));
+        } catch (Throwable e) {
+            LOG.error("Unable to get audit events for entity {}", guid, e);
+            throw new WebApplicationException(Servlets.getErrorResponse(e, 
Response.Status.INTERNAL_SERVER_ERROR));
+        }
+    }
+
+    private <T> JSONArray getJSONArray(Collection<T> elements) throws 
JSONException {
+        JSONArray jsonArray = new JSONArray();
+        for(T element : elements) {
+            jsonArray.put(new JSONObject(element.toString()));
+        }
+        return jsonArray;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java 
b/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
index 8b0d0e9..74d89ce 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/TypesResource.java
@@ -45,6 +45,7 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.List;
 
@@ -76,7 +77,7 @@ public class TypesResource {
      * domain. Could represent things like Hive Database, Hive Table, etc.
      */
     @POST
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response submit(@Context HttpServletRequest request) {
         try {
@@ -120,7 +121,7 @@ public class TypesResource {
      * @return
      */
     @PUT
-    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON})
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Response update(@Context HttpServletRequest request) {
         try {

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceElectorModule.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceElectorModule.java
 
b/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceElectorModule.java
index 065666d..ee6035d 100644
--- 
a/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceElectorModule.java
+++ 
b/webapp/src/main/java/org/apache/atlas/web/service/ActiveInstanceElectorModule.java
@@ -22,6 +22,7 @@ import com.google.inject.AbstractModule;
 import com.google.inject.multibindings.Multibinder;
 import org.apache.atlas.listener.ActiveStateChangeHandler;
 import org.apache.atlas.notification.NotificationHookConsumer;
+import org.apache.atlas.repository.audit.HBaseBasedAuditRepository;
 import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
 import org.apache.atlas.service.Service;
 import org.apache.atlas.services.DefaultMetadataService;
@@ -39,8 +40,7 @@ public class ActiveInstanceElectorModule extends 
AbstractModule {
         
activeStateChangeHandlerBinder.addBinding().to(GraphBackedSearchIndexer.class);
         
activeStateChangeHandlerBinder.addBinding().to(DefaultMetadataService.class);
         
activeStateChangeHandlerBinder.addBinding().to(NotificationHookConsumer.class);
-        //Enable this after ATLAS-498 is committed
-        
//activeStateChangeHandlerBinder.addBinding().to(HBaseBasedAuditRepository.class);
+        
activeStateChangeHandlerBinder.addBinding().to(HBaseBasedAuditRepository.class);
 
         Multibinder<Service> serviceBinder = 
Multibinder.newSetBinder(binder(), Service.class);
         serviceBinder.addBinding().to(ActiveInstanceElectorService.class);

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java 
b/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
new file mode 100644
index 0000000..0f8bcb1
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
@@ -0,0 +1,41 @@
+/**
+ * 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.web.service;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import org.apache.atlas.kafka.KafkaNotification;
+import org.apache.atlas.listener.EntityChangeListener;
+import org.apache.atlas.notification.NotificationHookConsumer;
+import org.apache.atlas.notification.entity.NotificationEntityChangeListener;
+import org.apache.atlas.service.Service;
+
+public class ServiceModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        Multibinder<Service> serviceBinder = 
Multibinder.newSetBinder(binder(), Service.class);
+        serviceBinder.addBinding().to(KafkaNotification.class);
+        serviceBinder.addBinding().to(NotificationHookConsumer.class);
+
+        //Add NotificationEntityChangeListener as EntityChangeListener
+        Multibinder<EntityChangeListener> entityChangeListenerBinder =
+                Multibinder.newSetBinder(binder(), EntityChangeListener.class);
+        
entityChangeListenerBinder.addBinding().to(NotificationEntityChangeListener.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/c2356f8e/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
 
b/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
index 6a939d3..83db46f 100755
--- 
a/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
+++ 
b/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
@@ -26,6 +26,7 @@ import com.sun.jersey.api.client.WebResource;
 
 import org.apache.atlas.AtlasClient;
 import org.apache.atlas.AtlasServiceException;
+import org.apache.atlas.EntityAuditEvent;
 import org.apache.atlas.notification.NotificationConsumer;
 import org.apache.atlas.notification.NotificationInterface;
 import org.apache.atlas.notification.NotificationModule;
@@ -146,6 +147,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
         db.set("description", randomString());
 
         final String dbid = serviceClient.createEntity(db).getString(0);
+        assertEntityAudit(dbid, 
EntityAuditEvent.EntityAuditAction.ENTITY_CREATE);
 
         waitForNotification(notificationConsumer, MAX_WAIT_TIME, new 
NotificationPredicate() {
             @Override
@@ -187,6 +189,17 @@ public class EntityJerseyResourceIT extends BaseResourceIT 
{
         assertEquals(results.length(), 1);
     }
 
+    private void assertEntityAudit(String dbid, 
EntityAuditEvent.EntityAuditAction auditAction)
+            throws Exception {
+        List<EntityAuditEvent> events = 
serviceClient.getEntityAuditEvents(dbid, (short) 100);
+        for (EntityAuditEvent event : events) {
+            if (event.getAction() == auditAction) {
+                return;
+            }
+        }
+        fail("Expected audit event with action = " + auditAction);
+    }
+
     @Test
     public void testEntityDefinitionAcrossTypeUpdate() throws Exception {
         //create type
@@ -478,6 +491,8 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
         JSONObject response = new JSONObject(responseAsString);
         Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
         Assert.assertNotNull(response.get(AtlasClient.GUID));
+
+        assertEntityAudit(guid, EntityAuditEvent.EntityAuditAction.TAG_ADD);
     }
 
     @Test(dependsOnMethods = "testAddTrait")
@@ -576,6 +591,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
         Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
         Assert.assertNotNull(response.get("GUID"));
         Assert.assertNotNull(response.get("traitName"));
+        assertEntityAudit(guid, EntityAuditEvent.EntityAuditAction.TAG_DELETE);
     }
 
     @Test

Reply via email to