You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2016/11/05 06:19:43 UTC

[1/2] incubator-ranger git commit: RANGER-1197: track downloaded and active policy/tag versions in plugins

Repository: incubator-ranger
Updated Branches:
  refs/heads/master 804753ed2 -> f4a20e0b9


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index 19fea65..f272ff3 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -30,6 +30,7 @@ import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 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;
@@ -67,6 +68,7 @@ import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.XXPolicyExportAudit;
 import org.apache.ranger.entity.XXService;
 import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
@@ -77,7 +79,12 @@ import org.apache.ranger.plugin.model.validation.RangerPolicyValidator;
 import org.apache.ranger.plugin.model.validation.RangerServiceDefValidator;
 import org.apache.ranger.plugin.model.validation.RangerServiceValidator;
 import org.apache.ranger.plugin.model.validation.RangerValidator.Action;
-import org.apache.ranger.plugin.policyengine.*;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineCache;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
 import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator;
 import org.apache.ranger.plugin.service.ResourceLookupContext;
 import org.apache.ranger.plugin.store.PList;
@@ -89,9 +96,11 @@ import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.plugin.util.ServicePolicies;
 import org.apache.ranger.security.context.RangerAPIList;
 import org.apache.ranger.security.web.filter.RangerCSRFPreventionFilter;
+import org.apache.ranger.service.RangerPluginInfoService;
 import org.apache.ranger.service.RangerPolicyService;
 import org.apache.ranger.service.RangerServiceDefService;
 import org.apache.ranger.service.RangerServiceService;
+import org.apache.ranger.view.RangerPluginInfoList;
 import org.apache.ranger.view.RangerPolicyList;
 import org.apache.ranger.view.RangerServiceDefList;
 import org.apache.ranger.view.RangerServiceList;
@@ -149,7 +158,10 @@ public class ServiceREST {
 	
 	@Autowired
 	RangerServiceDefService serviceDefService;
-	
+
+	@Autowired
+    RangerPluginInfoService pluginInfoService;
+
 	@Autowired
 	RangerSearchUtil searchUtil;
 	
@@ -1800,9 +1812,9 @@ public class ServiceREST {
 	@GET
 	@Path("/policies/download/{serviceName}")
 	@Produces({ "application/json", "application/xml" })
-	public ServicePolicies getServicePoliciesIfUpdated(@PathParam("serviceName") String serviceName, @QueryParam("lastKnownVersion") Long lastKnownVersion, @QueryParam("pluginId") String pluginId, @Context HttpServletRequest request) throws Exception {
+	public ServicePolicies getServicePoliciesIfUpdated(@PathParam("serviceName") String serviceName, @QueryParam("lastKnownVersion") Long lastKnownVersion, @DefaultValue("0") @QueryParam("lastActivationTime") Long lastActivationTime, @QueryParam("pluginId") String pluginId, @Context HttpServletRequest request) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> ServiceREST.getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ")");
+			LOG.debug("==> ServiceREST.getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ")");
 		}
 
 		ServicePolicies ret      = null;
@@ -1817,20 +1829,24 @@ public class ServiceREST {
 			
 			try {
 				if(RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
-					perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "ServiceREST.getServicePoliciesIfUpdated(serviceName=" + serviceName + ",lastKnownVersion=" + lastKnownVersion + ")");
+					perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "ServiceREST.getServicePoliciesIfUpdated(serviceName=" + serviceName + ",lastKnownVersion=" + lastKnownVersion +  ",lastActivationTime=" + lastActivationTime + ")");
 				}
 				ServicePolicies servicePolicies = svcStore.getServicePoliciesIfUpdated(serviceName, lastKnownVersion);
-	
+
+                Long downloadedVersion;
 				if(servicePolicies == null) {
+                    downloadedVersion = lastKnownVersion;
 					httpCode = HttpServletResponse.SC_NOT_MODIFIED;
 					logMsg   = "No change since last update";
 				} else {
+                    downloadedVersion = servicePolicies.getPolicyVersion();
 					ret = filterServicePolicies(servicePolicies);
 					httpCode = HttpServletResponse.SC_OK;
-					logMsg   = "Returning " + (ret.getPolicies() != null ? ret.getPolicies().size() : 0) + " policies. Policy version=" + ret.getPolicyVersion();
+                    logMsg   = "Returning " + (ret.getPolicies() != null ? ret.getPolicies().size() : 0) + " policies. Policy version=" + ret.getPolicyVersion();
 				}
-			} catch(Throwable excp) {
-				LOG.error("getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed", excp);
+                assetMgr.createPluginInfo(serviceName, pluginId, request, RangerPluginInfo.ENTITY_TYPE_POLICIES, downloadedVersion, lastKnownVersion, lastActivationTime, httpCode);
+            } catch(Throwable excp) {
+				LOG.error("getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ") failed", excp);
 	
 				httpCode = HttpServletResponse.SC_BAD_REQUEST;
 				logMsg   = excp.getMessage();
@@ -1846,16 +1862,16 @@ public class ServiceREST {
 		 }
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== ServiceREST.getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + "): count=" + ((ret == null || ret.getPolicies() == null) ? 0 : ret.getPolicies().size()));
+			LOG.debug("<== ServiceREST.getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + "): count=" + ((ret == null || ret.getPolicies() == null) ? 0 : ret.getPolicies().size()));
 		}
 
 		return ret;
 	}
-	
+
 	@GET
 	@Path("/secure/policies/download/{serviceName}")
 	@Produces({ "application/json", "application/xml" })
-	public ServicePolicies getSecureServicePoliciesIfUpdated(@PathParam("serviceName") String serviceName,@QueryParam("lastKnownVersion") Long lastKnownVersion,@QueryParam("pluginId") String pluginId,@Context HttpServletRequest request) throws Exception {
+	public ServicePolicies getSecureServicePoliciesIfUpdated(@PathParam("serviceName") String serviceName,@QueryParam("lastKnownVersion") Long lastKnownVersion, @DefaultValue("0") @QueryParam("lastActivationTime") Long lastActivationTime, @QueryParam("pluginId") String pluginId,@Context HttpServletRequest request) throws Exception {
 		if (LOG.isDebugEnabled()) {
 			LOG.debug("==> ServiceREST.getSecureServicePoliciesIfUpdated("+ serviceName + ", " + lastKnownVersion + ")");
 		}
@@ -1873,7 +1889,7 @@ public class ServiceREST {
 			}
 			try {
 				if (RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
-					perf = RangerPerfTracer.getPerfTracer(PERF_LOG,"ServiceREST.getSecureServicePoliciesIfUpdated(serviceName="+ serviceName + ",lastKnownVersion="+ lastKnownVersion + ")");
+					perf = RangerPerfTracer.getPerfTracer(PERF_LOG,"ServiceREST.getSecureServicePoliciesIfUpdated(serviceName="+ serviceName + ",lastKnownVersion="+ lastKnownVersion +  ",lastActivationTime=" + lastActivationTime + ")");
 				}
 				XXService xService = daoManager.getXXService().findByName(serviceName);
 				XXServiceDef xServiceDef = daoManager.getXXServiceDef().getById(xService.getType());
@@ -1907,21 +1923,26 @@ public class ServiceREST {
 				}
 				if (isAllowed) {
 					ServicePolicies servicePolicies = svcStore.getServicePoliciesIfUpdated(serviceName,lastKnownVersion);
+                    Long downloadedVersion;
 					if (servicePolicies == null) {
+					    downloadedVersion = lastKnownVersion;
 						httpCode = HttpServletResponse.SC_NOT_MODIFIED;
 						logMsg = "No change since last update";
 					} else {
+					    downloadedVersion = servicePolicies.getPolicyVersion();
 						ret = filterServicePolicies(servicePolicies);
 						httpCode = HttpServletResponse.SC_OK;
 						logMsg = "Returning " + (ret.getPolicies() != null ? ret.getPolicies().size() : 0) + " policies. Policy version=" + ret.getPolicyVersion();
 					}
-				} else {
+
+                    assetMgr.createPluginInfo(serviceName, pluginId, request, RangerPluginInfo.ENTITY_TYPE_POLICIES, downloadedVersion, lastKnownVersion, lastActivationTime, httpCode);
+                } else {
 					LOG.error("getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed as User doesn't have permission to download Policy");
 					httpCode = HttpServletResponse.SC_UNAUTHORIZED;
 					logMsg = "User doesn't have permission to download policy";
 				}
 			} catch (Throwable excp) {
-				LOG.error("getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed", excp);
+				LOG.error("getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ") failed", excp);
 				httpCode = HttpServletResponse.SC_BAD_REQUEST;
 				logMsg = excp.getMessage();
 			} finally {
@@ -1934,7 +1955,7 @@ public class ServiceREST {
 			}
 		}
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== ServiceREST.getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + "): count=" + ((ret == null || ret.getPolicies() == null) ? 0 : ret.getPolicies().size()));
+			LOG.debug("<== ServiceREST.getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + "): count=" + ((ret == null || ret.getPolicies() == null) ? 0 : ret.getPolicies().size()));
 		}
 		return ret;
 	}		
@@ -2078,6 +2099,45 @@ public class ServiceREST {
 		return svcStore.getPolicyForVersionNumber(policyId, versionNo);
 	}
 
