Repository: atlas
Updated Branches:
  refs/heads/branch-0.8 9c1008ddb -> 8d926f21f


ATLAS-2798: Export & Import Audits.


Project: http://git-wip-us.apache.org/repos/asf/atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/8d926f21
Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/8d926f21
Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/8d926f21

Branch: refs/heads/branch-0.8
Commit: 8d926f21fe3d447f8fbe13a760cc224fc1b6e757
Parents: 9c1008d
Author: Ashutosh Mestry <ames...@hortonworks.com>
Authored: Thu Aug 2 08:26:20 2018 -0700
Committer: Ashutosh Mestry <ames...@hortonworks.com>
Committed: Thu Aug 2 08:46:41 2018 -0700

----------------------------------------------------------------------
 addons/models/0010-base_model.json              |  73 ++++++++++
 .../model/impexp/ExportImportAuditEntry.java    | 135 +++++++++++++++++++
 .../impexp/ExportImportAuditService.java        | 121 +++++++++++++++++
 .../atlas/repository/ogm/DTORegistry.java       |   1 +
 .../apache/atlas/repository/ogm/DataAccess.java |   7 +-
 .../ogm/ExportImportAuditEntryDTO.java          |  90 +++++++++++++
 .../impexp/ExportImportAuditServiceTest.java    | 119 ++++++++++++++++
 .../atlas/web/resources/AdminResource.java      |  34 ++++-
 .../atlas/web/resources/AdminResourceTest.java  |   4 +-
 9 files changed, 579 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/addons/models/0010-base_model.json
----------------------------------------------------------------------
diff --git a/addons/models/0010-base_model.json 
b/addons/models/0010-base_model.json
index 2003d89..59660c5 100644
--- a/addons/models/0010-base_model.json
+++ b/addons/models/0010-base_model.json
@@ -249,6 +249,79 @@
           "isUnique": false
         }
       ]