+	@GET
+	@Path("/plugins/info")
+	@Produces({ "application/json", "application/xml" })
+	@PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_PLUGINS_INFO + "\")")
+	public RangerPluginInfoList getPluginsInfo(@Context HttpServletRequest request) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> ServiceREST.getPluginsInfo()");
+		}
+
+		RangerPluginInfoList ret = null;
+
+		SearchFilter filter = searchUtil.getSearchFilter(request, pluginInfoService.getSortFields());
+
+		try {
+			PList<RangerPluginInfo> paginatedPluginsInfo = pluginInfoService.searchRangerPluginInfo(filter);
+			if (paginatedPluginsInfo != null) {
+				ret = new RangerPluginInfoList();
+
+				ret.setPluginInfoList(paginatedPluginsInfo.getList());
+				ret.setPageSize(paginatedPluginsInfo.getPageSize());
+				ret.setResultSize(paginatedPluginsInfo.getResultSize());
+				ret.setStartIndex(paginatedPluginsInfo.getStartIndex());
+				ret.setTotalCount(paginatedPluginsInfo.getTotalCount());
+				ret.setSortBy(paginatedPluginsInfo.getSortBy());
+				ret.setSortType(paginatedPluginsInfo.getSortType());
+			}
+		} catch (WebApplicationException excp) {
+			throw excp;
+		} catch (Throwable excp) {
+			LOG.error("getPluginsInfo() failed", excp);
+
+			throw restErrorUtil.createRESTException(excp.getMessage());
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== ServiceREST.getPluginsInfo()");
+		}
+
+		return ret;
+	}
 
 	private RangerPolicy getPolicyByGuid(String guid) {
 		RangerPolicy ret = null;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
index b76c308..feb6a54 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
@@ -23,6 +23,7 @@ import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.biz.AssetMgr;
 import org.apache.ranger.biz.RangerBizUtil;
 import org.apache.ranger.biz.ServiceDBStore;
 import org.apache.ranger.biz.TagDBStore;
@@ -30,6 +31,7 @@ import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.XXService;
 import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
 import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.model.RangerServiceResource;
 import org.apache.ranger.plugin.model.RangerTag;
@@ -48,8 +50,18 @@ import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.*;
+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;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
 
 import java.util.List;
 
@@ -77,6 +89,9 @@ public class TagREST {
 	@Autowired
 	RangerBizUtil bizUtil;
 
+    @Autowired
+    AssetMgr assetMgr;
+
     TagValidator validator;
 
     public TagREST() {
@@ -1088,9 +1103,11 @@ public class TagREST {
     @Path(TagRESTConstants.TAGS_DOWNLOAD + "{serviceName}")
     @Produces({ "application/json", "application/xml" })
     public ServiceTags getServiceTagsIfUpdated(@PathParam("serviceName") String serviceName,
-                                                   @QueryParam(TagRESTConstants.LAST_KNOWN_TAG_VERSION_PARAM) Long lastKnownVersion, @QueryParam("pluginId") String pluginId) {
+                                                   @QueryParam(TagRESTConstants.LAST_KNOWN_TAG_VERSION_PARAM) Long lastKnownVersion,
+                                               @DefaultValue("0") @QueryParam(TagRESTConstants.LAST_ACTIVATION_TIME) Long lastActivationTime, @QueryParam("pluginId") String pluginId,
+                                               @Context HttpServletRequest request) {
         if(LOG.isDebugEnabled()) {
-            LOG.debug("==> TagREST.getServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+            LOG.debug("==> TagREST.getServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ", " + pluginId + ")");
         }
 
 		ServiceTags ret      = null;
@@ -1099,14 +1116,18 @@ public class TagREST {
 
         try {
             ret = tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion);
+            Long downloadedVersion;
 
 			if(ret == null) {
+                downloadedVersion = lastKnownVersion;
 				httpCode = HttpServletResponse.SC_NOT_MODIFIED;
 				logMsg   = "No change since last update";
 			} else {
+                downloadedVersion = ret.getTagVersion();
 				httpCode = HttpServletResponse.SC_OK;
 				logMsg   = "Returning " + (ret.getTags() != null ? ret.getTags().size() : 0) + " tags. Tag version=" + ret.getTagVersion();
 			}
+            assetMgr.createPluginInfo(serviceName, pluginId, request, RangerPluginInfo.ENTITY_TYPE_TAGS, downloadedVersion, lastKnownVersion, lastActivationTime, httpCode);
         } catch(Exception excp) {
             LOG.error("getServiceTagsIfUpdated(" + serviceName + ") failed", excp);
 
@@ -1120,7 +1141,7 @@ public class TagREST {
 		}
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("<==> TagREST.getServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+            LOG.debug("<== TagREST.getServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ", " + pluginId + ")");
         }
 
         return ret;
@@ -1130,9 +1151,12 @@ public class TagREST {
     @Path(TagRESTConstants.TAGS_SECURE_DOWNLOAD + "{serviceName}")
     @Produces({ "application/json", "application/xml" })
     public ServiceTags getSecureServiceTagsIfUpdated(@PathParam("serviceName") String serviceName,
-                                                   @QueryParam(TagRESTConstants.LAST_KNOWN_TAG_VERSION_PARAM) Long lastKnownVersion, @QueryParam("pluginId") String pluginId) {
+                                                   @QueryParam(TagRESTConstants.LAST_KNOWN_TAG_VERSION_PARAM) Long lastKnownVersion,
+                                                     @DefaultValue("0") @QueryParam(TagRESTConstants.LAST_ACTIVATION_TIME) Long lastActivationTime, @QueryParam("pluginId") String pluginId,
+                                                     @Context HttpServletRequest request) {
+
         if(LOG.isDebugEnabled()) {
-            LOG.debug("==> TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+            LOG.debug("==> TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ", " + pluginId + ")");
         }
 
 		ServiceTags ret      = null;
@@ -1162,16 +1186,20 @@ public class TagREST {
         	}
         	if (isAllowed) {
 	            ret = tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion);
-	
+                Long downloadedVersion;
+
 				if(ret == null) {
+                    downloadedVersion = lastKnownVersion;
 					httpCode = HttpServletResponse.SC_NOT_MODIFIED;
 					logMsg   = "No change since last update";
 				} else {
+                    downloadedVersion = ret.getTagVersion();
 					httpCode = HttpServletResponse.SC_OK;
 					logMsg   = "Returning " + (ret.getTags() != null ? ret.getTags().size() : 0) + " tags. Tag version=" + ret.getTagVersion();
 				}
+                assetMgr.createPluginInfo(serviceName, pluginId, request, RangerPluginInfo.ENTITY_TYPE_TAGS, downloadedVersion, lastKnownVersion, lastActivationTime, httpCode);
 			}else{
-				LOG.error("getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed as User doesn't have permission to download tags");
+				LOG.error("getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ") failed as User doesn't have permission to download tags");
 				httpCode = HttpServletResponse.SC_UNAUTHORIZED;
 				logMsg = "User doesn't have permission to download tags";
 			}
@@ -1180,17 +1208,24 @@ public class TagREST {
 
 			httpCode = HttpServletResponse.SC_BAD_REQUEST;
 			logMsg   = excp.getMessage();
+        }  finally {
+            // Placeholder to avoid PMD violations
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("httpCode=" + httpCode);
+            }
+            // createOrUpdatePluginTagVersion(serviceName, lastKnownVersion, pluginId, lastActivationTime);
         }
 
-		if(httpCode != HttpServletResponse.SC_OK) {
+        if(httpCode != HttpServletResponse.SC_OK) {
 			boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
 			throw restErrorUtil.createRESTException(httpCode, logMsg, logError);
 		}
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("<==> TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+            LOG.debug("<== TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + lastActivationTime + ", " + pluginId + ")");
         }
 
         return ret;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java b/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
index 7f836bc..9e78cf0 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
@@ -38,5 +38,6 @@ public class TagRESTConstants {
 
 	public static final String SERVICE_NAME_PARAM           = "serviceName";
 	public static final String LAST_KNOWN_TAG_VERSION_PARAM = "lastKnownVersion";
+	public static final String LAST_ACTIVATION_TIME = "lastActivationTime";
 	public static final String PATTERN_PARAM                = "pattern";
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
index 6466712..dd74e8f 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
@@ -85,6 +85,9 @@ public class RangerAPIList {
 	public static final String GET_POLICY_FROM_EVENT_TIME = "ServiceREST.getPolicyFromEventTime";
 	public static final String GET_POLICY_VERSION_LIST = "ServiceREST.getPolicyVersionList";
 	public static final String GET_POLICY_FOR_VERSION_NO = "ServiceREST.getPolicyForVersionNumber";
+	public static final String GET_PLUGINS_INFO = "ServiceREST.getPluginsInfo";
+
+
 
 	/**
 	 * List of APIs for UserREST

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
index 28b0a37..3529601 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIMapping.java
@@ -91,6 +91,7 @@ public class RangerAPIMapping {
 		apiAssociatedWithReports.add(RangerAPIList.GET_POLICY_FOR_VERSION_NO);
 		apiAssociatedWithReports.add(RangerAPIList.GET_POLICY_FROM_EVENT_TIME);
 		apiAssociatedWithReports.add(RangerAPIList.GET_POLICY_VERSION_LIST);
+		apiAssociatedWithReports.add(RangerAPIList.GET_PLUGINS_INFO);
 		apiAssociatedWithReports.add(RangerAPIList.GET_SERVICE);
 		apiAssociatedWithReports.add(RangerAPIList.GET_SERVICE_BY_NAME);
 		apiAssociatedWithReports.add(RangerAPIList.GET_SERVICE_DEF);
@@ -372,6 +373,7 @@ public class RangerAPIMapping {
 		apiAssociatedWithAudit.add(RangerAPIList.GET_POLICY_FOR_VERSION_NO);
 		apiAssociatedWithAudit.add(RangerAPIList.GET_POLICY_FROM_EVENT_TIME);
 		apiAssociatedWithAudit.add(RangerAPIList.GET_POLICY_VERSION_LIST);
+		apiAssociatedWithAudit.add(RangerAPIList.GET_PLUGINS_INFO);
 		apiAssociatedWithAudit.add(RangerAPIList.GET_SERVICE);
 		apiAssociatedWithAudit.add(RangerAPIList.GET_SERVICE_BY_NAME);
 		apiAssociatedWithAudit.add(RangerAPIList.GET_SERVICE_DEF);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginActivityLogger.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerPluginActivityLogger.java b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginActivityLogger.java
new file mode 100644
index 0000000..0335e6d
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginActivityLogger.java
@@ -0,0 +1,68 @@
+/*
+ * 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.ranger.service;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+public class RangerPluginActivityLogger {
+    @Autowired
+    RangerTransactionService transactionService;
+
+    @Autowired
+    RangerTransactionSynchronizationAdapter transactionSynchronizationAdapter;
+
+    private static final Log LOG = LogFactory.getLog(RangerPluginActivityLogger.class);
+
+    boolean pluginActivityAuditCommitInline = false;
+
+    @PostConstruct
+    public void init() {
+        pluginActivityAuditCommitInline = PropertiesUtil.getBooleanProperty("ranger.plugin.activity.audit.commit.inline", false);
+        LOG.info("ranger.plugin.activity.audit.commit.inline = " + pluginActivityAuditCommitInline);
+        if (pluginActivityAuditCommitInline) {
+            LOG.info("Will use TransactionManager for committing scheduled work");
+        } else {
+            LOG.info("Will use separate thread for committing scheduled work");
+        }
+    }
+
+    public void commitAfterTransactionComplete(Runnable commitWork) {
+        if (pluginActivityAuditCommitInline) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Using TransactionManager for committing work [pluginActivityAuditCommitInline:" + pluginActivityAuditCommitInline + "]");
+            }
+            transactionSynchronizationAdapter.executeOnTransactionCompletion(commitWork);
+        } else {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Using separate thread for committing work [pluginActivityAuditCommitInline:" + pluginActivityAuditCommitInline + "]");
+            }
+            transactionService.executeAfterTransactionComplete(commitWork);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginInfoService.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerPluginInfoService.java b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginInfoService.java
new file mode 100644
index 0000000..fe86e72
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerPluginInfoService.java
@@ -0,0 +1,196 @@
+/*
+ * 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.ranger.service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ranger.biz.RangerBizUtil;
+import org.apache.ranger.common.JSONUtil;
+import org.apache.ranger.common.RangerSearchUtil;
+import org.apache.ranger.common.SearchField;
+import org.apache.ranger.common.SortField;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXPluginInfo;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
+import org.apache.ranger.plugin.store.PList;
+import org.apache.ranger.plugin.util.SearchFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+@Service
+public class RangerPluginInfoService {
+
+	@Autowired
+	RangerSearchUtil searchUtil;
+
+	@Autowired
+	RangerBizUtil bizUtil;
+
+	@Autowired
+	JSONUtil jsonUtil;
+
+	@Autowired
+	RangerDaoManager daoManager;
+
+	private List<SortField> sortFields = new ArrayList<SortField>();
+	private List<SearchField> searchFields = new ArrayList<SearchField>();
+
+	RangerPluginInfoService() {
+
+		searchFields.add(new SearchField(SearchFilter.SERVICE_NAME, "obj.serviceName", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+		searchFields.add(new SearchField(SearchFilter.PLUGIN_HOST_NAME, "obj.hostName", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+		searchFields.add(new SearchField(SearchFilter.PLUGIN_APP_TYPE, "obj.appType", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+		searchFields.add(new SearchField(SearchFilter.PLUGIN_IP_ADDRESS, "obj.ipAddress", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+
+		sortFields.add(new SortField(SearchFilter.SERVICE_NAME, "obj.serviceName", true, SortField.SORT_ORDER.ASC));
+		sortFields.add(new SortField(SearchFilter.PLUGIN_HOST_NAME, "obj.hostName", true, SortField.SORT_ORDER.ASC));
+		sortFields.add(new SortField(SearchFilter.PLUGIN_APP_TYPE, "obj.appType", true, SortField.SORT_ORDER.ASC));
+
+	}
+
+	public List<SearchField> getSearchFields() {
+		return searchFields;
+	}
+
+	public List<SortField> getSortFields() {
+		return sortFields;
+	}
+
+	public PList<RangerPluginInfo> searchRangerPluginInfo(SearchFilter searchFilter) {
+		PList<RangerPluginInfo> retList = new PList<RangerPluginInfo>();
+		List<RangerPluginInfo> objList = new ArrayList<RangerPluginInfo>();
+
+		List<XXPluginInfo> xObjList = searchRangerObjects(searchFilter, searchFields, sortFields, retList);
+
+		for (XXPluginInfo xObj : xObjList) {
+			RangerPluginInfo obj = populateViewObject(xObj);
+			objList.add(obj);
+		}
+
+		retList.setList(objList);
+
+		return retList;
+	}
+
+	public RangerPluginInfo populateViewObject(XXPluginInfo xObj) {
+		RangerPluginInfo ret = new RangerPluginInfo();
+		ret.setId(xObj.getId());
+		ret.setCreateTime(xObj.getCreateTime());
+		ret.setUpdateTime(xObj.getUpdateTime());
+		ret.setServiceName(xObj.getServiceName());
+		ret.setHostName(xObj.getHostName());
+		ret.setAppType(xObj.getAppType());
+		ret.setIpAddress(xObj.getIpAddress());
+		ret.setInfo(jsonStringToMap(xObj.getInfo()));
+		return ret;
+	}
+
+	public XXPluginInfo populateDBObject(RangerPluginInfo modelObj) {
+		XXPluginInfo ret = new XXPluginInfo();
+		ret.setId(modelObj.getId());
+		ret.setCreateTime(modelObj.getCreateTime());
+		ret.setUpdateTime(modelObj.getUpdateTime());
+		ret.setServiceName(modelObj.getServiceName());
+		ret.setHostName(modelObj.getHostName());
+		ret.setAppType(modelObj.getAppType());
+		ret.setIpAddress(modelObj.getIpAddress());
+		ret.setInfo(mapToJsonString(modelObj.getInfo()));
+		return ret;
+	}
+	private List<XXPluginInfo> searchRangerObjects(SearchFilter searchCriteria, List<SearchField> searchFieldList, List<SortField> sortFieldList, PList<RangerPluginInfo> pList) {
+
+		// Get total count of the rows which meet the search criteria
+		long count = -1;
+		if (searchCriteria.isGetCount()) {
+			count = getCountForSearchQuery(searchCriteria, searchFieldList);
+			if (count == 0) {
+				return Collections.emptyList();
+			}
+		}
+
+		String sortClause = searchUtil.constructSortClause(searchCriteria, sortFieldList);
+
+		String queryStr = "SELECT obj FROM " + XXPluginInfo.class.getName() + " obj ";
+		Query query = createQuery(queryStr, sortClause, searchCriteria, searchFieldList, false);
+
+		List<XXPluginInfo> resultList = daoManager.getXXPluginInfo().executeQueryInSecurityContext(XXPluginInfo.class, query);
+
+		if (pList != null) {
+			pList.setResultSize(resultList.size());
+			pList.setPageSize(query.getMaxResults());
+			pList.setSortBy(searchCriteria.getSortBy());
+			pList.setSortType(searchCriteria.getSortType());
+			pList.setStartIndex(query.getFirstResult());
+			pList.setTotalCount(count);
+		}
+		return resultList;
+	}
+
+	private Query createQuery(String searchString, String sortString, SearchFilter searchCriteria,
+								List<SearchField> searchFieldList, boolean isCountQuery) {
+
+		EntityManager em = daoManager.getEntityManager();
+		return searchUtil.createSearchQuery(em, searchString, sortString, searchCriteria,
+				searchFieldList, bizUtil.getClassType(XXPluginInfo.class), false, isCountQuery);
+	}
+
+	private long getCountForSearchQuery(SearchFilter searchCriteria, List<SearchField> searchFieldList) {
+
+		String countQueryStr = "SELECT COUNT(obj) FROM " + XXPluginInfo.class.getName() + " obj ";
+
+		Query query = createQuery(countQueryStr, null, searchCriteria, searchFieldList, true);
+		Long count = daoManager.getXXPluginInfo().executeCountQueryInSecurityContext(XXPluginInfo.class, query);
+
+		if (count == null) {
+			return 0;
+		}
+		return count;
+	}
+
+	private String mapToJsonString(Map<String, String> map) {
+		String ret = null;
+
+		if(map != null) {
+			try {
+				ret = jsonUtil.readMapToString(map);
+			} catch(Exception excp) {
+			}
+		}
+
+		return ret;
+	}
+
+	private Map<String, String> jsonStringToMap(String jsonStr) {
+		Map<String, String> ret = null;
+
+			try {
+				ret = jsonUtil.jsonToMap(jsonStr);
+			} catch(Exception excp) {
+
+			}
+
+
+		return ret;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/service/RangerTransactionService.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerTransactionService.java b/security-admin/src/main/java/org/apache/ranger/service/RangerTransactionService.java
new file mode 100644
index 0000000..c60773e
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerTransactionService.java
@@ -0,0 +1,105 @@
+/*
+ * 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.ranger.service;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+@Service
+public class RangerTransactionService {
+    @Autowired
+    @Qualifier(value = "transactionManager")
+    PlatformTransactionManager txManager;
+
+    private static final Log LOG = LogFactory.getLog(RangerTransactionService.class);
+
+    private ScheduledExecutorService scheduler = null;
+
+    @PostConstruct
+    public void init() {
+        scheduler = Executors.newScheduledThreadPool(1);
+    }
+
+    @PreDestroy
+    public void destroy() {
+        try {
+            LOG.info("attempt to shutdown RangerTransactionService");
+            scheduler.shutdown();
+            scheduler.awaitTermination(5, TimeUnit.SECONDS);
+        }
+        catch (InterruptedException e) {
+            LOG.error("RangerTransactionService tasks interrupted");
+        }
+        finally {
+            if (!scheduler.isTerminated()) {
+                LOG.info("cancel non-finished RangerTransactionService tasks");
+            }
+            scheduler.shutdownNow();
+            LOG.info("RangerTransactionService shutdown finished");
+        }
+    }
+
+    public void executeAfterTransactionComplete(final Runnable task) {
+        try {
+            scheduler.schedule(new Runnable() {
+                @Override
+                public void run() {
+                    if (task != null) {
+                        try {
+                            //Create new  transaction
+                            TransactionTemplate txTemplate = new TransactionTemplate(txManager);
+                            txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+
+                            txTemplate.execute(new TransactionCallback<Object>() {
+                                public Object doInTransaction(TransactionStatus status) {
+                                    task.run();
+                                    return null;
+                                }
+                            });
+                        } catch (Exception e) {
+                            LOG.error("Failed to commit TransactionService transaction", e);
+                            LOG.error("Ignoring...");
+                        }
+                    }
+                }
+            }, 1000L, MILLISECONDS);
+        } catch (Exception e) {
+            LOG.error("Failed to schedule TransactionService transaction:", e);
+            LOG.error("Ignroing...");
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/view/RangerPluginInfoList.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/view/RangerPluginInfoList.java b/security-admin/src/main/java/org/apache/ranger/view/RangerPluginInfoList.java
new file mode 100644
index 0000000..52b6bba
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/RangerPluginInfoList.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ranger.view;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerPluginInfoList extends VList {
+	private static final long serialVersionUID = 1L;
+
+	List<RangerPluginInfo> pluginInfoList = new ArrayList<RangerPluginInfo>();
+
+	public RangerPluginInfoList() {
+		super();
+	}
+
+	public RangerPluginInfoList(List<RangerPluginInfo> objList) {
+		super(objList);
+		this.pluginInfoList = objList;
+	}
+
+	public List<RangerPluginInfo> getPluginInfoList() {
+		return pluginInfoList;
+	}
+
+	public void setPluginInfoList(List<RangerPluginInfo> pluginInfoList) {
+		this.pluginInfoList = pluginInfoList;
+	}
+
+	@Override
+	public int getListSize() {
+		if (pluginInfoList != null) {
+			return pluginInfoList.size();
+		}
+		return 0;
+	}
+
+	@Override
+	public List<?> getList() {
+		return pluginInfoList;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
----------------------------------------------------------------------
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index a94b9a0..fe9d91a 100644
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -1127,4 +1127,29 @@
 	<named-query name="XXPortalUserRole.findXPortalUserRolebyXPortalUserId">
 		<query>select obj.userRole from XXPortalUserRole obj where obj.userId = :userId</query>
 	</named-query>
+
+	<!-- XXPluginInfo -->
+	<named-query name="XXPluginInfo.find">
+		<query>
+			select obj from XXPluginInfo obj where obj.serviceName = :serviceName and obj.appType = :appType and obj.hostName = :hostName
+		</query>
+	</named-query>
+	<named-query name="XXPluginInfo.findByServiceName">
+		<query>
+			select obj from XXPluginInfo obj where obj.serviceName = :serviceName
+		</query>
+	</named-query>
+
+	<named-query name="XXPluginInfo.findByServiceId">
+		<query>
+			select obj from XXPluginInfo obj, XXService service where obj.serviceName = service.name and service.id = :serviceId
+		</query>
+	</named-query>
+
+	<named-query name="XXPluginInfo.findByServiceAndHostName">
+		<query>
+			select obj from XXPluginInfo obj where obj.serviceName = :serviceName and obj.hostName = :hostName
+		</query>
+	</named-query>
+
 </entity-mappings>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/security-admin/src/main/resources/META-INF/persistence.xml b/security-admin/src/main/resources/META-INF/persistence.xml
index b0f764a..20f5bba 100644
--- a/security-admin/src/main/resources/META-INF/persistence.xml
+++ b/security-admin/src/main/resources/META-INF/persistence.xml
@@ -76,6 +76,8 @@
 		<class>org.apache.ranger.entity.XXDataMaskTypeDef</class>
 		<class>org.apache.ranger.entity.XXPolicyItemDataMaskInfo</class>
 		<class>org.apache.ranger.entity.XXPolicyItemRowFilterInfo</class>
+		<class>org.apache.ranger.entity.XXServiceVersionInfo</class>
+		<class>org.apache.ranger.entity.XXPluginInfo</class>
         <shared-cache-mode>NONE</shared-cache-mode>
 
 		<properties>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
index e951549..fafd4e0 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
@@ -962,7 +962,7 @@ public class TestServiceREST {
 		Long lastKnownVersion = 1L;
 		String pluginId = "1";
 		ServicePolicies dbServicePolicies = serviceREST
-				.getServicePoliciesIfUpdated(serviceName, lastKnownVersion,
+				.getServicePoliciesIfUpdated(serviceName, lastKnownVersion, 0L,
 						pluginId, request);
 		Assert.assertNull(dbServicePolicies);
 	}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/test/java/org/apache/ranger/rest/TestTagREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestTagREST.java b/security-admin/src/test/java/org/apache/ranger/rest/TestTagREST.java
index fabd384..9608544 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestTagREST.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestTagREST.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import javax.ws.rs.WebApplicationException;
 
+import org.apache.ranger.biz.AssetMgr;
 import org.apache.ranger.biz.RangerBizUtil;
 import org.apache.ranger.biz.ServiceDBStore;
 import org.apache.ranger.biz.TagDBStore;
@@ -85,6 +86,9 @@ public class TestTagREST {
 	@Mock
 	ServiceDBStore svcStore;
 
+	@Mock
+	AssetMgr assetMgr;
+
 	@Rule
 	public ExpectedException thrown = ExpectedException.none();
 
@@ -1408,7 +1412,7 @@ public class TestTagREST {
 		Mockito.when(restErrorUtil.createRESTException(Mockito.anyInt(),Mockito.anyString(), Mockito.anyBoolean())).thenThrow(new WebApplicationException());
 		thrown.expect(WebApplicationException.class);
 		
-		tagREST.getServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		tagREST.getServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		
 		try {
 			Mockito.verify(tagStore).getServiceTagsIfUpdated(serviceName, lastKnownVersion);
@@ -1427,8 +1431,12 @@ public class TestTagREST {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
 		} catch (Exception e) {
 		}
-		
-		ServiceTags serviceTags = tagREST.getServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		try {
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
+
+		} catch (Exception e) {
+		}
+		ServiceTags serviceTags = tagREST.getServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		Assert.assertEquals(serviceTags.getServiceName(), oldServiceTag.getServiceName());
 		Assert.assertEquals(serviceTags.getTagVersion(), oldServiceTag.getTagVersion());
 		
@@ -1477,10 +1485,11 @@ public class TestTagREST {
 		
 		try {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
 		} catch (Exception e) {
 		}
 		
-		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		Assert.assertNotNull(result.getServiceName());
 		Assert.assertEquals(result.getServiceName(), oldServiceTag.getServiceName());
 		Assert.assertEquals(result.getTagVersion(), oldServiceTag.getTagVersion());
@@ -1539,10 +1548,11 @@ public class TestTagREST {
 		
 		try {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
 		} catch (Exception e) {
 		}
 		
-		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		Assert.assertNotNull(result.getServiceName());
 		Assert.assertEquals(result.getServiceName(), oldServiceTag.getServiceName());
 		Assert.assertEquals(result.getTagVersion(), oldServiceTag.getTagVersion());
@@ -1604,10 +1614,11 @@ public class TestTagREST {
 		Mockito.when(bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Tag_Download)).thenReturn(isAllowed);
 		try {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
 		} catch (Exception e) {
 		}
 		
-		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		Assert.assertNotNull(result.getServiceName());
 		Assert.assertEquals(result.getServiceName(), oldServiceTag.getServiceName());
 		Assert.assertEquals(result.getTagVersion(), oldServiceTag.getTagVersion());
@@ -1669,10 +1680,11 @@ public class TestTagREST {
 		Mockito.when(bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Tag_Download)).thenReturn(isAllowed);
 		try {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
 		} catch (Exception e) {
 		}
 		
-		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		ServiceTags result = tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		Assert.assertNotNull(result.getServiceName());
 		Assert.assertEquals(result.getServiceName(), oldServiceTag.getServiceName());
 		Assert.assertEquals(result.getTagVersion(), oldServiceTag.getTagVersion());
@@ -1735,7 +1747,7 @@ public class TestTagREST {
 		Mockito.when(restErrorUtil.createRESTException(Mockito.anyInt(), Mockito.anyString(), Mockito.anyBoolean())).thenThrow(new WebApplicationException());
 		thrown.expect(WebApplicationException.class);
 		
-		tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		
 		Mockito.verify(bizUtil).isAdmin();
 		Mockito.verify(bizUtil).isKeyAdmin();
@@ -1789,12 +1801,13 @@ public class TestTagREST {
 		Mockito.when(bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Tag_Download)).thenReturn(isAllowed);
 		try {
 			Mockito.when(tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion)).thenReturn(oldServiceTag);
+			Mockito.doNothing().when(assetMgr).createPluginInfo(serviceName, pluginId, null, 1, 1, lastKnownVersion, 1, 0);
 		} catch (Exception e) {
 		}
 		Mockito.when(restErrorUtil.createRESTException(Mockito.anyInt(), Mockito.anyString(), Mockito.anyBoolean())).thenThrow(new WebApplicationException());
 		thrown.expect(WebApplicationException.class);
 		
-		tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, pluginId);
+		tagREST.getSecureServiceTagsIfUpdated(serviceName, lastKnownVersion, 0L, pluginId, null);
 		
 		Mockito.verify(bizUtil).isAdmin();
 		Mockito.verify(bizUtil).isKeyAdmin();

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/storm-agent/src/test/java/org/apache/ranger/authorization/storm/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/storm-agent/src/test/java/org/apache/ranger/authorization/storm/RangerAdminClientImpl.java b/storm-agent/src/test/java/org/apache/ranger/authorization/storm/RangerAdminClientImpl.java
index e327435..ade034d 100644
--- a/storm-agent/src/test/java/org/apache/ranger/authorization/storm/RangerAdminClientImpl.java
+++ b/storm-agent/src/test/java/org/apache/ranger/authorization/storm/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
 
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
 
     }


[2/2] incubator-ranger git commit: RANGER-1197: track downloaded and active policy/tag versions in plugins

Posted by ma...@apache.org.
RANGER-1197: track downloaded and active policy/tag versions in plugins

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/f4a20e0b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/f4a20e0b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/f4a20e0b

Branch: refs/heads/master
Commit: f4a20e0b9e259a436cb27cb48988076eee4f443a
Parents: 804753e
Author: Abhay Kulkarni <ak...@hortonworks.com>
Authored: Mon Aug 1 15:00:35 2016 -0700
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Fri Nov 4 20:49:19 2016 -0700

----------------------------------------------------------------------
 .../ranger/admin/client/RangerAdminClient.java  |   4 +-
 .../admin/client/RangerAdminRESTClient.java     |  27 +-
 .../RangerAdminTagRetriever.java                |   4 +-
 .../RangerFileBasedTagRetriever.java            |   6 +-
 .../contextenricher/RangerTagEnricher.java      |  17 +-
 .../RangerTagFileStoreRetriever.java            |   3 +-
 .../contextenricher/RangerTagRetriever.java     |   2 +-
 .../ranger/plugin/model/RangerPluginInfo.java   | 261 ++++++++++++++++++
 .../ranger/plugin/util/PolicyRefresher.java     |  16 +-
 .../ranger/plugin/util/RangerRESTUtils.java     |  34 +++
 .../apache/ranger/plugin/util/SearchFilter.java |   6 +
 .../hbase/RangerAdminClientImpl.java            |   4 +-
 .../services/hdfs/RangerAdminClientImpl.java    |   4 +-
 .../services/hive/RangerAdminClientImpl.java    |   4 +-
 .../client/RangerAdminJersey2RESTClient.java    |  10 +-
 .../kafka/authorizer/RangerAdminClientImpl.java |   4 +-
 .../kms/authorizer/RangerAdminClientImpl.java   |   6 +-
 .../025-create-schema-for-plugin-info.sql       |  33 +++
 .../025-create-schema-for-plugin-info.sql       |  35 +++
 .../java/org/apache/ranger/biz/AssetMgr.java    | 267 +++++++++++++++----
 .../apache/ranger/common/RangerSearchUtil.java  |   5 +
 ...RangerTransactionSynchronizationAdapter.java | 130 +++++++++
 .../apache/ranger/db/RangerDaoManagerBase.java  |   7 +
 .../org/apache/ranger/db/XXPluginInfoDao.java   | 107 ++++++++
 .../org/apache/ranger/entity/XXPluginInfo.java  | 223 ++++++++++++++++
 .../java/org/apache/ranger/rest/AssetREST.java  |   2 +-
 .../org/apache/ranger/rest/PublicAPIsv2.java    |  17 ++
 .../org/apache/ranger/rest/ServiceREST.java     |  92 +++++--
 .../java/org/apache/ranger/rest/TagREST.java    |  55 +++-
 .../apache/ranger/rest/TagRESTConstants.java    |   1 +
 .../ranger/security/context/RangerAPIList.java  |   3 +
 .../security/context/RangerAPIMapping.java      |   2 +
 .../service/RangerPluginActivityLogger.java     |  68 +++++
 .../ranger/service/RangerPluginInfoService.java | 196 ++++++++++++++
 .../service/RangerTransactionService.java       | 105 ++++++++
 .../ranger/view/RangerPluginInfoList.java       |  72 +++++
 .../resources/META-INF/jpa_named_queries.xml    |  25 ++
 .../src/main/resources/META-INF/persistence.xml |   2 +
 .../org/apache/ranger/rest/TestServiceREST.java |   2 +-
 .../org/apache/ranger/rest/TestTagREST.java     |  31 ++-
 .../storm/RangerAdminClientImpl.java            |   4 +-
 41 files changed, 1771 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
index 5ae9854..6755e15 100644
--- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
+++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
@@ -30,13 +30,13 @@ import java.util.List;
 public interface RangerAdminClient {
 	void init(String serviceName, String appId, String configPropertyPrefix);
 
-	ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception;
+	ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception;
 
 	void grantAccess(GrantRevokeRequest request) throws Exception;
 
 	void revokeAccess(GrantRevokeRequest request) throws Exception;
 
-	ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception;
+	ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception;
 
 	List<String> getTagTypes(String tagTypePattern) throws Exception;
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
index 6ec44c4..646004a 100644
--- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
+++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
@@ -31,7 +31,11 @@ import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.ranger.admin.client.datatype.RESTResponse;
 import org.apache.ranger.audit.provider.MiscUtil;
 import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
-import org.apache.ranger.plugin.util.*;
+import org.apache.ranger.plugin.util.GrantRevokeRequest;
+import org.apache.ranger.plugin.util.RangerRESTClient;
+import org.apache.ranger.plugin.util.RangerRESTUtils;
+import org.apache.ranger.plugin.util.ServicePolicies;
+import org.apache.ranger.plugin.util.ServiceTags;
 
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -44,7 +48,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 	private String           serviceName = null;
 	private String           pluginId    = null;
 	private RangerRESTClient restClient  = null;
-	private RangerRESTUtils  restUtils   = new RangerRESTUtils();
+	private RangerRESTUtils restUtils   = new RangerRESTUtils();
 
 	public RangerAdminRESTClient() {
 	}
@@ -82,9 +86,9 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 	}
 
 	@Override
-	public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion) throws Exception {
+	public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ")");
+			LOG.debug("==> RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + ")");
 		}
 
 		ServicePolicies ret = null;
@@ -100,6 +104,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 				public ClientResponse run() {
 					WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName)
 												.queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion))
+												.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
 												.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
 					return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
 				};
@@ -111,6 +116,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 			}
 			WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName)
                                                                                 .queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion))
+                                                                                .queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
                                                                                 .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
 			response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
 		}
@@ -125,7 +131,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 		}
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + "): " + ret);
+			LOG.debug("<== RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): " + ret);
 		}
 
 		return ret;
@@ -243,9 +249,9 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 	}
 
 	@Override
-	public ServiceTags getServiceTagsIfUpdated(final long lastKnownVersion) throws Exception {
+	public ServiceTags getServiceTagsIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + "): ");
+			LOG.debug("==> RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): ");
 		}
 
 		ServiceTags ret = null;
@@ -259,6 +265,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 				public ClientResponse run() {
 					WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_GET_SECURE_SERVICE_TAGS_IF_UPDATED + serviceName)
 							.queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion))
+							.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
 							.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
 					return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
 				};
@@ -270,6 +277,7 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 		} else {
 			webResource = createWebResource(RangerRESTUtils.REST_URL_GET_SERVICE_TAGS_IF_UPDATED + serviceName)
 					.queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion))
+					.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
 					.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
 			response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
 		}
@@ -280,12 +288,13 @@ public class RangerAdminRESTClient implements RangerAdminClient {
 			RESTResponse resp = RESTResponse.fromClientResponse(response);
 			LOG.error("Error getting taggedResources. secureMode=" + isSecureMode + ", user=" + user
 					+ ", response=" + resp.toString() + ", serviceName=" + serviceName
-					+ ", " + "lastKnownVersion=" + lastKnownVersion);
+					+ ", " + "lastKnownVersion=" + lastKnownVersion
+					+ ", " + "lastActivationTimeInMillis=" + lastActivationTimeInMillis);
 			throw new Exception(resp.getMessage());
 		}
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + "): ");
+			LOG.debug("<== RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): ");
 		}
 
 		return ret;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java
index 7c5b378..9c336bf 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerAdminTagRetriever.java
@@ -48,13 +48,13 @@ public class RangerAdminTagRetriever extends RangerTagRetriever {
 	}
 
 	@Override
-	public ServiceTags retrieveTags(long lastKnownVersion) throws InterruptedException {
+	public ServiceTags retrieveTags(long lastKnownVersion, long lastActivationTimeInMillis) throws InterruptedException {
 
 		ServiceTags serviceTags = null;
 
 		if (adminClient != null) {
 			try {
-				serviceTags = adminClient.getServiceTagsIfUpdated(lastKnownVersion);
+				serviceTags = adminClient.getServiceTagsIfUpdated(lastKnownVersion, lastActivationTimeInMillis);
 			} catch (InterruptedException interruptedException) {
 				LOG.error("Tag-retriever thread was interrupted");
 				throw interruptedException;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java
index db4c6e4..248aafa 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerFileBasedTagRetriever.java
@@ -124,10 +124,10 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever {
 	}
 
 	@Override
-	public ServiceTags retrieveTags(long lastKnownVersion) throws InterruptedException {
+	public ServiceTags retrieveTags(long lastKnownVersion, long lastActivationTimeInMillis) throws InterruptedException {
 
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("==> retrieveTags(lastKnownVersion=" + lastKnownVersion + ", serviceTagsFilePath=" + serviceTagsFileName);
+			LOG.debug("==> retrieveTags(lastKnownVersion=" + lastKnownVersion + ", lastActivationTimeInMillis=" + lastActivationTimeInMillis + ", serviceTagsFilePath=" + serviceTagsFileName);
 		}
 
 		ServiceTags serviceTags = null;
@@ -152,7 +152,7 @@ public class RangerFileBasedTagRetriever extends RangerTagRetriever {
 		}
 
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== retrieveTags(lastKnownVersion=" + lastKnownVersion);
+			LOG.debug("<== retrieveTags(lastKnownVersion=" + lastKnownVersion + ", lastActivationTimeInMillis=" + lastActivationTimeInMillis);
 		}
 
 		return serviceTags;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
index 00e46ea..62e7c99 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagEnricher.java
@@ -357,6 +357,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 		private final RangerTagRetriever tagRetriever;
 		private final RangerTagEnricher tagEnricher;
 		private long lastKnownVersion = -1L;
+		private long lastActivationTimeInMillis = 0L;
 
 		private final long pollingIntervalMs;
 		private final String cacheFile;
@@ -381,6 +382,14 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			}
 		}
 
+		public long getLastActivationTimeInMillis() {
+			return lastActivationTimeInMillis;
+		}
+
+		public void setLastActivationTimeInMillis(long lastActivationTimeInMillis) {
+			this.lastActivationTimeInMillis = lastActivationTimeInMillis;
+		}
+
 		@Override
 		public void run() {
 
@@ -423,7 +432,7 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 			if (tagEnricher != null) {
 				ServiceTags serviceTags = null;
 
-				serviceTags = tagRetriever.retrieveTags(lastKnownVersion);
+				serviceTags = tagRetriever.retrieveTags(lastKnownVersion, lastActivationTimeInMillis);
 
 				if (serviceTags == null) {
 					if (!hasProvidedTagsToReceiver) {
@@ -435,9 +444,11 @@ public class RangerTagEnricher extends RangerAbstractContextEnricher {
 
 				if (serviceTags != null) {
 					tagEnricher.setServiceTags(serviceTags);
-					lastKnownVersion = serviceTags.getTagVersion() == null ? -1L : serviceTags.getTagVersion();
-					LOG.info("RangerTagRefresher.populateTags() - Updated tags-cache to new version of tags, lastKnownVersion=" + lastKnownVersion + "; newVersion=" + serviceTags.getTagVersion());
+					LOG.info("RangerTagRefresher.populateTags() - Updated tags-cache to new version of tags, lastKnownVersion=" + lastKnownVersion + "; newVersion="
+							+ (serviceTags.getTagVersion() == null ? -1L : serviceTags.getTagVersion()));
 					hasProvidedTagsToReceiver = true;
+					lastKnownVersion = serviceTags.getTagVersion() == null ? -1L : serviceTags.getTagVersion();
+					setLastActivationTimeInMillis(System.currentTimeMillis());
 				} else {
 					if (LOG.isDebugEnabled()) {
 						LOG.debug("RangerTagRefresher.populateTags() - No need to update tags-cache. lastKnownVersion=" + lastKnownVersion);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagFileStoreRetriever.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagFileStoreRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagFileStoreRetriever.java
index 1ee00d3..85cf420 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagFileStoreRetriever.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagFileStoreRetriever.java
@@ -47,12 +47,13 @@ public class RangerTagFileStoreRetriever extends RangerTagRetriever {
 	}
 
 	@Override
-	public ServiceTags retrieveTags(long lastKnownVersion) throws InterruptedException {
+	public ServiceTags retrieveTags(long lastKnownVersion, long lastActivationTimeInMillis) throws InterruptedException {
 
 		ServiceTags serviceTags = null;
 
 		if (tagStore != null) {
 			try {
+				// Ignore lastActivationTimeInMillis for TagFileStore
 				serviceTags = tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion);
 			} catch (InterruptedException interruptedException) {
 				LOG.error("Tag-retriever thread was interrupted");

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java
index 3ec1754..a5eeeaa 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerTagRetriever.java
@@ -32,7 +32,7 @@ public abstract class RangerTagRetriever {
 
 	public abstract void init(Map<String, String> options);
 
-	public abstract ServiceTags retrieveTags(long lastKnownVersion) throws InterruptedException;
+	public abstract ServiceTags retrieveTags(long lastKnownVersion, long lastActivationTimeInMillis) throws InterruptedException;
 
 	public String getServiceName() {
 		return serviceName;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
new file mode 100644
index 0000000..ee11c42
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
@@ -0,0 +1,261 @@
+/*
+ * 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.ranger.plugin.model;
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+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 java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerPluginInfo implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	public static final int ENTITY_TYPE_POLICIES = 0;
+	public static final int ENTITY_TYPE_TAGS     = 1;
+
+	public static final String PLUGIN_INFO_POLICY_DOWNLOAD_TIME      = "policyDownloadTime";
+	public static final String PLUGIN_INFO_POLICY_DOWNLOADED_VERSION = "policyDownloadedVersion";
+	public static final String PLUGIN_INFO_POLICY_ACTIVATION_TIME    = "policyActivationTime";
+	public static final String PLUGIN_INFO_POLICY_ACTIVE_VERSION     = "policyActiveVersion";
+	public static final String PLUGIN_INFO_TAG_DOWNLOAD_TIME         = "tagDownloadTime";
+	public static final String PLUGIN_INFO_TAG_DOWNLOADED_VERSION    = "tagDownloadedVersion";
+	public static final String PLUGIN_INFO_TAG_ACTIVATION_TIME       = "tagActivationTime";
+	public static final String PLUGIN_INFO_TAG_ACTIVE_VERSION        = "tagActiveVersion";
+
+	private Long    id         = null;
+	private Date    createTime = null;
+	private Date    updateTime = null;
+
+	private String serviceName;
+	private String hostName;
+	private String appType;
+	private String ipAddress;
+	private Map<String, String> info;
+
+	public RangerPluginInfo(Long id, Date createTime, Date updateTime, String serviceName, String appType, String hostName, String ipAddress, Map<String, String> info) {
+		super();
+
+		setId(id);
+		setCreateTime(createTime);
+		setUpdateTime(updateTime);
+		setServiceName(serviceName);
+		setAppType(appType);
+		setHostName(hostName);
+		setIpAddress(ipAddress);
+		setInfo(info);
+	}
+
+	public RangerPluginInfo() {
+		this(null, null, null, null, null, null, null, null);
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public String getServiceName() {
+		return serviceName;
+	}
+
+	public void setServiceName(String serviceName) {
+		this.serviceName = serviceName;
+	}
+
+	public String getHostName() {
+		return hostName;
+	}
+
+	public void setHostName(String hostName) {
+		this.hostName = hostName;
+	}
+
+	public String getAppType() {
+		return appType;
+	}
+
+	public void setAppType(String appType) {
+		this.appType = appType;
+	}
+
+	public String getIpAddress() {
+		return ipAddress;
+	}
+
+	public void setIpAddress(String ipAddress) {
+		this.ipAddress = ipAddress;
+	}
+
+	public Map<String, String> getInfo() {
+		return info;
+	}
+
+	public void setInfo(Map<String, String> info) {
+		this.info = info == null ? new HashMap<String, String>() : info;
+	}
+
+	@JsonIgnore
+	public void setPolicyDownloadTime(Long policyDownloadTime) {
+		getInfo().put(PLUGIN_INFO_POLICY_DOWNLOAD_TIME, policyDownloadTime == null ? null : Long.toString(policyDownloadTime));
+	}
+
+	@JsonIgnore
+	public Long getPolicyDownloadTime() {
+		String downloadTimeString = getInfo().get(PLUGIN_INFO_POLICY_DOWNLOAD_TIME);
+		return StringUtils.isNotBlank(downloadTimeString) ? Long.valueOf(downloadTimeString) : null;
+	}
+
+	@JsonIgnore
+	public void setPolicyDownloadedVersion(Long policyDownloadedVersion) {
+		getInfo().put(PLUGIN_INFO_POLICY_DOWNLOADED_VERSION, policyDownloadedVersion == null ? null : Long.toString(policyDownloadedVersion));
+	}
+
+	@JsonIgnore
+	public Long getPolicyDownloadedVersion() {
+		String downloadedVersionString = getInfo().get(PLUGIN_INFO_POLICY_DOWNLOADED_VERSION);
+		return StringUtils.isNotBlank(downloadedVersionString) ? Long.valueOf(downloadedVersionString) : null;
+	}
+
+	@JsonIgnore
+	public void setPolicyActivationTime(Long policyActivationTime) {
+		getInfo().put(PLUGIN_INFO_POLICY_ACTIVATION_TIME, policyActivationTime == null ? null : Long.toString(policyActivationTime));
+	}
+
+	@JsonIgnore
+	public Long getPolicyActivationTime() {
+		String activationTimeString = getInfo().get(PLUGIN_INFO_POLICY_ACTIVATION_TIME);
+		return StringUtils.isNotBlank(activationTimeString) ? Long.valueOf(activationTimeString) : null;
+	}
+
+	@JsonIgnore
+	public void setPolicyActiveVersion(Long policyActiveVersion) {
+		getInfo().put(PLUGIN_INFO_POLICY_ACTIVE_VERSION, policyActiveVersion == null ? null : Long.toString(policyActiveVersion));
+	}
+
+	@JsonIgnore
+	public Long getPolicyActiveVersion() {
+		String activeVersionString = getInfo().get(PLUGIN_INFO_POLICY_ACTIVE_VERSION);
+		return StringUtils.isNotBlank(activeVersionString) ? Long.valueOf(activeVersionString) : null;
+	}
+
+	@JsonIgnore
+	public void setTagDownloadTime(Long tagDownloadTime) {
+		getInfo().put(PLUGIN_INFO_TAG_DOWNLOAD_TIME, tagDownloadTime == null ? null : Long.toString(tagDownloadTime));
+	}
+
+	@JsonIgnore
+	public Long getTagDownloadTime() {
+		String downloadTimeString = getInfo().get(PLUGIN_INFO_TAG_DOWNLOAD_TIME);
+		return StringUtils.isNotBlank(downloadTimeString) ? Long.valueOf(downloadTimeString) : null;
+	}
+
+	@JsonIgnore
+	public void setTagDownloadedVersion(Long tagDownloadedVersion) {
+		getInfo().put(PLUGIN_INFO_TAG_DOWNLOADED_VERSION, tagDownloadedVersion == null ? null : Long.toString(tagDownloadedVersion));
+	}
+
+	@JsonIgnore
+	public Long getTagDownloadedVersion() {
+		String downloadedVersion = getInfo().get(PLUGIN_INFO_TAG_DOWNLOADED_VERSION);
+		return StringUtils.isNotBlank(downloadedVersion) ? Long.valueOf(downloadedVersion) : null;
+	}
+
+	@JsonIgnore
+	public void setTagActivationTime(Long tagActivationTime) {
+		getInfo().put(PLUGIN_INFO_TAG_ACTIVATION_TIME, tagActivationTime == null ? null : Long.toString(tagActivationTime));
+	}
+
+	@JsonIgnore
+	public Long getTagActivationTime() {
+		String activationTimeString = getInfo().get(PLUGIN_INFO_TAG_ACTIVATION_TIME);
+		return StringUtils.isNotBlank(activationTimeString) ? Long.valueOf(activationTimeString) : null;
+	}
+
+	@JsonIgnore
+	public void setTagActiveVersion(Long tagActiveVersion) {
+		getInfo().put(PLUGIN_INFO_TAG_ACTIVE_VERSION, tagActiveVersion == null ? null : Long.toString(tagActiveVersion));
+	}
+
+	@JsonIgnore
+	public Long getTagActiveVersion() {
+		String activeVersionString = getInfo().get(PLUGIN_INFO_TAG_ACTIVE_VERSION);
+		return StringUtils.isNotBlank(activeVersionString) ? Long.valueOf(activeVersionString) : null;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+
+		toString(sb);
+
+		return sb.toString();
+	}
+
+	public StringBuilder toString(StringBuilder sb) {
+		sb.append("RangerPluginInfo={");
+
+		sb.append("id={").append(id).append("} ");
+		sb.append("createTime={").append(createTime).append("} ");
+		sb.append("updateTime={").append(updateTime).append("} ");
+		sb.append("serviceName={").append(serviceName).append("} ");
+		sb.append("hostName={").append(hostName).append("} ");
+		sb.append("appType={").append(appType).append("} ");
+		sb.append("ipAddress={").append(ipAddress).append("} ");
+		sb.append("info={").append(info).append("} ");
+
+		sb.append(" }");
+
+		return sb;
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
index 014e866..91c24c6 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
@@ -49,7 +49,8 @@ public class PolicyRefresher extends Thread {
 	private final Gson              gson;
 
 	private long 	pollingIntervalMs   = 30 * 1000;
-	private long 	lastKnownVersion    = -1;
+	private long 	lastKnownVersion    = -1L;
+	private long	lastActivationTimeInMillis  = 0L;
 	private boolean policiesSetInPlugin = false;
 
 
@@ -130,6 +131,13 @@ public class PolicyRefresher extends Thread {
 		this.pollingIntervalMs = pollingIntervalMilliSeconds;
 	}
 
+	public long getLastActivationTimeInMillis() {
+		return lastActivationTimeInMillis;
+	}
+
+	public void setLastActivationTimeInMillis(long lastActivationTimeInMillis) {
+		this.lastActivationTimeInMillis = lastActivationTimeInMillis;
+	}
 
 	public void startRefresher() {
 
@@ -207,6 +215,8 @@ public class PolicyRefresher extends Thread {
 		if (svcPolicies != null) {
 			plugIn.setPolicies(svcPolicies);
 			policiesSetInPlugin = true;
+			setLastActivationTimeInMillis(System.currentTimeMillis());
+			lastKnownVersion = svcPolicies.getPolicyVersion();
 		}
 
 		if(LOG.isDebugEnabled()) {
@@ -229,7 +239,7 @@ public class PolicyRefresher extends Thread {
 		}
 
 		try {
-			svcPolicies = rangerAdmin.getServicePoliciesIfUpdated(lastKnownVersion);
+			svcPolicies = rangerAdmin.getServicePoliciesIfUpdated(lastKnownVersion, lastActivationTimeInMillis);
 
 			boolean isUpdated = svcPolicies != null;
 
@@ -244,8 +254,6 @@ public class PolicyRefresher extends Thread {
 
 				LOG.info("PolicyRefresher(serviceName=" + serviceName + "): found updated version. lastKnownVersion=" + lastKnownVersion + "; newVersion=" + newVersion);
 
-			   	lastKnownVersion = newVersion;
-
 			} else {
 				if(LOG.isDebugEnabled()) {
 					LOG.debug("PolicyRefresher(serviceName=" + serviceName + ").run(): no update found. lastKnownVersion=" + lastKnownVersion);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
index ed674ee..fa81f0b 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
@@ -56,6 +56,7 @@ public class RangerRESTUtils {
 	public static final String REST_MIME_TYPE_JSON     = "application/json";
 
 	public static final String REST_PARAM_LAST_KNOWN_POLICY_VERSION = "lastKnownVersion";
+	public static final String REST_PARAM_LAST_ACTIVATION_TIME = "lastActivationTime";
 	public static final String REST_PARAM_PLUGIN_ID                 = "pluginId";
 
 	private static final int MAX_PLUGIN_ID_LEN = 255;
@@ -130,4 +131,37 @@ public class RangerRESTUtils {
 
         return ret ;
     }
+
+    public String getHostnameFromPluginId(String pluginId, String serviceName) {
+    	String ret = "";
+
+    	if (StringUtils.isNotBlank(pluginId)) {
+			int lastIndex;
+			String[] parts = pluginId.split("@");
+			int index = parts.length > 1 ? 1 : 0;
+			if (StringUtils.isNotBlank(serviceName)) {
+				lastIndex = StringUtils.lastIndexOf(parts[index], serviceName);
+				if (lastIndex > 1) {
+					ret = parts[index].substring(0, lastIndex-1);
+				}
+			} else {
+				lastIndex = StringUtils.lastIndexOf(parts[index], "-");
+				if (lastIndex > 0) {
+					ret = parts[index].substring(0, lastIndex);
+				}
+			}
+		}
+
+		return ret;
+	}
+	public String getAppIdFromPluginId(String pluginId) {
+		String ret = "**Unknown**";
+
+		if (StringUtils.isNotBlank(pluginId)) {
+			String[] parts = pluginId.split("@");
+			ret = parts[0];
+		}
+
+		return ret;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
----------------------------------------------------------------------
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
index 49a48cd..73ea6e9 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
@@ -65,6 +65,12 @@ public class SearchFilter {
 	public static final String TAG_MAP_GUID              = "tagResourceMapGuid";  // search
 
 	public static final String SERVICE_NAME_PARTIAL      = "serviceNamePartial";
+
+	public static final String PLUGIN_HOST_NAME          = "pluginHostName";
+	public static final String PLUGIN_APP_TYPE           = "pluginAppType";
+	public static final String PLUGIN_ENTITY_TYPE        = "pluginEntityType";
+	public static final String PLUGIN_IP_ADDRESS         = "pluginIpAddress";
+
 	private Map<String, String> params     = null;
 	private int                 startIndex = 0;
 	private int                 maxRows    = Integer.MAX_VALUE;

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAdminClientImpl.java b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAdminClientImpl.java
index 3269fbb..e5c4113 100644
--- a/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAdminClientImpl.java
+++ b/hbase-agent/src/test/java/org/apache/ranger/authorization/hbase/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
         
     }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/hdfs-agent/src/test/java/org/apache/ranger/services/hdfs/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/hdfs-agent/src/test/java/org/apache/ranger/services/hdfs/RangerAdminClientImpl.java b/hdfs-agent/src/test/java/org/apache/ranger/services/hdfs/RangerAdminClientImpl.java
index 5c612e9..99d3f78 100644
--- a/hdfs-agent/src/test/java/org/apache/ranger/services/hdfs/RangerAdminClientImpl.java
+++ b/hdfs-agent/src/test/java/org/apache/ranger/services/hdfs/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
 
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
 
     }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/hive-agent/src/test/java/org/apache/ranger/services/hive/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/hive-agent/src/test/java/org/apache/ranger/services/hive/RangerAdminClientImpl.java b/hive-agent/src/test/java/org/apache/ranger/services/hive/RangerAdminClientImpl.java
index 43770c2..8b48dd8 100644
--- a/hive-agent/src/test/java/org/apache/ranger/services/hive/RangerAdminClientImpl.java
+++ b/hive-agent/src/test/java/org/apache/ranger/services/hive/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
 
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
 
     }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
----------------------------------------------------------------------
diff --git a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
index aeff332..6c0b3e9 100644
--- a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
+++ b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
@@ -91,9 +91,9 @@ public class RangerAdminJersey2RESTClient implements RangerAdminClient {
 	}
 
 	@Override
-	public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion) throws Exception {
+	public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerAdminJersey2RESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ")");
+			LOG.debug("==> RangerAdminJersey2RESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + ")");
 		}
 
 		UserGroupInformation user = MiscUtil.getUGILoginUser();
@@ -162,11 +162,11 @@ public class RangerAdminJersey2RESTClient implements RangerAdminClient {
 			}
 
 			if(LOG.isDebugEnabled()) {
-				LOG.debug("<== RangerAdminJersey2RESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + "): " + servicePolicies);
+				LOG.debug("<== RangerAdminJersey2RESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): " + servicePolicies);
 			}
 			return servicePolicies;
 		} catch (Exception ex) {
-			LOG.error("Failed getting policies from server. url=" + url + ", pluginId=" + _pluginId + ", lastKnownVersion=" + lastKnownVersion );
+			LOG.error("Failed getting policies from server. url=" + url + ", pluginId=" + _pluginId + ", lastKnownVersion=" + lastKnownVersion + ", " + lastActivationTimeInMillis);
 			throw ex;
 		}
 	}
@@ -242,7 +242,7 @@ public class RangerAdminJersey2RESTClient implements RangerAdminClient {
 	}
 
 	@Override
-	public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+	public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 		throw new Exception("RangerAdminjersey2RESTClient.getServiceTagsIfUpdated() -- *** NOT IMPLEMENTED *** ");
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/plugin-kafka/src/test/java/org/apache/ranger/authorization/kafka/authorizer/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/plugin-kafka/src/test/java/org/apache/ranger/authorization/kafka/authorizer/RangerAdminClientImpl.java b/plugin-kafka/src/test/java/org/apache/ranger/authorization/kafka/authorizer/RangerAdminClientImpl.java
index c08a6df..26dc151 100644
--- a/plugin-kafka/src/test/java/org/apache/ranger/authorization/kafka/authorizer/RangerAdminClientImpl.java
+++ b/plugin-kafka/src/test/java/org/apache/ranger/authorization/kafka/authorizer/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
         
     }

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
----------------------------------------------------------------------
diff --git a/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
index e889447..6196727 100644
--- a/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
+++ b/plugin-kms/src/test/java/org/apache/ranger/authorization/kms/authorizer/RangerAdminClientImpl.java
@@ -50,7 +50,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
         this.gson = gson;
     }
 
-    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception {
+    public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
 
         String basedir = System.getProperty("basedir");
         if (basedir == null) {
@@ -71,7 +71,7 @@ public class RangerAdminClientImpl implements RangerAdminClient {
 
     }
 
-    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception {
+    public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion, long lastActivationTimeInMillis) throws Exception {
         return null;
 
     }
@@ -81,4 +81,4 @@ public class RangerAdminClientImpl implements RangerAdminClient {
     }
 
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/db/mysql/patches/025-create-schema-for-plugin-info.sql
----------------------------------------------------------------------
diff --git a/security-admin/db/mysql/patches/025-create-schema-for-plugin-info.sql b/security-admin/db/mysql/patches/025-create-schema-for-plugin-info.sql
new file mode 100644
index 0000000..732f2cf
--- /dev/null
+++ b/security-admin/db/mysql/patches/025-create-schema-for-plugin-info.sql
@@ -0,0 +1,33 @@
+-- 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.
+
+DROP TABLE IF EXISTS `x_plugin_info`;
+
+
+CREATE TABLE x_plugin_info (
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NOT NULL,
+`update_time` datetime NOT NULL,
+`service_name` varchar(255) NOT  NULL,
+`app_type` varchar(128) NOT NULL,
+`host_name` varchar(64) NOT NULL,
+`ip_address` varchar(64) NOT NULL,
+`info` varchar(1024) NOT NULL,
+ PRIMARY KEY (`id`),
+ CREATE UNIQUE INDEX x_plugin_info_IDX_unique ON x_plugin_info(service_name, host_name, app_type),
+ CREATE INDEX x_plugin_info_IDX_service_name ON x_plugin_info(service_name),
+ CREATE INDEX x_plugin_info_IDX_host_name ON x_plugin_info(host_name)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/db/postgres/patches/025-create-schema-for-plugin-info.sql
----------------------------------------------------------------------
diff --git a/security-admin/db/postgres/patches/025-create-schema-for-plugin-info.sql b/security-admin/db/postgres/patches/025-create-schema-for-plugin-info.sql
new file mode 100644
index 0000000..1b12915
--- /dev/null
+++ b/security-admin/db/postgres/patches/025-create-schema-for-plugin-info.sql
@@ -0,0 +1,35 @@
+-- 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.
+
+DROP TABLE IF EXISTS x_plugin_info;
+DROP SEQUENCE IF EXISTS x_plugin_info_seq;
+
+CREATE SEQUENCE x_plugin_info_seq;
+
+CREATE TABLE x_plugin_info (
+id BIGINT DEFAULT nextval('x_plugin_info_seq'::regclass),
+create_time TIMESTAMP NOT NULL,
+update_time TIMESTAMP NOT NULL,
+service_name varchar(255) NOT NULL,
+app_type varchar(128) NOT NULL,
+host_name varchar(64) NOT NULL,
+ip_address varchar(64) NOT NULL,
+info varchar(1024) NOT NULL,
+primary key (id)
+);
+CREATE UNIQUE INDEX x_plugin_info_IDX_unique ON x_plugin_info(service_name, host_name, app_type);
+CREATE INDEX x_plugin_info_IDX_service_name ON x_plugin_info(service_name);
+CREATE INDEX x_plugin_info_IDX_host_name ON x_plugin_info(host_name);
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
index 931356e..3df1aba 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
@@ -23,6 +23,7 @@ import java.io.File;
 import java.io.IOException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -32,8 +33,10 @@ import java.util.Set;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.ranger.common.AppConstants;
 import org.apache.ranger.common.DateUtil;
@@ -45,10 +48,15 @@ import org.apache.ranger.common.SearchCriteria;
 import org.apache.ranger.common.StringUtil;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.XXPermMap;
+import org.apache.ranger.entity.XXPluginInfo;
 import org.apache.ranger.entity.XXPolicyExportAudit;
 import org.apache.ranger.entity.XXPortalUser;
 import org.apache.ranger.entity.XXTrxLog;
 import org.apache.ranger.entity.XXUser;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
+import org.apache.ranger.plugin.util.RangerRESTUtils;
+import org.apache.ranger.service.RangerPluginActivityLogger;
+import org.apache.ranger.service.RangerPluginInfoService;
 import org.apache.ranger.service.XAccessAuditService;
 import org.apache.ranger.service.XAuditMapService;
 import org.apache.ranger.service.XGroupService;
@@ -58,25 +66,26 @@ import org.apache.ranger.service.XTrxLogService;
 import org.apache.ranger.service.XUserService;
 import org.apache.ranger.solr.SolrAccessAuditsService;
 import org.apache.ranger.util.RestUtil;
-import org.apache.ranger.view.*;
+import org.apache.ranger.view.VXAccessAuditList;
+import org.apache.ranger.view.VXAsset;
+import org.apache.ranger.view.VXAuditMap;
+import org.apache.ranger.view.VXPermMap;
+import org.apache.ranger.view.VXPolicyExportAuditList;
+import org.apache.ranger.view.VXResource;
+import org.apache.ranger.view.VXTrxLog;
+import org.apache.ranger.view.VXTrxLogList;
+import org.apache.ranger.view.VXUser;
 import org.codehaus.jackson.JsonGenerationException;
 import org.codehaus.jackson.map.JsonMappingException;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.PlatformTransactionManager;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.TransactionCallback;
-import org.springframework.transaction.support.TransactionTemplate;
 
 @Component
 public class AssetMgr extends AssetMgrBase {
-	
-	
+
 	@Autowired
 	XPermMapService xPermMapService;
-	
+
 	@Autowired
 	XAuditMapService xAuditMapService;
 
@@ -114,14 +123,15 @@ public class AssetMgr extends AssetMgrBase {
 	SolrAccessAuditsService solrAccessAuditsService;
 
 	@Autowired
-	@Qualifier(value = "transactionManager")
-	PlatformTransactionManager txManager;
-	
-	@Autowired
 	XPolicyService xPolicyService;
-	
-	static Logger logger = Logger.getLogger(AssetMgr.class);
 
+	@Autowired
+	RangerPluginActivityLogger activityLogger;
+
+	@Autowired
+	RangerPluginInfoService pluginInfoService;
+
+	static Logger logger = Logger.getLogger(AssetMgr.class);
 
 	public File getXResourceFile(Long id, String fileType) {
 		VXResource xResource = xResourceService.readResource(id);
@@ -171,8 +181,8 @@ public class AssetMgr extends AssetMgrBase {
 	}
 
 	public String getLatestRepoPolicy(VXAsset xAsset, List<VXResource> xResourceList, Long updatedTime,
-			X509Certificate[] certchain, boolean httpEnabled, String epoch,
-			String ipAddress, boolean isSecure, String count, String agentId) {
+									  X509Certificate[] certchain, boolean httpEnabled, String epoch,
+									  String ipAddress, boolean isSecure, String count, String agentId) {
 		if(xAsset==null){
 			logger.error("Requested repository not found");
 			throw restErrorUtil.createRESTException("No Data Found.",
@@ -631,26 +641,193 @@ public class AssetMgr extends AssetMgrBase {
 
 	public XXPolicyExportAudit createPolicyAudit(
 			final XXPolicyExportAudit xXPolicyExportAudit) {
-		TransactionTemplate txTemplate = new TransactionTemplate(txManager);
-		txTemplate
-				.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
-		XXPolicyExportAudit policyExportAudit = (XXPolicyExportAudit) txTemplate
-				.execute(new TransactionCallback<Object>() {
-					public Object doInTransaction(TransactionStatus status) {
-						if (xXPolicyExportAudit.getHttpRetCode() == HttpServletResponse.SC_NOT_MODIFIED) {
-							boolean logNotModified = PropertiesUtil.getBooleanProperty("ranger.log.SC_NOT_MODIFIED", false);
-							if (!logNotModified) {
-								logger.debug("Not logging HttpServletResponse."
-										+ "SC_NOT_MODIFIED, to enable, update "
-										+ ": ranger.log.SC_NOT_MODIFIED");
-								return null;
-							}
+
+		XXPolicyExportAudit ret = null;
+		if (xXPolicyExportAudit.getHttpRetCode() == HttpServletResponse.SC_NOT_MODIFIED) {
+			boolean logNotModified = PropertiesUtil.getBooleanProperty("ranger.log.SC_NOT_MODIFIED", false);
+			if (!logNotModified) {
+				logger.debug("Not logging HttpServletResponse."
+						+ "SC_NOT_MODIFIED, to enable, update "
+						+ ": ranger.log.SC_NOT_MODIFIED");
+			} else {
+				// Create PolicyExportAudit record after transaction is completed. If it is created in-line here
+				// then the TransactionManager will roll-back the changes because the HTTP return code is
+				// HttpServletResponse.SC_NOT_MODIFIED
+				Runnable commitWork = new Runnable() {
+					@Override
+					public void run() {
+						rangerDaoManager.getXXPolicyExportAudit().create(xXPolicyExportAudit);
+
+					}
+				};
+				activityLogger.commitAfterTransactionComplete(commitWork);
+			}
+		} else {
+			ret = rangerDaoManager.getXXPolicyExportAudit().create(xXPolicyExportAudit);
+		}
+
+		return ret;
+	}
+
+	public void createPluginInfo(String serviceName, String pluginId, HttpServletRequest request, int entityType, long downloadedVersion, long lastKnownVersion, long lastActivationTime, int httpCode) {
+		RangerRESTUtils restUtils = new RangerRESTUtils();
+
+		final String ipAddress = request != null ? request.getRemoteAddr() : null;
+		final String appType = restUtils.getAppIdFromPluginId(pluginId);
+
+		String tmpHostName = null;
+		if (StringUtils.isNotBlank(pluginId)) {
+			tmpHostName = restUtils.getHostnameFromPluginId(pluginId, serviceName);
+		}
+		if (StringUtils.isBlank(tmpHostName) && request != null) {
+			tmpHostName = request.getRemoteHost();
+		}
+
+		final String hostName = (StringUtils.isBlank(tmpHostName)) ? ipAddress : tmpHostName;
+
+		RangerPluginInfo pluginSvcVersionInfo = new RangerPluginInfo();
+
+		pluginSvcVersionInfo.setServiceName(serviceName);
+		pluginSvcVersionInfo.setAppType(appType);
+		pluginSvcVersionInfo.setHostName(hostName);
+		pluginSvcVersionInfo.setIpAddress(ipAddress);
+
+		if (entityType == RangerPluginInfo.ENTITY_TYPE_POLICIES) {
+			pluginSvcVersionInfo.setPolicyActiveVersion(lastKnownVersion);
+			pluginSvcVersionInfo.setPolicyActivationTime(lastActivationTime);
+			pluginSvcVersionInfo.setPolicyDownloadedVersion(downloadedVersion);
+			pluginSvcVersionInfo.setPolicyDownloadTime(new Date().getTime());
+		} else {
+			pluginSvcVersionInfo.setTagActiveVersion(lastKnownVersion);
+			pluginSvcVersionInfo.setTagActivationTime(lastActivationTime);
+			pluginSvcVersionInfo.setTagDownloadedVersion(downloadedVersion);
+			pluginSvcVersionInfo.setTagDownloadTime(new Date().getTime());
+		}
+
+		createOrUpdatePluginInfo(pluginSvcVersionInfo, httpCode);
+	}
+
+	void createOrUpdatePluginInfo(final RangerPluginInfo pluginInfo, final int httpCode) {
+		if (logger.isDebugEnabled()) {
+			logger.debug("==> createOrUpdatePluginInfo(pluginInfo=" + pluginInfo + ", httpCode=" + httpCode + ")");
+		}
+
+		if (httpCode == HttpServletResponse.SC_NOT_MODIFIED) {
+			// Create or update PluginInfo record after transaction is completed. If it is created in-line here
+			// then the TransactionManager will roll-back the changes because the HTTP return code is
+			// HttpServletResponse.SC_NOT_MODIFIED
+			Runnable commitWork = new Runnable() {
+				@Override
+				public void run() {
+					doCreateOrUpdateXXPluginInfo(pluginInfo);
+				}
+			};
+			activityLogger.commitAfterTransactionComplete(commitWork);
+		} else {
+			doCreateOrUpdateXXPluginInfo(pluginInfo);
+		}
+		if (logger.isDebugEnabled()) {
+			logger.debug("<== createOrUpdatePluginInfo(pluginInfo=" + pluginInfo + ", httpCode=" + httpCode + ")");
+		}
+
+	}
+
+	XXPluginInfo doCreateOrUpdateXXPluginInfo(RangerPluginInfo pluginInfo) {
+		XXPluginInfo ret = null;
+
+		if (StringUtils.isNotBlank(pluginInfo.getServiceName())) {
+
+			boolean isPolicyInfo = pluginInfo.getPolicyDownloadedVersion() != null;
+
+			// If the ranger-admin is restarted, plugin contains latest version and there is no row for this pluginInfo
+			if (isPolicyInfo) {
+				if (pluginInfo.getPolicyDownloadedVersion().equals(pluginInfo.getPolicyActiveVersion())) {
+					// This is our best guess of when policies may have been downloaded
+					pluginInfo.setPolicyDownloadTime(pluginInfo.getPolicyActivationTime());
+				}
+			} else {
+				if (pluginInfo.getTagDownloadedVersion().equals(pluginInfo.getTagActiveVersion())) {
+					// This is our best guess of when tags may have been downloaded
+					pluginInfo.setTagDownloadTime(pluginInfo.getTagActivationTime());
+				}
+			}
+
+			XXPluginInfo xObj = rangerDaoManager.getXXPluginInfo().find(pluginInfo.getServiceName(),
+					pluginInfo.getHostName(), pluginInfo.getAppType());
+
+			if (xObj == null) {
+				xObj = pluginInfoService.populateDBObject(pluginInfo);
+
+				if (logger.isDebugEnabled()) {
+					logger.debug("Creating RangerPluginInfo record for service-version");
+				}
+				ret = rangerDaoManager.getXXPluginInfo().create(xObj);
+			} else {
+				boolean needsUpdating = false;
+
+				RangerPluginInfo dbObj = pluginInfoService.populateViewObject(xObj);
+				if (!dbObj.getIpAddress().equals(pluginInfo.getIpAddress())) {
+					dbObj.setIpAddress(pluginInfo.getIpAddress());
+					needsUpdating = true;
+				}
+				if (isPolicyInfo) {
+					if (dbObj.getPolicyDownloadedVersion() == null || !dbObj.getPolicyDownloadedVersion().equals(pluginInfo.getPolicyDownloadedVersion())) {
+						dbObj.setPolicyDownloadedVersion(pluginInfo.getPolicyDownloadedVersion());
+						dbObj.setPolicyDownloadTime(pluginInfo.getPolicyDownloadTime());
+						needsUpdating = true;
+					}
+					long lastKnownPolicyVersion = pluginInfo.getPolicyActiveVersion();
+					long lastPolicyActivationTime = pluginInfo.getPolicyActivationTime();
+
+					if (lastKnownPolicyVersion > 0 && (dbObj.getPolicyActiveVersion() == null || !dbObj.getPolicyActiveVersion().equals(lastKnownPolicyVersion))) {
+						dbObj.setPolicyActiveVersion(lastKnownPolicyVersion);
+						if (lastPolicyActivationTime > 0) {
+							dbObj.setPolicyActivationTime(lastPolicyActivationTime);
+						}
+						needsUpdating = true;
+					} else if (lastKnownPolicyVersion == -1) {
+						dbObj.setPolicyDownloadTime(pluginInfo.getPolicyDownloadTime());
+						dbObj.setPolicyActiveVersion(null);
+						dbObj.setPolicyActivationTime(null);
+						needsUpdating = true;
+					}
+				} else {
+					if (dbObj.getTagDownloadedVersion() == null || !dbObj.getTagDownloadedVersion().equals(pluginInfo.getTagDownloadedVersion())) {
+						dbObj.setTagDownloadedVersion(pluginInfo.getTagDownloadedVersion());
+						dbObj.setTagDownloadTime(pluginInfo.getTagDownloadTime());
+						needsUpdating = true;
+					}
+					long lastKnownTagVersion = pluginInfo.getTagActiveVersion();
+					long lastTagActivationTime = pluginInfo.getTagActivationTime();
+
+					if (lastKnownTagVersion > 0 && (dbObj.getTagActiveVersion() == null || !dbObj.getTagActiveVersion().equals(lastKnownTagVersion))) {
+						dbObj.setTagActiveVersion(lastKnownTagVersion);
+						if (lastTagActivationTime > 0) {
+							dbObj.setTagActivationTime(lastTagActivationTime);
 						}
-						return rangerDaoManager.getXXPolicyExportAudit().create(
-								xXPolicyExportAudit);
+						needsUpdating = true;
+					} else if (lastKnownTagVersion == -1) {
+						dbObj.setTagDownloadTime(pluginInfo.getTagDownloadTime());
+						dbObj.setTagActiveVersion(null);
+						dbObj.setTagActivationTime(null);
+						needsUpdating = true;
 					}
-				});
-		return policyExportAudit;
+				}
+
+				if (needsUpdating) {
+					if (logger.isDebugEnabled()) {
+						logger.debug("Updating XXPluginInfo record for service-version");
+					}
+					xObj = pluginInfoService.populateDBObject(dbObj);
+
+					ret = rangerDaoManager.getXXPluginInfo().update(xObj);
+				}
+			}
+		} else {
+			logger.error("Invalid parameters: pluginInfo=" + pluginInfo + ")");
+		}
+
+		return ret;
 	}
 
 	public VXTrxLogList getReportLogs(SearchCriteria searchCriteria) {
@@ -665,17 +842,17 @@ public class AssetMgr extends AssetMgrBase {
 		if (searchCriteria.getParamList() != null
 				&& searchCriteria.getParamList().size() > 0) {
 			int clientTimeOffsetInMinute = RestUtil.getClientTimeOffset();
-			java.util.Date temp = null;
+			Date temp = null;
 			DateUtil dateUtil = new DateUtil();
 			if (searchCriteria.getParamList().containsKey("startDate")) {
-				temp = (java.util.Date) searchCriteria.getParamList().get(
+				temp = (Date) searchCriteria.getParamList().get(
 						"startDate");
 				temp = dateUtil.getDateFromGivenDate(temp, 0, 0, 0, 0);
 				temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);
 				searchCriteria.getParamList().put("startDate", temp);
 			}
 			if (searchCriteria.getParamList().containsKey("endDate")) {
-				temp = (java.util.Date) searchCriteria.getParamList().get(
+				temp = (Date) searchCriteria.getParamList().get(
 						"endDate");
 				temp = dateUtil.getDateFromGivenDate(temp, 0, 23, 59, 59);
 				temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);
@@ -713,17 +890,17 @@ public class AssetMgr extends AssetMgrBase {
         if (searchCriteria.getParamList() != null
                 && searchCriteria.getParamList().size() > 0) {
             int clientTimeOffsetInMinute = RestUtil.getClientTimeOffset();
-            java.util.Date temp = null;
+            Date temp = null;
             DateUtil dateUtil = new DateUtil();
             if (searchCriteria.getParamList().containsKey("startDate")) {
-                temp = (java.util.Date) searchCriteria.getParamList().get(
+                temp = (Date) searchCriteria.getParamList().get(
                         "startDate");
                 temp = dateUtil.getDateFromGivenDate(temp, 0, 0, 0, 0);
                 temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);
                 searchCriteria.getParamList().put("startDate", temp);
             }
             if (searchCriteria.getParamList().containsKey("endDate")) {
-                temp = (java.util.Date) searchCriteria.getParamList().get(
+                temp = (Date) searchCriteria.getParamList().get(
                         "endDate");
                 temp = dateUtil.getDateFromGivenDate(temp, 0, 23, 59, 59);
                 temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);
@@ -828,17 +1005,17 @@ public class AssetMgr extends AssetMgrBase {
                 && searchCriteria.getParamList().size() > 0) {
 
             int clientTimeOffsetInMinute = RestUtil.getClientTimeOffset();
-            java.util.Date temp = null;
+            Date temp = null;
             DateUtil dateUtil = new DateUtil();
             if (searchCriteria.getParamList().containsKey("startDate")) {
-                temp = (java.util.Date) searchCriteria.getParamList().get(
+                temp = (Date) searchCriteria.getParamList().get(
                         "startDate");
                 temp = dateUtil.getDateFromGivenDate(temp, 0, 0, 0, 0);
                 temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);
                 searchCriteria.getParamList().put("startDate", temp);
             }
             if (searchCriteria.getParamList().containsKey("endDate")) {
-                temp = (java.util.Date) searchCriteria.getParamList().get(
+                temp = (Date) searchCriteria.getParamList().get(
                         "endDate");
                 temp = dateUtil.getDateFromGivenDate(temp, 0, 23, 59, 59);
                 temp = dateUtil.addTimeOffset(temp, clientTimeOffsetInMinute);

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java b/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
index 2d049a4..4fb52a4 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RangerSearchUtil.java
@@ -67,6 +67,11 @@ public class RangerSearchUtil extends SearchUtil {
 		ret.setParam(SearchFilter.RESOURCE_SIGNATURE, request.getParameter(SearchFilter.RESOURCE_SIGNATURE));
 		ret.setParam(SearchFilter.POLICY_TYPE, request.getParameter(SearchFilter.POLICY_TYPE));
 
+		ret.setParam(SearchFilter.PLUGIN_HOST_NAME, request.getParameter(SearchFilter.PLUGIN_HOST_NAME));
+		ret.setParam(SearchFilter.PLUGIN_APP_TYPE, request.getParameter(SearchFilter.PLUGIN_APP_TYPE));
+		ret.setParam(SearchFilter.PLUGIN_ENTITY_TYPE, request.getParameter(SearchFilter.PLUGIN_ENTITY_TYPE));
+		ret.setParam(SearchFilter.PLUGIN_IP_ADDRESS, request.getParameter(SearchFilter.PLUGIN_IP_ADDRESS));
+
 		for (Map.Entry<String, String[]> e : request.getParameterMap().entrySet()) {
 			String name = e.getKey();
 			String[] values = e.getValue();

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/common/db/RangerTransactionSynchronizationAdapter.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/common/db/RangerTransactionSynchronizationAdapter.java b/security-admin/src/main/java/org/apache/ranger/common/db/RangerTransactionSynchronizationAdapter.java
new file mode 100644
index 0000000..2a62fb4
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/common/db/RangerTransactionSynchronizationAdapter.java
@@ -0,0 +1,130 @@
+/*
+ * 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.ranger.common.db;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+@Component
+public class RangerTransactionSynchronizationAdapter extends TransactionSynchronizationAdapter {
+
+    @Autowired
+    @Qualifier(value = "transactionManager")
+    PlatformTransactionManager txManager;
+
+    private static final Log LOG = LogFactory.getLog(RangerTransactionSynchronizationAdapter.class);
+
+    private static final ThreadLocal<List<Runnable>> RUNNABLES = new ThreadLocal<List<Runnable>>();
+
+    public void executeOnTransactionCompletion(Runnable runnable) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Submitting new runnable {" + runnable + "} to run after completion");
+        }
+
+        /*
+        From TransactionSynchronizationManager documentation:
+        TransactionSynchronizationManager is a central helper that manages resources and transaction synchronizations per thread.
+        Resource management code should only register synchronizations when this manager is active,
+        which can be checked via isSynchronizationActive(); it should perform immediate resource cleanup else.
+        If transaction synchronization isn't active, there is either no current transaction,
+        or the transaction manager doesn't support transaction synchronization.
+
+        Note: Synchronization is an Interface for transaction synchronization callbacks which is implemented by
+        TransactionSynchronizationAdapter
+        */
+
+        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+            LOG.info("Transaction synchronization is NOT ACTIVE. Executing right now runnable {" + runnable + "}");
+            runnable.run();
+            return;
+        }
+        List<Runnable> threadRunnables = RUNNABLES.get();
+        if (threadRunnables == null) {
+            threadRunnables = new ArrayList<Runnable>();
+            RUNNABLES.set(threadRunnables);
+            // Register a new transaction synchronization for the current thread.
+            // TransactionSynchronizationManage will call afterCompletion() when current transaction completes.
+            TransactionSynchronizationManager.registerSynchronization(this);
+        }
+        threadRunnables.add(runnable);
+    }
+
+    @Override
+    public void afterCompletion(int status) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Transaction completed with status {" + (status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK") + "}");
+        }
+        /* Thread runnables are expected to be executed only when the status is STATUS_ROLLED_BACK. Currently, executeOnTransactionCompletion()
+         * is called only for those changes that are going to be rolled-back by TransactionSynchronizationManager - such
+         * as when the operation returns HttpServletResponse.SC_NOT_MODIFIED status.
+         */
+        //if (status == STATUS_ROLLED_BACK) {
+            final List<Runnable> threadRunnables = RUNNABLES.get();
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Transaction completed, executing {" + threadRunnables.size() + "} runnables");
+            }
+            if (threadRunnables != null) {
+                try {
+                    //Create new  transaction
+                    TransactionTemplate txTemplate = new TransactionTemplate(txManager);
+                    txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+
+                    txTemplate.execute(new TransactionCallback<Object>() {
+                        public Object doInTransaction(TransactionStatus status) {
+                            for (Runnable runnable : threadRunnables) {
+                                if (LOG.isDebugEnabled()) {
+                                    LOG.debug("Executing runnable {" + runnable + "}");
+                                }
+                                try {
+                                    runnable.run();
+                                } catch (RuntimeException e) {
+                                    LOG.error("Failed to execute runnable " + runnable, e);
+                                    break;
+                                }
+                            }
+
+                            return null;
+                        }
+                    });
+                } catch (Exception e) {
+                    LOG.error("Failed to commit TransactionService transaction", e);
+                    LOG.error("Ignoring...");
+                }
+            }
+
+        //}
+        RUNNABLES.remove();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java b/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
index 6cd5c9f..15331ae 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
@@ -363,6 +363,9 @@ public abstract class RangerDaoManagerBase {
 		if (className.equals("XXServiceVersionInfo")) {
 			return getXXServiceVersionInfo();
 		}
+		if (className.equals("XXPluginInfo")) {
+			return getXXPluginInfo();
+		}
 		logger.error("No DaoManager found for className=" + className, new Throwable());
 		return null;
 	}
@@ -583,5 +586,9 @@ public abstract class RangerDaoManagerBase {
 	public XXServiceVersionInfoDao getXXServiceVersionInfo() {
 		return new XXServiceVersionInfoDao(this);
 	}
+
+	public XXPluginInfoDao getXXPluginInfo() {
+		return new XXPluginInfoDao(this);
+	}
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/db/XXPluginInfoDao.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPluginInfoDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPluginInfoDao.java
new file mode 100644
index 0000000..8eb1636
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXPluginInfoDao.java
@@ -0,0 +1,107 @@
+/*
+ * 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.ranger.db;
+
+import java.util.List;
+
+import javax.persistence.NoResultException;
+
+import org.apache.ranger.common.DateUtil;
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXPluginInfo;
+
+/**
+ */
+
+public class XXPluginInfoDao extends BaseDao<XXPluginInfo> {
+	/**
+	 * Default Constructor
+	 */
+	public XXPluginInfoDao(RangerDaoManagerBase daoManager) {
+		super(daoManager);
+	}
+
+	@Override
+	public XXPluginInfo create(XXPluginInfo obj) {
+		obj.setCreateTime(DateUtil.getUTCDate());
+		obj.setUpdateTime(DateUtil.getUTCDate());
+		return super.create(obj);
+	}
+
+	@Override
+	public XXPluginInfo update(XXPluginInfo obj) {
+		obj.setUpdateTime(DateUtil.getUTCDate());
+		return super.update(obj);
+	}
+	public XXPluginInfo find(String serviceName, String hostName, String appType) {
+		if (serviceName == null || hostName == null || appType == null) {
+			return null;
+		}
+		try {
+			return getEntityManager()
+					.createNamedQuery("XXPluginInfo.find", tClass)
+					.setParameter("serviceName", serviceName)
+					.setParameter("appType", appType)
+					.setParameter("hostName", hostName)
+					.getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+	public List<XXPluginInfo> findByServiceName(String serviceName) {
+		if (serviceName == null) {
+			return null;
+		}
+		try {
+			return getEntityManager()
+					.createNamedQuery("XXPluginInfo.findByServiceName", tClass)
+					.setParameter("serviceName", serviceName).getResultList();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+
+	public List<XXPluginInfo> findByServiceId(Long serviceId) {
+		if (serviceId == null) {
+			return null;
+		}
+		try {
+			return getEntityManager()
+					.createNamedQuery("XXPluginInfo.findByServiceId", tClass)
+					.setParameter("serviceId", serviceId).getResultList();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+
+	public List<XXPluginInfo> findByServiceAndHostName(String serviceName, String hostName) {
+		if (serviceName == null || hostName == null) {
+			return null;
+		}
+		try {
+			return getEntityManager()
+					.createNamedQuery("XXPluginInfo.findByServiceAndHostName", tClass)
+					.setParameter("serviceName", serviceName)
+					.setParameter("hostName", hostName)
+					.getResultList();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/entity/XXPluginInfo.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXPluginInfo.java b/security-admin/src/main/java/org/apache/ranger/entity/XXPluginInfo.java
new file mode 100644
index 0000000..2196cdf
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXPluginInfo.java
@@ -0,0 +1,223 @@
+/*
+ * 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.ranger.entity;
+
+import java.util.Date;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.ranger.common.AppConstants;
+
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name = "x_plugin_info")
+public class XXPluginInfo implements java.io.Serializable {
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@SequenceGenerator(name = "X_PLUGIN_INFO_SEQ", sequenceName = "X_PLUGIN_INFO_SEQ", allocationSize = 1)
+	@GeneratedValue(strategy = GenerationType.AUTO, generator = "X_PLUGIN_INFO_SEQ")
+	@Column(name = "id")
+	protected Long id;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="CREATE_TIME"   )
+	protected Date createTime;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="UPDATE_TIME"   )
+	protected Date updateTime;
+
+	@Column(name = "service_name")
+	protected String serviceName;
+
+	@Column(name = "app_type")
+	protected String appType;
+
+	@Column(name = "host_name")
+	protected String hostName;
+
+	@Column(name = "ip_address")
+	protected String ipAddress;
+
+	@Column(name = "info")
+	protected String info;
+
+	/**
+	 * Default constructor. This will set all the attributes to default value.
+	 */
+	public XXPluginInfo( ) {
+	}
+
+	public int getMyClassType( ) {
+	    return AppConstants.CLASS_TYPE_NONE;
+	}
+
+	public String getMyDisplayValue() {
+		return null;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getId() {
+		return this.id;
+	}
+
+	public void setCreateTime( Date createTime ) {
+		this.createTime = createTime;
+	}
+
+	public Date getCreateTime( ) {
+		return this.createTime;
+	}
+
+	public void setUpdateTime( Date updateTime ) {
+		this.updateTime = updateTime;
+	}
+
+	public Date getUpdateTime( ) {
+		return this.updateTime;
+	}
+
+	public void setServiceName(String serviceName) {
+		this.serviceName = serviceName;
+	}
+
+	public String getServiceName() {
+		return this.serviceName;
+	}
+
+	public void setAppType(String appType) {
+		this.appType = appType;
+	}
+
+	public String getAppType() {
+		return this.appType;
+	}
+
+	public void setHostName(String hostName) {
+		this.hostName = hostName;
+	}
+
+	public String getHostName() {
+		return this.hostName;
+	}
+
+	public void setIpAddress(String ipAddress) {
+		this.ipAddress = ipAddress;
+	}
+
+	public String getIpAddress() {
+		return this.ipAddress;
+	}
+
+	public void setInfo(String info) {
+		this.info = info;
+	}
+
+	public String getInfo() {
+		return this.info;
+	}
+
+	/**
+	 * This return the bean content in string format
+	 * @return formatedStr
+	*/
+	@Override
+	public String toString( ) {
+		String str = "XXPluginInfo={";
+		str += "id={" + id + "} ";
+		str += "createTime={" + createTime + "} ";
+		str += "updateTime={" + updateTime + "} ";
+		str += "serviceName={" + serviceName + "} ";
+		str += "hostName={" + hostName + "} ";
+		str += "appType={" + appType + "} ";
+		str += "ipAddress={" + ipAddress + "} ";
+		str += "info={" + info + "} ";
+		str += "}";
+		return str;
+	}
+
+	/**
+	 * Checks for all attributes except referenced db objects
+	 * @return true if all attributes match
+	*/
+	@Override
+	public boolean equals( Object obj) {
+		if (obj == null)
+			return false;
+		if (this == obj)
+			return true;
+		if (!super.equals(obj))
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		XXPluginInfo other = (XXPluginInfo) obj;
+		if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
+			return false;
+		}
+		if ((this.createTime == null && other.createTime != null) || (this.createTime != null && !this.createTime.equals(other.createTime))) {
+			return false;
+		}
+		if ((this.updateTime == null && other.updateTime != null) || (this.updateTime != null && !this.updateTime.equals(other.updateTime))) {
+			return false;
+		}
+		if ((this.serviceName == null && other.serviceName != null) || (this.serviceName != null && !this.serviceName.equals(other.serviceName))) {
+			return false;
+		}
+		if ((this.hostName == null && other.hostName != null) || (this.hostName != null && !this.hostName.equals(other.hostName))) {
+			return false;
+		}
+		if ((this.appType == null && other.appType != null) || (this.appType != null && !this.appType.equals(other.appType))) {
+			return false;
+		}
+		if ((this.ipAddress == null && other.ipAddress != null) || (this.ipAddress != null && !this.ipAddress.equals(other.ipAddress))) {
+			return false;
+		}
+		if ((this.info == null && other.info != null) || (this.info != null && !this.info.equals(other.info))) {
+			return false;
+		}
+		return true;
+	}
+
+	public static boolean equals(Object object1, Object object2) {
+		if (object1 == object2) {
+			return true;
+		}
+		if ((object1 == null) || (object2 == null)) {
+			return false;
+		}
+		return object1.equals(object2);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/rest/AssetREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/AssetREST.java b/security-admin/src/main/java/org/apache/ranger/rest/AssetREST.java
index 3d2997b..52c141b 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/AssetREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/AssetREST.java
@@ -535,7 +535,7 @@ public class AssetREST {
 		ServicePolicies servicePolicies = null;
 
 		try {
-			servicePolicies = serviceREST.getServicePoliciesIfUpdated(repository, lastKnowPolicyVersion, agentId, request);
+			servicePolicies = serviceREST.getServicePoliciesIfUpdated(repository, lastKnowPolicyVersion, 0L, agentId, request);
 		} catch(Exception excp) {
 			logger.error("failed to retrieve policies for repository " + repository, excp);
 		}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/f4a20e0b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
index e2a6435..81d6001 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
@@ -23,10 +23,12 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.common.annotation.RangerAnnotationJSMgrName;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.util.SearchFilter;
+import org.apache.ranger.view.RangerPluginInfoList;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -432,4 +434,19 @@ public class PublicAPIsv2 {
 			logger.debug("<== PublicAPIsv2.deletePolicyByName(" + serviceName + "," + policyName + ")");
 		}
 	}
+
+	@GET
+	@Path("/api/plugins/info")
+	public List<RangerPluginInfo> getPluginsInfo(@Context HttpServletRequest request) {
+		if (logger.isDebugEnabled()) {
+			logger.debug("==> PublicAPIsv2.getPluginsInfo()");
+		}
+
+		RangerPluginInfoList pluginInfoList = serviceREST.getPluginsInfo(request);
+
+		if (logger.isDebugEnabled()) {
+			logger.debug("<== PublicAPIsv2.getPluginsInfo()");
+		}
+		return pluginInfoList.getPluginInfoList();
+	}
 }