+    },
+    {
+      "name": "__ExportImportAuditEntry",
+      "typeVersion": "1.0",
+      "superTypes": [
+        "__internal"
+      ],
+      "attributeDefs": [
+        {
+          "name": "userName",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": false,
+          "isOptional": true,
+          "isUnique": false
+        },
+        {
+          "name": "operation",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": false,
+          "isUnique": false
+        },
+        {
+          "name": "sourceClusterName",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": false,
+          "isUnique": false
+        },
+        {
+          "name": "targetClusterName",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": true,
+          "isUnique": false
+        },
+        {
+          "name": "operationParams",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": true,
+          "isUnique": false
+        },
+        {
+          "name": "operationStartTime",
+          "typeName": "long",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": false,
+          "isUnique": false
+        },
+        {
+          "name": "operationEndTime",
+          "typeName": "long",
+          "cardinality": "SINGLE",
+          "isIndexable": true,
+          "isOptional": true,
+          "isUnique": false
+        },
+        {
+          "name": "resultSummary",
+          "typeName": "string",
+          "cardinality": "SINGLE",
+          "isIndexable": false,
+          "isOptional": true,
+          "isUnique": false
+        }
+      ]
     }
   ]
 }

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/intg/src/main/java/org/apache/atlas/model/impexp/ExportImportAuditEntry.java
----------------------------------------------------------------------
diff --git 
a/intg/src/main/java/org/apache/atlas/model/impexp/ExportImportAuditEntry.java 
b/intg/src/main/java/org/apache/atlas/model/impexp/ExportImportAuditEntry.java
new file mode 100644
index 0000000..2c83c42
--- /dev/null
+++ 
b/intg/src/main/java/org/apache/atlas/model/impexp/ExportImportAuditEntry.java
@@ -0,0 +1,135 @@
+/**
+ * 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.impexp;
+
+import org.apache.atlas.model.AtlasBaseModelObject;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE;
+import static 
org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.PUBLIC_ONLY;
+
+@JsonAutoDetect(getterVisibility = PUBLIC_ONLY, setterVisibility = 
PUBLIC_ONLY, fieldVisibility = NONE)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ExportImportAuditEntry extends AtlasBaseModelObject implements 
Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String OPERATION_EXPORT = "EXPORT";
+    public static final String OPERATION_IMPORT = "IMPORT";
+
+    private String userName;
+    private String operation;
+    private String operationParams;
+    private long startTime;
+    private long endTime;
+    private String resultSummary;
+    private String sourceClusterName;
+    private String targetClusterName;
+
+    public ExportImportAuditEntry() {
+
+    }
+
+    public ExportImportAuditEntry(String sourceClusterName, String operation) {
+        this.sourceClusterName = sourceClusterName;
+        this.operation = operation;
+    }
+
+    public String getOperation() {
+        return operation;
+    }
+
+    public void setOperation(String operation) {
+        this.operation = operation;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getUserName() {
+        return this.userName;
+    }
+    public void setOperationParams(String operationParams) {
+        this.operationParams = operationParams;
+    }
+
+    public String getOperationParams() {
+        return this.operationParams;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setEndTime(long endTime) {
+        this.endTime = endTime;
+    }
+
+    public long getEndTime() {
+        return this.endTime;
+    }
+
+    public String getTargetClusterName() {
+        return this.targetClusterName;
+    }
+
+    public String getSourceClusterName() {
+        return this.sourceClusterName;
+    }
+
+    public void setSourceClusterName(String sourceClusterName) {
+        this.sourceClusterName = sourceClusterName;
+    }
+
+    public void setTargetClusterName(String targetClusterName) {
+        this.targetClusterName = targetClusterName;
+    }
+
+    public String getResultSummary() {
+        return resultSummary;
+    }
+
+    public void setResultSummary(String resultSummary) {
+        this.resultSummary = resultSummary;
+    }
+
+    @Override
+    public StringBuilder toString(StringBuilder sb) {
+        sb.append(", userName: ").append(userName);
+        sb.append(", operation: ").append(operation);
+        sb.append(", operationParams: ").append(operationParams);
+        sb.append(", sourceClusterName: ").append(sourceClusterName);
+        sb.append(", targetClusterName: ").append(targetClusterName);
+        sb.append(", startTime: ").append(startTime);
+        sb.append(", endTime: ").append(endTime);
+        sb.append(", resultSummary: ").append(resultSummary);
+
+        return sb;
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/repository/src/main/java/org/apache/atlas/repository/impexp/ExportImportAuditService.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/repository/impexp/ExportImportAuditService.java
 
b/repository/src/main/java/org/apache/atlas/repository/impexp/ExportImportAuditService.java
new file mode 100644
index 0000000..ebfc33f
--- /dev/null
+++ 
b/repository/src/main/java/org/apache/atlas/repository/impexp/ExportImportAuditService.java
@@ -0,0 +1,121 @@
+/**
+ * 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.repository.impexp;
+
+import org.apache.atlas.annotation.AtlasService;
+import org.apache.atlas.discovery.AtlasDiscoveryService;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.discovery.AtlasSearchResult;
+import org.apache.atlas.model.discovery.SearchParameters;
+import org.apache.atlas.model.impexp.ExportImportAuditEntry;
+import org.apache.atlas.repository.ogm.DataAccess;
+import org.apache.atlas.repository.ogm.ExportImportAuditEntryDTO;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+
+@AtlasService
+public class ExportImportAuditService {
+    private static final Logger LOG = 
LoggerFactory.getLogger(ExportImportAuditService.class);
+    private static final String ENTITY_TYPE_NAME = "__ExportImportAuditEntry";
+
+    private final DataAccess dataAccess;
+    private AtlasDiscoveryService discoveryService;
+
+    @Inject
+    public ExportImportAuditService(DataAccess dataAccess, 
AtlasDiscoveryService discoveryService) {
+        this.dataAccess = dataAccess;
+        this.discoveryService = discoveryService;
+    }
+
+    public void save(ExportImportAuditEntry entry) throws AtlasBaseException {
+        dataAccess.saveNoLoad(entry);
+    }
+    public ExportImportAuditEntry get(ExportImportAuditEntry entry) throws 
AtlasBaseException {
+        if(entry.getGuid() == null) {
+            throw new AtlasBaseException("entity does not have GUID set. load 
cannot proceed.");
+        }
+        return dataAccess.load(entry);
+    }
+
+    public AtlasSearchResult get(String userName, String operation, String 
sourceCluster, String targetCluster,
+                                 String startTime, String endTime,
+                                 int limit, int offset) throws 
AtlasBaseException {
+        SearchParameters.FilterCriteria criteria = new 
SearchParameters.FilterCriteria();
+        criteria.setCriterion(new 
ArrayList<SearchParameters.FilterCriteria>());
+
+        addSearchParameters(criteria, userName, operation, sourceCluster, 
targetCluster, startTime, endTime);
+
+        SearchParameters searchParameters = getSearchParameters(limit, offset, 
criteria);
+
+        return discoveryService.searchWithParameters(searchParameters);
+    }
+
+    private SearchParameters getSearchParameters(int limit, int offset, 
SearchParameters.FilterCriteria criteria) {
+        SearchParameters searchParameters = new SearchParameters();
+        searchParameters.setTypeName(ENTITY_TYPE_NAME);
+        searchParameters.setEntityFilters(criteria);
+        searchParameters.setLimit(limit);
+        searchParameters.setOffset(offset);
+        return searchParameters;
+    }
+
+    private void addSearchParameters(SearchParameters.FilterCriteria criteria,
+                                     String userName, String operation, String 
sourceCluster, String targetCluster,
+                                     String startTime, String endTime) {
+
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_USER_NAME, userName);
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_OPERATION, operation);
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_SOURCE_CLUSTER_NAME, sourceCluster);
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_TARGET_CLUSTER_NAME, targetCluster);
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_START_TIME, startTime);
+        addParameterIfValueNotEmpty(criteria, 
ExportImportAuditEntryDTO.PROPERTY_END_TIME, endTime);
+    }
+
+    private void addParameterIfValueNotEmpty(SearchParameters.FilterCriteria 
criteria,
+                                             String attributeName, String 
value) {
+        if(StringUtils.isEmpty(value)) return;
+
+        boolean isFirstCriteria = criteria.getAttributeName() == null;
+        SearchParameters.FilterCriteria cx = isFirstCriteria
+                                                ? criteria
+                                                : new 
SearchParameters.FilterCriteria();
+
+        setCriteria(cx, attributeName, value);
+
+        if(isFirstCriteria) {
+            cx.setCondition(SearchParameters.FilterCriteria.Condition.AND);
+        }
+
+        if(!isFirstCriteria) {
+            criteria.getCriterion().add(cx);
+        }
+    }
+
+    private SearchParameters.FilterCriteria 
setCriteria(SearchParameters.FilterCriteria criteria, String attributeName, 
String value) {
+        criteria.setAttributeName(attributeName);
+        criteria.setAttributeValue(value);
+        criteria.setOperator(SearchParameters.Operator.EQ);
+
+        return criteria;
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java 
b/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java
index c62ce1b..d417ce7 100644
--- a/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java
+++ b/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java
@@ -38,6 +38,7 @@ public class DTORegistry {
         registerDTO(savedSearchDTO);
         registerDTO(userProfileDTO);
         registerDTO(new AtlasClusterDTO(typeRegistry));
+        registerDTO(new ExportImportAuditEntryDTO(typeRegistry));
     }
 
     public <T extends DataTransferObject> DataTransferObject get(Type t) {

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java 
b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
index c99d2f8..b7e943f 100644
--- a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
+++ b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java
@@ -42,6 +42,11 @@ public class DataAccess {
     }
 
     public <T extends AtlasBaseModelObject> T save(T obj) throws 
AtlasBaseException {
+        saveNoLoad(obj);
+        return this.load(obj);
+    }
+
+    public <T extends AtlasBaseModelObject> void saveNoLoad(T obj) throws 
AtlasBaseException {
         DataTransferObject<T> dto = 
(DataTransferObject<T>)dtoRegistry.get(obj.getClass());
 
         AtlasEntityWithExtInfo entityWithExtInfo      = 
dto.toEntityWithExtInfo(obj);
@@ -50,8 +55,6 @@ public class DataAccess {
         if (hasError(entityMutationResponse)) {
             throw new 
AtlasBaseException(AtlasErrorCode.DATA_ACCESS_SAVE_FAILED, obj.toString());
         }
-
-        return this.load(obj);
     }
 
     public <T extends AtlasBaseModelObject> T load(T obj) throws 
AtlasBaseException {

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/repository/src/main/java/org/apache/atlas/repository/ogm/ExportImportAuditEntryDTO.java
----------------------------------------------------------------------
diff --git 
a/repository/src/main/java/org/apache/atlas/repository/ogm/ExportImportAuditEntryDTO.java
 
b/repository/src/main/java/org/apache/atlas/repository/ogm/ExportImportAuditEntryDTO.java
new file mode 100644
index 0000000..8d1aebf
--- /dev/null
+++ 
b/repository/src/main/java/org/apache/atlas/repository/ogm/ExportImportAuditEntryDTO.java
@@ -0,0 +1,90 @@
+/**
+ * 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.repository.ogm;
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.impexp.ExportImportAuditEntry;
+import org.apache.atlas.type.AtlasTypeRegistry;
+
+import java.util.Map;
+
+public class ExportImportAuditEntryDTO extends 
AbstractDataTransferObject<ExportImportAuditEntry> {
+
+    public static final String PROPERTY_USER_NAME              = "userName";
+    public static final String PROPERTY_OPERATION              = "operation";
+    public static final String PROPERTY_OPERATION_PARAMS       = 
"operationParams";
+    public static final String PROPERTY_START_TIME             = 
"operationStartTime";
+    public static final String PROPERTY_END_TIME               = 
"operationEndTime";
+    public static final String PROPERTY_RESULT_SUMMARY         = 
"resultSummary";
+    public static final String PROPERTY_SOURCE_CLUSTER_NAME    = 
"sourceClusterName";
+    public static final String PROPERTY_TARGET_CLUSTER_NAME    = 
"targetClusterName";
+
+    protected ExportImportAuditEntryDTO(AtlasTypeRegistry typeRegistry) {
+        super(typeRegistry, ExportImportAuditEntry.class);
+    }
+
+    @Override
+    public ExportImportAuditEntry from(AtlasEntity entity) {
+        ExportImportAuditEntry entry = new ExportImportAuditEntry();
+
+        setGuid(entry, entity);
+        entry.setUserName((String) entity.getAttribute(PROPERTY_USER_NAME));
+        entry.setOperation((String) entity.getAttribute(PROPERTY_OPERATION));
+        entry.setOperationParams((String) 
entity.getAttribute(PROPERTY_OPERATION_PARAMS));
+        entry.setStartTime((long) entity.getAttribute(PROPERTY_START_TIME));
+        entry.setEndTime((long) entity.getAttribute(PROPERTY_END_TIME));
+        entry.setSourceClusterName((String) 
entity.getAttribute(PROPERTY_SOURCE_CLUSTER_NAME));
+        entry.setTargetClusterName((String) 
entity.getAttribute(PROPERTY_TARGET_CLUSTER_NAME));
+        entry.setResultSummary((String) 
entity.getAttribute(PROPERTY_RESULT_SUMMARY));
+
+        return entry;
+    }
+
+    @Override
+    public ExportImportAuditEntry from(AtlasEntity.AtlasEntityWithExtInfo 
entityWithExtInfo) {
+        return from(entityWithExtInfo.getEntity());
+    }
+
+    @Override
+    public AtlasEntity toEntity(ExportImportAuditEntry obj) {
+        AtlasEntity entity = getDefaultAtlasEntity(obj);
+
+        entity.setAttribute(PROPERTY_USER_NAME, obj.getUserName());
+        entity.setAttribute(PROPERTY_OPERATION, obj.getOperation());
+        entity.setAttribute(PROPERTY_OPERATION_PARAMS, 
obj.getOperationParams());
+        entity.setAttribute(PROPERTY_START_TIME, obj.getStartTime());
+        entity.setAttribute(PROPERTY_END_TIME, obj.getEndTime());
+        entity.setAttribute(PROPERTY_SOURCE_CLUSTER_NAME, 
obj.getSourceClusterName());
+        entity.setAttribute(PROPERTY_TARGET_CLUSTER_NAME, 
obj.getTargetClusterName());
+        entity.setAttribute(PROPERTY_RESULT_SUMMARY, obj.getResultSummary());
+
+        return entity;
+    }
+
+    @Override
+    public AtlasEntity.AtlasEntityWithExtInfo 
toEntityWithExtInfo(ExportImportAuditEntry obj) throws AtlasBaseException {
+        return new AtlasEntity.AtlasEntityWithExtInfo(toEntity(obj));
+    }
+
+    @Override
+    public Map<String, Object> getUniqueAttributes(final 
ExportImportAuditEntry obj) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/repository/src/test/java/org/apache/atlas/repository/impexp/ExportImportAuditServiceTest.java
----------------------------------------------------------------------
diff --git 
a/repository/src/test/java/org/apache/atlas/repository/impexp/ExportImportAuditServiceTest.java
 
b/repository/src/test/java/org/apache/atlas/repository/impexp/ExportImportAuditServiceTest.java
new file mode 100644
index 0000000..f3803e5
--- /dev/null
+++ 
b/repository/src/test/java/org/apache/atlas/repository/impexp/ExportImportAuditServiceTest.java
@@ -0,0 +1,119 @@
+/**
+ * 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.repository.impexp;
+
+import org.apache.atlas.TestModules;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.discovery.AtlasSearchResult;
+import org.apache.atlas.model.impexp.ExportImportAuditEntry;
+import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.store.AtlasTypeDefStore;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+import java.io.IOException;
+
+import static 
org.apache.atlas.repository.impexp.ZipFileResourceTestUtils.loadBaseModel;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
+
+@Guice(modules = TestModules.TestOnlyModule.class)
+public class ExportImportAuditServiceTest {
+    @Inject
+    AtlasTypeRegistry typeRegistry;
+
+    @Inject
+    private AtlasTypeDefStore typeDefStore;
+
+    @Inject
+    ExportImportAuditService auditService;
+
+    @BeforeClass
+    public void setup() throws IOException, AtlasBaseException {
+        loadBaseModel(typeDefStore, typeRegistry);
+    }
+
+    @Test
+    public void checkTypeRegistered() throws AtlasBaseException {
+        AtlasType auditEntryType = typeRegistry.getType("__" + 
ExportImportAuditEntry.class.getSimpleName());
+        assertNotNull(auditEntryType);
+    }
+
+    @Test
+    public void saveLogEntry() throws AtlasBaseException, InterruptedException 
{
+        final String source1 = "clx";
+        final String target1 = "cly";
+        ExportImportAuditEntry entry = saveAndGet(source1, 
ExportImportAuditEntry.OPERATION_EXPORT, target1);
+
+        String source2 = "clx2";
+        String target2 = "clx1";
+        ExportImportAuditEntry entry2 = saveAndGet(source2, 
ExportImportAuditEntry.OPERATION_EXPORT, target2);
+
+        Thread.sleep(1000);
+        ExportImportAuditEntry actualEntry = retrieveEntry(entry);
+        ExportImportAuditEntry actualEntry2 = retrieveEntry(entry2);
+
+        assertNotEquals(actualEntry.getGuid(), actualEntry2.getGuid());
+        assertNotNull(actualEntry.getGuid());
+        assertEquals(actualEntry.getSourceClusterName(), 
entry.getSourceClusterName());
+        assertEquals(actualEntry.getTargetClusterName(), 
entry.getTargetClusterName());
+        assertEquals(actualEntry.getOperation(), entry.getOperation());
+    }
+
+    @Test
+    public void numberOfSavedEntries_Retrieved() throws AtlasBaseException, 
InterruptedException {
+        final String source1 = "cluster1";
+        final String target1 = "cly";
+        int MAX_ENTRIES = 5;
+
+        for (int i = 0; i < MAX_ENTRIES; i++) {
+            saveAndGet(source1, ExportImportAuditEntry.OPERATION_EXPORT, 
target1);
+        }
+
+        Thread.sleep(1000);
+        AtlasSearchResult results = auditService.get(source1, 
ExportImportAuditEntry.OPERATION_EXPORT, "", "", "", "", 10, 0);
+        assertEquals(results.getEntities().size(), MAX_ENTRIES);
+    }
+
+
+    private ExportImportAuditEntry retrieveEntry(ExportImportAuditEntry entry) 
throws AtlasBaseException {
+        AtlasSearchResult result = auditService.get(entry.getUserName(), 
entry.getOperation(), entry.getSourceClusterName(),
+                                                            
entry.getTargetClusterName(), Long.toString(entry.getStartTime()), "", 10, 0);
+        assertNotNull(result);
+        assertEquals(result.getEntities().size(), 1);
+        entry.setGuid(result.getEntities().get(0).getGuid());
+        return auditService.get(entry);
+    }
+
+    private ExportImportAuditEntry saveAndGet(String sourceClusterName, String 
operation, String targetClusterName) throws AtlasBaseException {
+        ExportImportAuditEntry entry = new 
ExportImportAuditEntry(sourceClusterName, operation);
+
+        entry.setTargetClusterName(targetClusterName);
+        entry.setUserName("default");
+        entry.setStartTime(System.currentTimeMillis());
+        entry.setEndTime(System.currentTimeMillis() + 1000L);
+        auditService.save(entry);
+        return entry;
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java 
b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
index 072dbb4..4224bb1 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/AdminResource.java
@@ -28,6 +28,7 @@ import org.apache.atlas.authorize.AtlasResourceTypes;
 import org.apache.atlas.authorize.simple.AtlasAuthorizationUtils;
 import org.apache.atlas.discovery.SearchContext;
 import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.discovery.AtlasSearchResult;
 import org.apache.atlas.model.impexp.AtlasExportRequest;
 import org.apache.atlas.model.impexp.AtlasExportResult;
 import org.apache.atlas.model.impexp.AtlasImportRequest;
@@ -37,9 +38,11 @@ import org.apache.atlas.repository.impexp.ExportService;
 import org.apache.atlas.repository.impexp.ImportService;
 import org.apache.atlas.repository.impexp.ZipSink;
 import org.apache.atlas.repository.impexp.ZipSource;
+import org.apache.atlas.repository.impexp.ExportImportAuditService;
 import org.apache.atlas.services.MetricsService;
 import org.apache.atlas.type.AtlasType;
 import org.apache.atlas.util.SearchTracker;
+import org.apache.atlas.utils.AtlasPerfTracer;
 import org.apache.atlas.web.filters.AtlasCSRFPreventionFilter;
 import org.apache.atlas.web.service.ServiceState;
 import org.apache.atlas.web.util.Servlets;
@@ -89,6 +92,7 @@ import java.util.concurrent.locks.ReentrantLock;
 @Service
 public class AdminResource {
     private static final Logger LOG = 
LoggerFactory.getLogger(AdminResource.class);
+    private static final Logger PERF_LOG = 
AtlasPerfTracer.getPerfLogger("AdminResource");
 
     @Context
     private HttpServletRequest httpServletRequest;
@@ -115,6 +119,7 @@ public class AdminResource {
     private final ExportService exportService;
     private final ImportService importService;
     private final SearchTracker activeSearches;
+    private ExportImportAuditService exportImportAuditService;
 
     static {
         try {
@@ -126,12 +131,14 @@ public class AdminResource {
 
     @Inject
     public AdminResource(ServiceState serviceState, MetricsService 
metricsService,
-                         ExportService exportService, ImportService 
importService, SearchTracker activeSearches) {
+                         ExportService exportService, ImportService 
importService, SearchTracker activeSearches,
+                         ExportImportAuditService exportImportAuditService) {
         this.serviceState               = serviceState;
         this.metricsService             = metricsService;
         this.exportService = exportService;
         this.importService = importService;
         this.activeSearches = activeSearches;
+        this.exportImportAuditService = exportImportAuditService;
         importExportOperationLock = new ReentrantLock();
     }
 
@@ -425,6 +432,31 @@ public class AdminResource {
     }
 
     @GET
+    @Path("/expimp/audit")
+    @Consumes(Servlets.JSON_MEDIA_TYPE)
+    @Produces(Servlets.JSON_MEDIA_TYPE)
+    public AtlasSearchResult 
getExportImportAudit(@QueryParam("sourceClusterName") String sourceCluster,
+                                                  @QueryParam("targetCluster") 
String targetCluster,
+                                                  @QueryParam("userName") 
String userName,
+                                                  @QueryParam("operation") 
String operation,
+                                                  @QueryParam("startTime") 
String startTime,
+                                                  @QueryParam("endTime") 
String endTime,
+                                                  @QueryParam("limit") int 
limit,
+                                                  @QueryParam("offset") int 
offset) throws AtlasBaseException {
+        AtlasPerfTracer perf = null;
+
+        try {
+            if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, 
"getExportImportAudit(" + sourceCluster + ")");
+            }
+
+            return exportImportAuditService.get(userName, operation, 
sourceCluster, targetCluster, startTime, endTime, limit, offset);
+        } finally {
+            AtlasPerfTracer.log(perf);
+        }
+    }
+
+    @GET
     @Path("activeSearches")
     @Produces(Servlets.JSON_MEDIA_TYPE)
     public Set<String> getActiveSearches() {

http://git-wip-us.apache.org/repos/asf/atlas/blob/8d926f21/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
----------------------------------------------------------------------
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java 
b/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
index c0bbf09..1fe3119 100644
--- a/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/AdminResourceTest.java
@@ -48,7 +48,7 @@ public class AdminResourceTest {
 
         
when(serviceState.getState()).thenReturn(ServiceState.ServiceStateValue.ACTIVE);
 
-        AdminResource adminResource = new AdminResource(serviceState, null, 
null, null, null);
+        AdminResource adminResource = new AdminResource(serviceState, null, 
null, null, null, null);
         Response response = adminResource.getStatus();
         assertEquals(response.getStatus(), HttpServletResponse.SC_OK);
         JSONObject entity = (JSONObject) response.getEntity();
@@ -59,7 +59,7 @@ public class AdminResourceTest {
     public void testResourceGetsValueFromServiceState() throws JSONException {
         
when(serviceState.getState()).thenReturn(ServiceState.ServiceStateValue.PASSIVE);
 
-        AdminResource adminResource = new AdminResource(serviceState, null, 
null, null, null);
+        AdminResource adminResource = new AdminResource(serviceState, null, 
null, null, null, null);
         Response response = adminResource.getStatus();
 
         verify(serviceState).getState();

Reply via email to