http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java
 
b/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java
new file mode 100755
index 0000000..e57a36b
--- /dev/null
+++ 
b/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java
@@ -0,0 +1,1529 @@
+/*
+ *                        AT&T - PROPRIETARY
+ *          THIS FILE CONTAINS PROPRIETARY INFORMATION OF
+ *        AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN
+ *             ACCORDANCE WITH APPLICABLE AGREEMENTS.
+ *
+ *          Copyright (c) 2013 AT&T Knowledge Ventures
+ *              Unpublished and Not for Publication
+ *                     All Rights Reserved
+ */
+package com.att.research.xacml.rest;
+
+
+import com.att.research.xacml.api.pap.*;
+import com.att.research.xacml.std.pap.StdPDP;
+import com.att.research.xacml.std.pap.StdPDPGroup;
+import 
com.att.research.xacml.std.pap.StdPDPItemSetChangeNotifier.StdItemSetChangeListener;
+import com.att.research.xacml.std.pap.StdPDPStatus;
+import com.att.research.xacml.util.FactoryException;
+import com.att.research.xacml.util.XACMLProperties;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Splitter;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebInitParam;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Servlet implementation class XacmlPapServlet
+ * 
+ * 
+ * @author pameladragosh
+ */
+@WebServlet(
+               description = "Implements the XACML PAP RESTful API.", 
+               urlPatterns = { "/" }, 
+               loadOnStartup=1,
+               initParams = {
+                               @WebInitParam(name = "XACML_PROPERTIES_NAME", 
value = "xacml.pap.properties", description = "The location of the properties 
file holding configuration information.")
+               })
+
+public class XACMLPapServlet extends HttpServlet implements 
StdItemSetChangeListener, Runnable {
+       private static final long serialVersionUID = 1L;
+       private static final Log logger = 
LogFactory.getLog(XACMLPapServlet.class);
+       
+       /*
+        * 
+        * papEngine - This is our engine workhorse that manages the PDP Groups 
and Nodes.
+        */
+       private PAPEngine papEngine = null;
+       
+       /*
+        * This PAP instance's own URL.
+        * 
+        * Need this when creating URLs to send to the PDPs so they can GET the 
Policy files from this process. 
+        */
+       private static String papURL = null;
+       
+       /*
+        * List of Admin Console URLs.
+        * Used to send notifications when configuration changes.
+        * 
+        * The CopyOnWriteArrayList *should* protect from concurrency errors.
+        * This list is seldom changed but often read, so the costs of this 
approach make sense.
+        */
+       private static final CopyOnWriteArrayList<String> 
adminConsoleURLStringList = new CopyOnWriteArrayList<String>();
+       
+       /*
+        * This thread may be invoked upon startup to initiate sending PDP 
policy/pip configuration when
+        * this servlet starts. Its configurable by the admin.
+        */
+       private Thread initiateThread = null;
+       
+       /*
+       // The heartbeat thread.
+       */
+       private static Heartbeat heartbeat = null;
+       private static Thread heartbeatThread = null;
+       
+    /**
+     * @see HttpServlet#HttpServlet()
+     */
+    public XACMLPapServlet() {
+        super();
+    }
+
+       /**
+        * @see Servlet#init(ServletConfig)
+        */
+       public void init(ServletConfig config) throws ServletException {
+               try {
+                       //
+                       // Initialize
+                       //
+                       XACMLRest.xacmlInit(config);
+                       //
+                       // Load the properties
+                       //
+                       XACMLRest.loadXacmlProperties(null, null);
+                       //
+                       // Load our PAP engine, first create a factory
+                       //
+                       PAPEngineFactory factory = 
PAPEngineFactory.newInstance(XACMLProperties.getProperty(XACMLProperties.PROP_PAP_PAPENGINEFACTORY));
+                       //
+                       // The factory knows how to go about creating a PAP 
Engine
+                       //
+                       this.papEngine = factory.newEngine();                   
+                       //
+                       // we are about to call the PDPs and give them their 
configuration.
+                       // To do that we need to have the URL of this PAP so we 
can construct the Policy file URLs
+                       //
+                       XACMLPapServlet.papURL = 
XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL);
+                       //
+                       // Sanity check that a URL was defined somewhere, its 
essential.
+                       //
+                       // How to check that its valid? We can validate the 
form, but since we are in the init() method we
+                       // are not fully loaded yet so we really couldn't ping 
ourself to see if the URL will work. One
+                       // will have to look for errors in the PDP logs to 
determine if they are failing to initiate a
+                       // request to this servlet.
+                       //
+                       if (XACMLPapServlet.papURL == null) {
+                               throw new PAPException("The property " + 
XACMLRestProperties.PROP_PAP_URL + " is not valid: " + XACMLPapServlet.papURL);
+                       }
+                       //
+                       // Configurable - have the PAP servlet initiate sending 
the latest PDP policy/pip configuration
+                       // to all its known PDP nodes.
+                       //
+                       // Note: parseBoolean will return false if there is no 
property defined. This is fine for a default.
+                       //
+                       if 
(Boolean.parseBoolean(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_INITIATE_PDP_CONFIG)))
 {
+                               this.initiateThread = new Thread(this);
+                               this.initiateThread.start();
+                       }
+                       //
+                       // After startup, the PAP does Heartbeats to each of 
the PDPs periodically
+                       //
+                       XACMLPapServlet.heartbeat = new 
Heartbeat(this.papEngine);
+                       XACMLPapServlet.heartbeatThread = new 
Thread(XACMLPapServlet.heartbeat);
+                       XACMLPapServlet.heartbeatThread.start();
+               } catch (FactoryException | PAPException e) {
+                       logger.error("Failed to create engine", e);
+                       throw new ServletException ("PAP not initialized; 
error: "+e);
+               } catch (Exception e) {
+                       logger.error("Failed to create engine - unexpected 
error: ", e);
+                       throw new ServletException ("PAP not initialized; 
unexpected error: "+e);               }
+       }
+
+       /**
+        * Thread used only during PAP startup to initiate change messages to 
all known PDPs.
+        * This must be on a separate thread so that any GET requests from the 
PDPs during this update can be serviced.
+        */
+       @Override
+       public void run() {
+               //
+               // send the current configuration to all the PDPs that we know 
about
+               //
+               changed();
+       }
+       
+
+       /**
+        * @see Servlet#destroy()
+        * 
+        * Depending on how this servlet is run, we may or may not care about 
cleaning up the resources.
+        * For now we assume that we do care.
+        */
+       public void destroy() {
+               //
+               // Make sure our threads are destroyed
+               //
+               if (XACMLPapServlet.heartbeatThread != null) {
+                       //
+                       // stop the heartbeat
+                       //
+                       try {
+                               if (XACMLPapServlet.heartbeat != null) {
+                                       XACMLPapServlet.heartbeat.terminate();
+                               }
+                               XACMLPapServlet.heartbeatThread.interrupt();
+                               XACMLPapServlet.heartbeatThread.join();
+                       } catch (InterruptedException e) {
+                               logger.error(e);
+                       }
+               }
+               if (this.initiateThread != null) {
+                       try {
+                               this.initiateThread.interrupt();
+                               this.initiateThread.join();
+                       } catch (InterruptedException e) {
+                               logger.error(e);
+                       }
+               }
+       }
+       
+       /**
+        * 
+        * Called by:
+        *      - PDP nodes to register themselves with the PAP, and
+        *      - Admin Console to make changes in the PDP Groups.
+        * 
+        * @see HttpServlet#doPost(HttpServletRequest request, 
HttpServletResponse response)
+        */
+       protected void doPost(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
+               try {
+
+                       XACMLRest.dumpRequest(request);
+
+                       // since getParameter reads the content string, 
explicitly get the content before doing that.
+                       // Simply getting the inputStream seems to protect it 
against being consumed by getParameter.
+                       request.getInputStream();
+                       
+                       //
+                       // Is this from the Admin Console?
+                       //
+                       String groupId = request.getParameter("groupId");
+                       if (groupId != null) {
+                               //
+                               // this is from the Admin Console, so handle 
separately
+                               //
+                               doACPost(request, response, groupId);
+                               return;
+                       }
+                       
+                       //
+                       //  Request is from a PDP.
+                       //      It is coming up and asking for its config
+                       //
+                       
+                       //
+                       // Get the PDP's ID
+                       //
+                       String id = this.getPDPID(request);
+                       logger.info("doPost from: " + id);
+                       //
+                       // Get the PDP Object
+                       //
+                       PDP pdp = this.papEngine.getPDP(id);
+                       //
+                       // Is it known?
+                       //
+                       if (pdp == null) {
+                               logger.info("Unknown PDP: " + id);
+                               try {
+                                       this.papEngine.newPDP(id, 
this.papEngine.getDefaultGroup(), id, "Registered on first startup");
+                               } catch (NullPointerException | PAPException e) 
{
+                                       logger.error("Failed to create new 
PDP", e);
+                                       
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
e.getMessage());
+                                       return;
+                               }
+                               // get the PDP we just created
+                               pdp = this.papEngine.getPDP(id);
+                               if (pdp == null) {
+                                       String message = "Failed to create new 
PDP for id: " + id;
+                                       logger.error(message);
+                                       
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
+                                       return;
+                               }
+                       }
+                       //
+                       // Get the PDP's Group
+                       //
+                       PDPGroup group = this.papEngine.getPDPGroup(pdp);
+                       if (group == null) {
+                               
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "PDP not associated 
with any group, even the default");
+                               return;
+                       }
+                       //
+                       // Determine what group the PDP node is in and get
+                       // its policy/pip properties.
+                       //
+                       Properties policies = group.getPolicyProperties();
+                       Properties pipconfig = group.getPipConfigProperties();
+                       //
+                       // Get the current policy/pip configuration that the 
PDP has
+                       //
+                       Properties pdpProperties = new Properties();
+                       pdpProperties.load(request.getInputStream());
+                       logger.info("PDP Current Properties: " + 
pdpProperties.toString());
+                       logger.info("Policies: " + (policies != null ? 
policies.toString() : "null"));
+                       logger.info("Pip config: " + (pipconfig != null ? 
pipconfig.toString() : "null"));
+                       //
+                       // Validate the node's properties
+                       //
+                       boolean isCurrent = this.isPDPCurrent(policies, 
pipconfig, pdpProperties);
+                       //
+                       // Send back current configuration
+                       //
+                       if (isCurrent == false) {
+                               //
+                               // Tell the PDP we are sending back the current 
policies/pip config
+                               //
+                               logger.info("PDP configuration NOT current.");
+                               if (policies != null) {
+                                       //
+                                       // Put URL's into the properties in 
case the PDP needs to
+                                       // retrieve them.
+                                       //
+                                       
this.populatePolicyURL(request.getRequestURL(), policies);
+                                       //
+                                       // Copy the properties to the output 
stream
+                                       //
+                                       
policies.store(response.getOutputStream(), "");
+                               }
+                               if (pipconfig != null) {
+                                       //
+                                       // Copy the properties to the output 
stream
+                                       //
+                                       
pipconfig.store(response.getOutputStream(), "");
+                               }
+                               //
+                               // We are good - and we are sending them 
information
+                               //
+                               response.setStatus(HttpServletResponse.SC_OK);
+//TODO - Correct?                              
+                               setPDPSummaryStatus(pdp, 
PDPStatus.Status.OUT_OF_SYNCH);
+                       } else {
+                               //
+                               // Tell them they are good
+                               //
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               
+ //TODO - Correct?
+                               setPDPSummaryStatus(pdp, 
PDPStatus.Status.UP_TO_DATE);
+
+                       }
+                       //
+                       // tell the AC that something changed
+                       //
+                       notifyAC();
+               } catch (PAPException e) {
+                       logger.debug("POST exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+       }
+
+       
+       /**
+        * @see HttpServlet#doGet(HttpServletRequest request, 
HttpServletResponse response)
+        */
+       protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
+               try {
+                       XACMLRest.dumpRequest(request);
+                       
+                       // Is this from the Admin Console?
+                       String groupId = request.getParameter("groupId");
+                       if (groupId != null) {
+                               // this is from the Admin Console, so handle 
separately
+                               doACGet(request, response, groupId);
+                               return;
+                       }
+                       //
+                       // Get the PDP's ID
+                       //
+                       String id = this.getPDPID(request);
+                       logger.info("doGet from: " + id);
+                       //
+                       // Get the PDP Object
+                       //
+                       PDP pdp = this.papEngine.getPDP(id);
+                       //
+                       // Is it known?
+                       //
+                       if (pdp == null) {
+                               //
+                               // Check if request came from localhost
+                               //
+                               String message = "Unknown PDP: " + id + " from 
" + request.getRemoteHost() + " us: " + request.getLocalAddr();
+                               logger.info(message);
+                               if (request.getRemoteHost().equals("localhost") 
||
+                                       
request.getRemoteHost().equals("127.0.0.1") ||
+                                       
request.getRemoteHost().equals(request.getLocalAddr())) {
+                                       //
+                                       // Return status information - 
basically all the groups
+                                       //
+                                       Set<PDPGroup> groups = 
papEngine.getPDPGroups();
+                                       
+                                       // convert response object to JSON and 
include in the response
+                           ObjectMapper mapper = new ObjectMapper();
+                           mapper.writeValue(response.getOutputStream(),  
groups);
+                                       response.setHeader("content-type", 
"application/json");
+                                       
response.setStatus(HttpServletResponse.SC_OK);
+                                       return;
+                               }
+                               
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message);
+                               return;
+                       }
+                       //
+                       // Get the PDP's Group
+                       //
+                       PDPGroup group = this.papEngine.getPDPGroup(pdp);
+                       if (group == null) {
+                               String message = "No group associated with pdp 
" + pdp.getId();
+                               logger.warn(message);
+                               
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message);
+                               return;
+                       }
+                       //
+                       // Which policy do they want?
+                       //
+                       String policyId = request.getParameter("id");
+                       if (policyId == null) {
+                               String message = "Did not specify an id for the 
policy";
+                               logger.warn(message);
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+                               return;
+                       }
+                       PDPPolicy policy = group.getPolicy(policyId);
+                       if (policy == null) {
+                               String message = "Unknown policy: " + policyId;
+                               logger.warn(message);
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+                               return;
+                       }
+                       //
+                       // Get its stream
+                       //
+                       try (InputStream is = policy.getStream(); OutputStream 
os = response.getOutputStream()) {
+                               //
+                               // Send the policy back
+                               //
+                               IOUtils.copy(is, os);
+                               
+                               response.setStatus(HttpServletResponse.SC_OK);
+                       } catch (PAPException e) {
+                               String message = "Failed to open policy id " + 
policyId;
+                               logger.error(message);
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+                       }
+               }  catch (PAPException e) {
+                       logger.error("GET exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+       }
+
+       protected String        getPDPID(HttpServletRequest request) {
+               String pdpURL = 
request.getHeader(XACMLRestProperties.PROP_PDP_HTTP_HEADER_ID);
+               if (pdpURL == null || pdpURL.isEmpty()) {
+                       //
+                       // Should send back its port for identification
+                       //
+                       logger.warn("PDP did not send custom header");
+                       pdpURL = "";
+               }
+               return  pdpURL;
+       }
+       
+       private boolean isPDPCurrent(Properties policies, Properties pipconfig, 
Properties pdpProperties) {
+               String localRootPolicies = 
policies.getProperty(XACMLProperties.PROP_ROOTPOLICIES);
+               String localReferencedPolicies = 
policies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES);
+               if (localRootPolicies == null || localReferencedPolicies == 
null) {
+                       logger.warn("Missing property on PAP server: 
RootPolicies="+localRootPolicies+"  
ReferencedPolicies="+localReferencedPolicies);
+                       return false;
+               }
+               //
+               // Compare the policies and pipconfig properties to the 
pdpProperties
+               //
+               try {
+                       //
+                       // the policy properties includes only 
xacml.rootPolicies and 
+                       // xacml.referencedPolicies without any .url entries
+                       //
+                       Properties pdpPolicies = 
XACMLProperties.getPolicyProperties(pdpProperties, false);
+                       Properties pdpPipConfig = 
XACMLProperties.getPipProperties(pdpProperties);
+                       if 
(localRootPolicies.equals(pdpPolicies.getProperty(XACMLProperties.PROP_ROOTPOLICIES))
 &&
+                                       
localReferencedPolicies.equals(pdpPolicies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES))
 &&
+                                       pdpPipConfig.equals(pipconfig)) {
+                               //
+                               // The PDP is current
+                               //
+                               return true;
+                       }
+               } catch (Exception e) {
+                       // we get here if the PDP did not include either 
xacml.rootPolicies or xacml.pip.engines,
+                       // or if there are policies that do not have a 
corresponding ".url" property.
+                       // Either of these cases means that the PDP is not 
up-to-date, so just drop-through to return false.
+               }
+               return false;
+       }
+
+       private void populatePolicyURL(StringBuffer urlPath, Properties 
policies) {
+               String lists[] = new String[2];
+               lists[0] = 
policies.getProperty(XACMLProperties.PROP_ROOTPOLICIES);
+               lists[1] = 
policies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES);
+               for (String list : lists) {
+                       if (list != null && list.isEmpty() == false) {
+                               for (String id : 
Splitter.on(',').trimResults().omitEmptyStrings().split(list)) {
+                                       String url = urlPath + "?id=" + id;
+                                       logger.info("Policy URL for " + id + ": 
" + url);
+                                       policies.setProperty(id + ".url", url);
+                               }
+                       }
+               }
+       }
+       
+       
+       /**
+        * @see HttpServlet#doPut(HttpServletRequest request, 
HttpServletResponse response)
+        */
+       protected void doPut(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
+               XACMLRest.dumpRequest(request);
+               //
+               // since getParameter reads the content string, explicitly get 
the content before doing that.
+               // Simply getting the inputStream seems to protect it against 
being consumed by getParameter.
+               //
+               request.getInputStream();
+               //
+               // See if this is Admin Console registering itself with us
+               //
+               String acURLString = request.getParameter("adminConsoleURL");
+               if (acURLString != null) {
+                       //
+                       // remember this Admin Console for future updates
+                       //
+                       if ( ! adminConsoleURLStringList.contains(acURLString)) 
{
+                               adminConsoleURLStringList.add(acURLString);
+                       }
+                       if (logger.isDebugEnabled()) {
+                               logger.debug("Admin Console registering with 
URL: " + acURLString);
+                       }
+                       response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                       return;
+               }
+               //
+               // Is this some other operation from the Admin Console?
+               //
+               String groupId = request.getParameter("groupId");
+               if (groupId != null) {
+                       //
+                       // this is from the Admin Console, so handle separately
+                       //
+                       doACPut(request, response, groupId);
+                       return;
+               }
+               //
+               // We do not expect anything from anywhere else.
+               // This method is here in case we ever need to support other 
operations.
+               //
+               response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request 
does not have groupId");
+       }
+       
+       /**
+        * @see HttpServlet#doDelete(HttpServletRequest request, 
HttpServletResponse response)
+        */
+       protected void doDelete(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
+               XACMLRest.dumpRequest(request);
+               //
+               // Is this from the Admin Console?
+               //
+               String groupId = request.getParameter("groupId");
+               if (groupId != null) {
+                       //
+                       // this is from the Admin Console, so handle separately
+                       //
+                       doACDelete(request, response, groupId);
+                       return;
+               }
+               //
+               // We do not expect anything from anywhere else.
+               // This method is here in case we ever need to support other 
operations.
+               //
+               response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request 
does not have groupId");
+       }
+       //
+       // Admin Console request handling
+       //
+       
+       /**
+        * Requests from the Admin Console to GET info about the Groups and PDPs
+        * 
+        * @param request
+        * @param response
+        * @param groupId
+        * @throws ServletException
+        * @throws java.io.IOException
+        */
+       private void doACGet(HttpServletRequest request, HttpServletResponse 
response, String groupId) throws ServletException, IOException {
+               try {
+                       String parameterDefault = 
request.getParameter("default");
+                       String pdpId = request.getParameter("pdpId");
+                       String pdpGroup = request.getParameter("getPDPGroup");
+                       if ("".equals(groupId)) {
+                               // request IS from AC but does not identify a 
group by name
+                               if (parameterDefault != null) {
+                                       // Request is for the Default group 
(whatever its id)
+                                       PDPGroup group = 
papEngine.getDefaultGroup();
+                                       
+                                       // convert response object to JSON and 
include in the response
+                           ObjectMapper mapper = new ObjectMapper();
+                           mapper.writeValue(response.getOutputStream(),  
group);
+                           
+                                       if (logger.isDebugEnabled()) {
+                                               logger.debug("GET Default group 
req from '" + request.getRequestURL() + "'");
+                                       }
+                                       
response.setStatus(HttpServletResponse.SC_OK);
+                                       response.setHeader("content-type", 
"application/json");
+                                       response.getOutputStream().close();
+                                       return;
+                                       
+                               } else if (pdpId != null) {
+                                       // Request is related to a PDP
+                                       if (pdpGroup == null) {
+                                               // Request is for the PDP itself
+                                               // Request is for the 
(unspecified) group containing a given PDP
+                                               PDP pdp = 
papEngine.getPDP(pdpId);
+                                               
+                                               // convert response object to 
JSON and include in the response
+                                   ObjectMapper mapper = new ObjectMapper();
+                                   
mapper.writeValue(response.getOutputStream(),  pdp);
+                                   
+                                               if (logger.isDebugEnabled()) {
+                                                       logger.debug("GET pdp 
'" + pdpId + "' req from '" + request.getRequestURL() + "'");
+                                               }
+                                               
response.setStatus(HttpServletResponse.SC_OK);
+                                               
response.setHeader("content-type", "application/json");
+                                               
response.getOutputStream().close();
+                                               return;
+                                       
+                                       } else {
+                                               // Request is for the 
(unspecified) group containing a given PDP
+                                               PDP pdp = 
papEngine.getPDP(pdpId);
+                                               PDPGroup group = 
papEngine.getPDPGroup(pdp);
+                                               
+                                               // convert response object to 
JSON and include in the response
+                                   ObjectMapper mapper = new ObjectMapper();
+                                   
mapper.writeValue(response.getOutputStream(),  group);
+                                   
+                                               if (logger.isDebugEnabled()) {
+                                                       logger.debug("GET PDP 
'" + pdpId + "' Group req from '" + request.getRequestURL() + "'");
+                                               }
+                                               
response.setStatus(HttpServletResponse.SC_OK);
+                                               
response.setHeader("content-type", "application/json");
+                                               
response.getOutputStream().close();
+                                               return;
+                                       }
+                                       
+                               } else {
+                                       // request is for top-level properties 
about all groups
+                                       Set<PDPGroup> groups = 
papEngine.getPDPGroups();
+                                       
+                                       // convert response object to JSON and 
include in the response
+                           ObjectMapper mapper = new ObjectMapper();
+                           mapper.writeValue(response.getOutputStream(),  
groups);
+                                       
+//TODO
+// In "notification" section, ALSO need to tell AC about other changes (made 
by other ACs)?'
+//TODO add new PDP notification (or just "config changed" notification) in 
appropriate place
+                           if (logger.isDebugEnabled()) {
+                               logger.debug("GET All groups req");
+                           }
+                                       
response.setStatus(HttpServletResponse.SC_OK);
+                                       response.setHeader("content-type", 
"application/json");
+                                       response.getOutputStream().close();
+                                       return;
+                               }
+                       }
+                       
+                       // for all other GET operations the group must exist 
before the operation can be done
+                       PDPGroup group = papEngine.getGroup(groupId);
+                       if (group == null) {
+                               logger.error("Unknown groupId '" + groupId + 
"'");
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + 
groupId +"'");
+                               return;
+                       }
+                       
+                       
+                       // Figure out which request this is based on the 
parameters
+                       String policyId = request.getParameter("policyId");
+                       
+                       if (policyId != null) {
+//                             // retrieve a policy
+//                             PDPPolicy policy = 
papEngine.getPDPPolicy(policyId);
+//                             
+//                             // convert response object to JSON and include 
in the response
+//                 ObjectMapper mapper = new ObjectMapper();
+//                 mapper.writeValue(response.getOutputStream(),  pdp);
+//                 
+//                     logger.debug("GET group '" + group.getId() + "' req 
from '" + request.getRequestURL() + "'");
+//                             response.setStatus(HttpServletResponse.SC_OK);
+//                             response.setHeader("content-type", 
"application/json");
+//                             response.getOutputStream().close();
+//                             return;
+                               
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "GET Policy not 
implemented");
+                               
+                       } else {
+                               // No other parameters, so return the 
identified Group
+                               
+                               // convert response object to JSON and include 
in the response
+                   ObjectMapper mapper = new ObjectMapper();
+                   mapper.writeValue(response.getOutputStream(),  group);
+                   
+                   if (logger.isDebugEnabled()) {
+                       logger.debug("GET group '" + group.getId() + "' req 
from '" + request.getRequestURL() + "'");
+                   }
+                               response.setStatus(HttpServletResponse.SC_OK);
+                               response.setHeader("content-type", 
"application/json");
+                               response.getOutputStream().close();
+                               return;
+                       }
+                       
+                       //
+                       // Currently there are no other GET calls from the AC.
+                       // The AC uses the "GET All Groups" operation to fill 
its local cache and uses that cache for all other GETs without calling the PAP.
+                       // Other GETs that could be called:
+                       //                              Specific Group  
(groupId=<groupId>)
+                       //                              A Policy                
(groupId=<groupId> policyId=<policyId>)
+                       //                              A PDP                   
(groupId=<groupId> pdpId=<pdpId>)
+               
+       //TODO - implement other GET operations if needed
+       
+                       logger.error("UNIMPLEMENTED ");
+                       response.sendError(HttpServletResponse.SC_BAD_REQUEST, 
"UNIMPLEMENTED");
+               } catch (PAPException e) {
+                       logger.error("AC Get exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+               
+       }
+
+               
+       /**
+        * Requests from the Admin Console for operations not on single 
specific objects
+        * 
+        * @param request
+        * @param response
+        * @param groupId
+        * @throws ServletException
+        * @throws java.io.IOException
+        */
+       private void doACPost(HttpServletRequest request, HttpServletResponse 
response, String groupId) throws ServletException, IOException {
+               try {
+                       String groupName = request.getParameter("groupName");
+                       String groupDescription = 
request.getParameter("groupDescription");
+                       if (groupName != null && groupDescription != null) {
+                               // Args:              group=<groupId> 
groupName=<name> groupDescription=<description>            <= create a new group
+                               String unescapedName = 
URLDecoder.decode(groupName, "UTF-8");
+                               String unescapedDescription = 
URLDecoder.decode(groupDescription, "UTF-8");
+                               try {
+                                       papEngine.newGroup(unescapedName, 
unescapedDescription);
+                               } catch (Exception e) {
+                                       logger.error("Unable to create new 
group: " + e.getLocalizedMessage());
+                                       response.sendError(500, "Unable to 
create new group '" + groupId + "'");
+                                       return;
+                               }
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("New Group '" + groupId + 
"' created");
+                               }
+                               // tell the Admin Consoles there is a change
+                               notifyAC();
+                               // new group by definition has no PDPs, so no 
need to notify them of changes
+                               return;
+                       }
+                       
+                       // for all remaining POST operations the group must 
exist before the operation can be done
+                       PDPGroup group = papEngine.getGroup(groupId);
+                       if (group == null) {
+                               logger.error("Unknown groupId '" + groupId + 
"'");
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + 
groupId +"'");
+                               return;
+                       }
+                       
+                       // determine the operation needed based on the 
parameters in the request
+                       if (request.getParameter("policyId") != null) {
+                               //      Args:        group=<groupId> 
policy=<policyId>          <= copy file
+                               // copy a policy from the request contents into 
a file in the group's directory on this machine
+                               String policyId = 
request.getParameter("policyId");
+                               try {
+                                       ((StdPDPGroup) 
group).copyPolicyToFile(policyId, request.getInputStream());
+                               } catch (Exception e) {
+                                       String message = "Policy '" + policyId 
+ "' not copied to group '" + groupId +"': " + e;
+                                       logger.error(message);
+                                       response.sendError(500, message);
+                                       return;
+                               }
+                               // policy file copied ok
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("policy '" + policyId + "' 
copied to directory for group '" + groupId + "'");
+                               }
+                               return;
+                               
+                       } else if (request.getParameter("default") != null) {
+                               // Args:       group=<groupId> default=true     
          <= make default
+                               // change the current default group to be the 
one identified in the request.
+                               //
+                               // This is a POST operation rather than a PUT 
"update group" because of the side-effect that the current default group is 
also changed.
+                               // It should never be the case that multiple 
groups are currently marked as the default, but protect against that anyway.
+                               try {
+                                       papEngine.SetDefaultGroup(group);
+                               } catch (Exception e) {
+                                       logger.error("Unable to set group: " + 
e.getLocalizedMessage());
+                                       response.sendError(500, "Unable to set 
group '" + groupId + "' to default");
+                                       return;
+                               }
+                               
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("Group '" + groupId + "' 
set to be default");
+                               }
+                               // Notify the Admin Consoles that something 
changed
+                               // For now the AC cannot handle anything more 
detailed than the whole set of PDPGroups, so just notify on that
+//TODO - Future: FIGURE OUT WHAT LEVEL TO NOTIFY: 2 groups or entire set - 
currently notify AC to update whole configuration of all groups
+                               notifyAC();
+                               // This does not affect any PDPs in the 
existing groups, so no need to notify them of this change
+                               return;
+                               
+                       } else if (request.getParameter("pdpId") != null) {
+                               // Args:       group=<groupId> pdpId=<pdpId>    
           <= move PDP to group
+                               String pdpId = request.getParameter("pdpId");
+                               PDP pdp = papEngine.getPDP(pdpId);
+                               
+                               PDPGroup originalGroup = 
papEngine.getPDPGroup(pdp);
+                               
+                               papEngine.movePDP(pdp, group);
+                               
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("PDP '" + pdp.getId() +"' 
moved to group '" + group.getId() + "' set to be default");
+                               }
+                               
+                               // update the status of both the original group 
and the new one
+                               ((StdPDPGroup)originalGroup).resetStatus();
+                               ((StdPDPGroup)group).resetStatus();
+                               
+                               // Notify the Admin Consoles that something 
changed
+                               // For now the AC cannot handle anything more 
detailed than the whole set of PDPGroups, so just notify on that
+                               notifyAC();
+                               // Need to notify the PDP that it's config may 
have changed
+                               pdpChanged(pdp);
+                               return;
+                               
+                               
+                       }
+               } catch (PAPException e) {
+                       logger.error("AC POST exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+       }
+
+       /**
+        * Requests from the Admin Console to create new items or update 
existing ones
+        * 
+        * @param request
+        * @param response
+        * @param groupId
+        * @throws ServletException
+        * @throws java.io.IOException
+        */
+       private void doACPut(HttpServletRequest request, HttpServletResponse 
response, String groupId) throws ServletException, IOException {
+               try {
+                       
+                       
+                       // for PUT operations the group may or may not need to 
exist before the operation can be done
+                       PDPGroup group = papEngine.getGroup(groupId);
+       
+                       // determine the operation needed based on the 
parameters in the request
+
+                       // for remaining operations the group must exist before 
the operation can be done
+                       if (group == null) {
+                               logger.error("Unknown groupId '" + groupId + 
"'");
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + 
groupId +"'");
+                               return;
+                       }
+                       if (request.getParameter("policy") != null) {
+       //        group=<groupId> policy=<policyId> contents=policy file        
       <= Create new policy file in group dir, or replace it if it already 
exists (do not touch properties)
+       //TODO - currently this is done by the AC, but it should be done here 
by getting the policy file out of the contents and saving to disk
+                               logger.error("PARTIALLY IMPLEMENTED!!!  ACTUAL 
CHANGES SHOULD BE MADE BY PAP SERVLET!!! ");
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               return;
+                       } else if (request.getParameter("pdpId") != null) {
+                               // ARGS:        group=<groupId> 
pdpId=<pdpId/URL>          <= create a new PDP or Update an Existing one
+                               
+                               String pdpId = request.getParameter("pdpId");
+                               
+               // get the request content into a String
+               String json = null;
+                       // read the inputStream into a buffer (trick found 
online scans entire input looking for end-of-file)
+                   java.util.Scanner scanner = new 
java.util.Scanner(request.getInputStream());
+                   scanner.useDelimiter("\\A");
+                   json =  scanner.hasNext() ? scanner.next() : "";
+                   scanner.close();
+                   logger.info("JSON request from AC: " + json);
+               
+               // convert Object sent as JSON into local object
+                   ObjectMapper mapper = new ObjectMapper();
+                               
+                   Object objectFromJSON = mapper.readValue(json, 
StdPDP.class);
+
+                               if (pdpId == null ||
+                                               objectFromJSON == null ||
+                                               ! (objectFromJSON instanceof 
StdPDP) ||
+                                               
((StdPDP)objectFromJSON).getId() == null ||
+                                               ! 
((StdPDP)objectFromJSON).getId().equals(pdpId)) {
+                                       logger.error("PDP new/update had bad 
input. pdpId=" + pdpId + " objectFromJSON="+objectFromJSON);
+                                       response.sendError(500, "Bad input, 
pdpid="+pdpId+" object="+objectFromJSON);
+                               }
+                               StdPDP pdp = (StdPDP) objectFromJSON;
+                               
+                               if (papEngine.getPDP(pdpId) == null) {
+                                       // this is a request to create a new 
PDP object
+                                       papEngine.newPDP(pdp.getId(), group, 
pdp.getName(), pdp.getDescription());
+                               } else {
+                                       // this is a request to update the pdp
+                                       papEngine.updatePDP(pdp);
+                               }
+
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("PDP '" + pdpId + "' 
created/updated");
+                               }
+                               
+                               // adjust the group's state including the new 
PDP
+                               ((StdPDPGroup)group).resetStatus();
+                               
+                               // tell the Admin Consoles there is a change
+                               notifyAC();
+                               // this might affect the PDP, so notify it of 
the change
+                               pdpChanged(pdp);
+                               return;
+                       } else if (request.getParameter("pipId") != null) {
+       //                group=<groupId> pipId=<pipEngineId> contents=pip 
properties              <= add a PIP to pip config, or replace it if it already 
exists (lenient operation) 
+       //TODO
+                               logger.error("UNIMPLEMENTED ");
+                               
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED");
+                               return;
+                       } else {
+                               // Assume that this is an update of an existing 
PDP Group
+                               // ARGS:        group=<groupId>         <= 
Update an Existing Group
+                                                               
+               // get the request content into a String
+               String json = null;
+                       // read the inputStream into a buffer (trick found 
online scans entire input looking for end-of-file)
+                   java.util.Scanner scanner = new 
java.util.Scanner(request.getInputStream());
+                   scanner.useDelimiter("\\A");
+                   json =  scanner.hasNext() ? scanner.next() : "";
+                   scanner.close();
+                   logger.info("JSON request from AC: " + json);
+               
+               // convert Object sent as JSON into local object
+                   ObjectMapper mapper = new ObjectMapper();
+                   
+                   Object objectFromJSON  = mapper.readValue(json, 
StdPDPGroup.class);
+
+                               if (objectFromJSON == null ||
+                                               ! (objectFromJSON instanceof 
StdPDPGroup) ||
+                                               ! 
((StdPDPGroup)objectFromJSON).getId().equals(group.getId())) {
+                                       logger.error("Group update had bad 
input. id=" + group.getId() + " objectFromJSON="+objectFromJSON);
+                                       response.sendError(500, "Bad input, 
id="+group.getId() +" object="+objectFromJSON);
+                               }
+                               
+                               // The Path on the PAP side is not carried on 
the RESTful interface with the AC
+                               // (because it is local to the PAP)
+                               // so we need to fill that in before submitting 
the group for update
+                               
((StdPDPGroup)objectFromJSON).setDirectory(((StdPDPGroup)group).getDirectory());
+
+                               
papEngine.updateGroup((StdPDPGroup)objectFromJSON);
+
+
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("Group '" + group.getId() 
+ "' updated");
+                               }
+                               // tell the Admin Consoles there is a change
+                               notifyAC();
+                               // Group changed, which might include changing 
the policies
+                               groupChanged(group);
+                               return;
+                       }
+               } catch (PAPException e) {
+                       logger.error("AC PUT exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+       }
+       
+       /**
+        * Requests from the Admin Console to delete/remove items
+        * 
+        * @param request
+        * @param response
+        * @param groupId
+        * @throws ServletException
+        * @throws java.io.IOException
+        */
+       private void doACDelete(HttpServletRequest request, HttpServletResponse 
response, String groupId) throws ServletException, IOException {
+               try {
+                       // for all DELETE operations the group must exist 
before the operation can be done
+                       PDPGroup group = papEngine.getGroup(groupId);
+                       if (group == null) {
+                               logger.error("Unknown groupId '" + groupId + 
"'");
+                               
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + 
groupId +"'");
+                               return;
+                       }
+                       // determine the operation needed based on the 
parameters in the request
+                       if (request.getParameter("policy") != null) {
+       //        group=<groupId> policy=<policyId>  [delete=<true|false>]      
 <= delete policy file from group
+       //TODO
+                               logger.error("UNIMPLEMENTED ");
+                               
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED");
+                               return;
+                       } else if (request.getParameter("pdpId") != null) {
+                               // ARGS:        group=<groupId> pdpId=<pdpId>   
               <= delete PDP 
+                               String pdpId = request.getParameter("pdpId");
+                               PDP pdp = papEngine.getPDP(pdpId);
+                               
+                               papEngine.removePDP(pdp);
+                               
+                               // adjust the status of the group, which may 
have changed when we removed this PDP
+                               ((StdPDPGroup)group).resetStatus();
+                               
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               notifyAC();
+
+                               // update the PDP and tell it that it has NO 
Policies (which prevents it from serving PEP Requests)
+                               pdpChanged(pdp);
+                               return;
+                       } else if (request.getParameter("pipId") != null) {
+       //        group=<groupId> pipId=<pipEngineId> <= delete PIP config for 
given engine
+       //TODO
+                               logger.error("UNIMPLEMENTED ");
+                               
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED");
+                               return;
+                       } else {
+                               // ARGS:      group=<groupId> 
movePDPsToGroupId=<movePDPsToGroupId>            <= delete a group and move all 
its PDPs to the given group
+                               String moveToGroupId = 
request.getParameter("movePDPsToGroupId");
+                               PDPGroup moveToGroup = null;
+                               if (moveToGroupId != null) {
+                                       moveToGroup = 
papEngine.getGroup(moveToGroupId);
+                               }
+                               
+                               // get list of PDPs in the group being deleted 
so we can notify them that they got changed
+                               Set<PDP> movedPDPs = new HashSet<PDP>();
+                               movedPDPs.addAll(group.getPdps());
+                               
+                               // do the move/remove
+                               papEngine.removeGroup(group, moveToGroup);
+                               
+                               
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                               notifyAC();
+                               // notify any PDPs in the removed set that 
their config may have changed
+                               for (PDP pdp : movedPDPs) {
+                                       pdpChanged(pdp);
+                               }
+                               return;
+                       }
+
+               } catch (PAPException e) {
+                       logger.error("AC DELETE exception: " + e, e);
+                       response.sendError(500, e.getMessage());
+                       return;
+               }
+       }
+
+       //
+       // Heartbeat thread - periodically check on PDPs' status
+       //
+       
+       /**
+        * Heartbeat with all known PDPs.
+        * 
+        * Implementation note:
+        * 
+        * The PDPs are contacted Sequentially, not in Parallel.
+        * 
+        * If we did this in parallel using multiple threads we would 
simultaneously use
+        *              - 1 thread and
+        *              - 1 connection
+        * for EACH PDP.
+        * This could become a resource problem since we already use multiple 
threads and connections for updating the PDPs
+        * when user changes occur.
+        * Using separate threads can also make it tricky dealing with timeouts 
on PDPs that are non-responsive.
+        * 
+        * The Sequential operation does a heartbeat request to each PDP one at 
a time.
+        * This has the flaw that any PDPs that do not respond will hold up the 
entire heartbeat sequence until they timeout.
+        * If there are a lot of non-responsive PDPs and the timeout is 
large-ish (the default is 20 seconds)
+        * it could take a long time to cycle through all of the PDPs.
+        * That means that this may not notice a PDP being down in a 
predictable time.
+        * 
+        * @author glenngriffin
+        *
+        */
+       private class Heartbeat implements Runnable {
+               private PAPEngine papEngine;
+               private Set<PDP> pdps = new HashSet<PDP>();
+               private int heartbeatInterval;
+               private int heartbeatTimeout;
+               
+               public volatile boolean isRunning = false;
+               
+               public synchronized boolean isRunning() {
+                       return this.isRunning;
+               }
+               
+               public synchronized void terminate() {
+                       this.isRunning = false;
+               }
+               
+               public Heartbeat(PAPEngine engine) {
+                       this.papEngine = engine;
+                       this.heartbeatInterval = 
Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_INTERVAL,
 "10000"));
+                       this.heartbeatTimeout = 
Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_TIMEOUT,
 "10000"));
+               }
+
+               @Override
+               public void run() {
+                       //
+                       // Set ourselves as running
+                       //
+                       synchronized(this) {
+                               this.isRunning = true;
+                       }
+                       HashMap<String, URL> idToURLMap = new HashMap<String, 
URL>();
+                       try {
+                               while (this.isRunning()) {
+                                       // Wait the given time
+                                       Thread.sleep(heartbeatInterval);
+                                       
+                                       // get the list of PDPs (may have 
changed since last time)
+                                       pdps.clear();
+                                       synchronized(papEngine) {
+                                               try {
+                                                       for (PDPGroup g : 
papEngine.getPDPGroups()) {
+                                                               for (PDP p : 
g.getPdps()) {
+                                                                       
pdps.add(p);
+                                                               }
+                                                       }
+                                               } catch (PAPException e) {
+                                                       logger.error("Heartbeat 
unable to read PDPs from PAPEngine: " + e.getMessage(), e);
+                                               }
+                                       }
+                                       //
+                                       // Check for shutdown
+                                       //
+                                       if (this.isRunning() == false) {
+                                               logger.info("isRunning is 
false, getting out of loop.");
+                                               break;
+                                       }
+                                       
+                                       // try to get the summary status from 
each PDP
+                                       boolean changeSeen = false;
+                                       for (PDP pdp : pdps) {
+                                               //
+                                               // Check for shutdown
+                                               //
+                                               if (this.isRunning() == false) {
+                                                       logger.info("isRunning 
is false, getting out of loop.");
+                                                       break;
+                                               }
+                                               // the id of the PDP is its url 
(though we add a query parameter)
+                                               URL pdpURL = 
idToURLMap.get(pdp.getId());
+                                               if (pdpURL == null) {
+                                                       // haven't seen this 
PDP before
+                                                       String fullURLString = 
null;
+                                                       try {
+                                                               fullURLString = 
pdp.getId() + "?type=hb";
+                                                               pdpURL = new 
URL(fullURLString);
+                                                               
idToURLMap.put(pdp.getId(), pdpURL);
+                                                       } catch 
(MalformedURLException e) {
+                                                               
logger.error("PDP id '" + fullURLString + "' is not a valid URL: " + e, e);
+                                                               continue;
+                                                       }
+                                               }
+                                               
+                                               // Do a GET with type HeartBeat
+                                               String newStatus = "";
+                                               
+                                               HttpURLConnection connection = 
null;
+                                               try {
+
+                                                       //
+                                                       // Open up the 
connection
+                                                       //
+                                                       connection = 
(HttpURLConnection)pdpURL.openConnection();
+                                                       //
+                                                       // Setup our method and 
headers
+                                                       //
+                                           connection.setRequestMethod("GET");
+                                           
connection.setConnectTimeout(heartbeatTimeout);
+                                           //
+                                           // Do the connect
+                                           //
+                                           connection.connect();
+                                           if (connection.getResponseCode() == 
204) {
+                                               newStatus = 
connection.getHeaderField(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB);
+                                                               if 
(logger.isDebugEnabled()) {
+                                                                       
logger.debug("Heartbeat '" + pdp.getId() + "' status='" + newStatus + "'");
+                                                               }
+                                           } else {
+                                               // anything else is an 
unexpected result
+                                               newStatus = 
PDPStatus.Status.UNKNOWN.toString();
+                                               logger.error("Heartbeat connect 
response code " + connection.getResponseCode() + ": " + pdp.getId());
+                                           }
+                                   } catch (UnknownHostException e) {
+                                       newStatus = 
PDPStatus.Status.NO_SUCH_HOST.toString();
+                                       logger.error("Heartbeat '" + 
pdp.getId() + "' NO_SUCH_HOST");
+                                               } catch (SocketTimeoutException 
e) {
+                                       newStatus = 
PDPStatus.Status.CANNOT_CONNECT.toString();
+                                       logger.error("Heartbeat '" + 
pdp.getId() + "' connection timeout: " + e );
+                                               } catch (ConnectException e) {
+                                       newStatus = 
PDPStatus.Status.CANNOT_CONNECT.toString();
+                                       logger.error("Heartbeat '" + 
pdp.getId() + "' cannot connect: " + e );
+                                               } catch (Exception e) {
+                                       newStatus = 
PDPStatus.Status.UNKNOWN.toString();
+                                       logger.error("Heartbeat '" + 
pdp.getId() + "' connect exception: " + e, e);
+                                               } finally {
+                                                       // cleanup the 
connection
+                                                       connection.disconnect();
+                                               }
+
+                                               if ( ! 
pdp.getStatus().getStatus().toString().equals(newStatus)) {
+                                                       if 
(logger.isDebugEnabled()) {
+                                                               
logger.debug("previous status='" + pdp.getStatus().getStatus()+"'  new 
Status='" + newStatus + "'");
+                                                       }
+                                       try {
+                                                               
setPDPSummaryStatus(pdp, newStatus);
+                                                       } catch (PAPException 
e) {
+                                                               
logger.error("Unable to set state for PDP '" + pdp.getId() + "': " + e, e);
+                                                       }
+                                                       changeSeen = true;
+                                               }
+                                               
+                                       }
+                                       //
+                                       // Check for shutdown
+                                       //
+                                       if (this.isRunning() == false) {
+                                               logger.info("isRunning is 
false, getting out of loop.");
+                                               break;
+                                       }
+
+                                       // if any of the PDPs changed state, 
tell the ACs to update
+                                       if (changeSeen) {
+                                               notifyAC();
+                                       }
+                                       
+                               }
+                       } catch (InterruptedException e) {
+                               logger.error("Heartbeat interrupted.  Shutting 
down");
+                               this.terminate();
+                       }
+               }
+       }
+       
+       
+       //
+       // HELPER to change Group status when PDP status is changed
+       //
+       // (Must NOT be called from a method that is synchronized on the 
papEngine or it may deadlock)
+       //
+       
+       private void setPDPSummaryStatus(PDP pdp, PDPStatus.Status newStatus) 
throws PAPException {
+               setPDPSummaryStatus(pdp, newStatus.toString());
+       }
+
+       private void setPDPSummaryStatus(PDP pdp, String newStatus) throws 
PAPException {
+       synchronized(papEngine) {
+               StdPDPStatus status = (StdPDPStatus)pdp.getStatus();
+               status.setStatus(PDPStatus.Status.valueOf(newStatus));
+               ((StdPDP)pdp).setStatus(status);
+               
+               // now adjust the group
+               StdPDPGroup group = (StdPDPGroup)papEngine.getPDPGroup(pdp);
+               // if the PDP was just deleted it may transiently exist but not 
be in a group
+               if (group != null) {
+                       group.resetStatus();
+               }
+       }
+       }
+       
+       
+       //
+       // Callback methods telling this servlet to notify PDPs of changes made 
by the PAP StdEngine
+       //      in the PDP group directories
+       //
+       
+       @Override
+       public void changed() {
+               // all PDPs in all groups need to be updated/sync'd
+               Set<PDPGroup> groups;
+               try {
+                       groups = papEngine.getPDPGroups();
+               } catch (PAPException e) {
+                       logger.error("getPDPGroups failed: " + 
e.getLocalizedMessage());
+                       throw new RuntimeException("Unable to get Groups: " + 
e);
+               }
+               for (PDPGroup group : groups) {
+                       groupChanged(group);
+               }
+       }
+
+       @Override
+       public void groupChanged(PDPGroup group) {
+               // all PDPs within one group need to be updated/sync'd
+               for (PDP pdp : group.getPdps()) {
+                       pdpChanged(pdp);
+               }
+       }
+
+       @Override
+       public void pdpChanged(PDP pdp) {
+               // kick off a thread to do an event notification for each PDP.
+               // This needs to be on a separate thread so that PDPs that do 
not respond (down, non-existent, etc)
+               // do not block the PSP response to the AC, which would freeze 
the GUI until all PDPs sequentially respond or time-out.
+               Thread t = new Thread(new UpdatePDPThread(pdp));
+               t.start();
+       }
+       
+       private class UpdatePDPThread implements Runnable {
+               private PDP pdp;
+
+               // remember which PDP to notify
+               public UpdatePDPThread(PDP pdp) {
+                       this.pdp = pdp;
+               }
+
+               public void run() {
+                       // send the current configuration to one PDP
+                       HttpURLConnection connection = null;
+                       try {
+                               
+                               //
+                               // the Id of the PDP is its URL
+                               //
+                               if (logger.isDebugEnabled()) {
+                                       logger.debug("creating url for id '" + 
pdp.getId() + "'");
+                               }
+       //TODO - currently always send both policies and pips.  Do we care 
enough to add code to allow sending just one or the other?
+       //TODO          (need to change "cache=", implying getting some input 
saying which to change)
+                               URL url = new URL(pdp.getId() + "?cache=all");
+                               
+                               //
+                               // Open up the connection
+                               //
+                               connection = 
(HttpURLConnection)url.openConnection();
+                               //
+                               // Setup our method and headers
+                               //
+                   connection.setRequestMethod("PUT");
+       //                      connection.setRequestProperty("Accept", 
"text/x-java-properties");
+                   connection.setRequestProperty("Content-Type", 
"text/x-java-properties");
+       //            connection.setUseCaches(false);
+                   //
+                   // Adding this in. It seems the HttpUrlConnection class 
does NOT
+                   // properly forward our headers for POST re-direction. It 
does so
+                   // for a GET re-direction.
+                   //
+                   // So we need to handle this ourselves.
+                   //
+       //TODO - is this needed for a PUT?  seems better to leave in for now?
+//                 connection.setInstanceFollowRedirects(false);
+                   //
+                   // PLD - MUST be able to handle re-directs.
+                   //
+                   connection.setInstanceFollowRedirects(true);
+                               connection.setDoOutput(true);
+       //                      connection.setDoInput(true);
+                       try (OutputStream os = connection.getOutputStream()) {
+       
+                               PDPGroup group = papEngine.getPDPGroup(pdp);
+                               // if the PDP was just deleted, there is no 
group, but we want to send an update anyway
+                               if (group == null) {
+                                       // create blank properties files
+                                       Properties policyProperties = new 
Properties();
+                                       
policyProperties.put(XACMLProperties.PROP_ROOTPOLICIES, "");
+                                       
policyProperties.put(XACMLProperties.PROP_REFERENCEDPOLICIES, "");
+                                       policyProperties.store(os, "");
+                                       
+                                       Properties pipProps = new Properties();
+                                               
pipProps.setProperty(XACMLProperties.PROP_PIP_ENGINES, "");
+                                               pipProps.store(os, "");
+                                       
+                               } else {
+                                       // send properties from the current 
group
+                                       group.getPolicyProperties().store(os, 
"");
+                                       Properties policyLocations = new 
Properties();
+                                       for (PDPPolicy policy : 
group.getPolicies()) {
+                                                  
policyLocations.put(policy.getId() + ".url", XACMLPapServlet.papURL + "?id=" + 
policy.getId());
+                                       }
+                                       policyLocations.store(os, "");
+                                       
group.getPipConfigProperties().store(os, "");
+                               }
+               
+                       } catch (Exception e) {
+                               logger.error("Failed to send property file to " 
+ pdp.getId(), e);
+                               // Since this is a server-side error, it 
probably does not reflect a problem on the client,
+                               // so do not change the PDP status.
+                               return;
+                       }
+                   //
+                   // Do the connect
+                   //
+                   connection.connect();
+                   if (connection.getResponseCode() == 204) {
+                       logger.info("Success. We are configured correctly.");
+                                       setPDPSummaryStatus(pdp, 
PDPStatus.Status.UP_TO_DATE);
+                   } else if (connection.getResponseCode() == 200) {
+                       logger.info("Success. PDP needs to update its 
configuration.");
+                                       setPDPSummaryStatus(pdp, 
PDPStatus.Status.OUT_OF_SYNCH);
+                   } else {
+                       logger.warn("Failed: " + connection.getResponseCode() + 
"  message: " + connection.getResponseMessage());
+                                       setPDPSummaryStatus(pdp, 
PDPStatus.Status.UNKNOWN);
+                   }
+                       } catch (Exception e) {
+                               logger.error("Unable to sync config with PDP '" 
+ pdp.getId() + "': " + e, e);
+                               try {
+                                       setPDPSummaryStatus(pdp, 
PDPStatus.Status.UNKNOWN);
+                               } catch (PAPException e1) {
+                                       logger.error("Unable to set status of 
PDP '" + pdp.getId() + "' to UNKNOWN: " + e, e);
+                               }
+                       } finally {
+                               // cleanup the connection
+                               connection.disconnect();
+                               
+                   // tell the AC to update it's status info
+                   notifyAC();
+                       }
+                       
+               }
+       }
+
+       //
+       // RESTful Interface from PAP to ACs notifying them of changes
+       //
+       
+       private void notifyAC() {
+               // kick off a thread to do one event notification for all 
registered ACs
+               // This needs to be on a separate thread so that ACs can make 
calls back to PAP to get the updated Group data
+               // as part of processing this message on their end.
+               Thread t = new Thread(new NotifyACThread());
+               t.start();
+       }
+       
+       private class NotifyACThread implements Runnable {
+       
+               public void run() {
+                       List<String> disconnectedACs = new ArrayList<String>();
+// logger.debug("LIST SIZE="+adminConsoleURLStringList.size());
+                       
+                       // There should be no Concurrent exception here because 
the list is a CopyOnWriteArrayList.
+                       // The "for each" loop uses the collection's iterator 
under the covers, so it should be correct.
+                       for (String acURL : adminConsoleURLStringList) {
+                               HttpURLConnection connection = null;
+                               try {
+                                       
+                                       acURL += "?PAPNotification=true";
+                                       
+//TODO - Currently we just tell AC that "Something changed" without being 
specific.  Do we want to tell it which group/pdp changed?
+//TODO - If so, put correct parameters into the Query string here
+                                       acURL += "&objectType=all" + 
"&action=update";
+       
+                                       if (logger.isDebugEnabled()) {
+                                               logger.debug("creating url for 
id '" + acURL + "'");
+                                       }
+//TODO - currently always send both policies and pips.  Do we care enough to 
add code to allow sending just one or the other?
+//TODO         (need to change "cache=", implying getting some input saying 
which to change)
+                                       
+                                       URL url = new URL(acURL );
+                                       
+                                       //
+                                       // Open up the connection
+                                       //
+                                       connection = 
(HttpURLConnection)url.openConnection();
+                                       //
+                                       // Setup our method and headers
+                                       //
+                           connection.setRequestMethod("PUT");
+                           connection.setRequestProperty("Content-Type", 
"text/x-java-properties");
+                           //
+                           // Adding this in. It seems the HttpUrlConnection 
class does NOT
+                           // properly forward our headers for POST 
re-direction. It does so
+                           // for a GET re-direction.
+                           //
+                           // So we need to handle this ourselves.
+                           //
+               //TODO - is this needed for a PUT?  seems better to leave in 
for now?
+                           connection.setInstanceFollowRedirects(false);
+                                       //
+                                       // Do not include any data in the PUT 
because this is just a
+                                       // notification to the AC.
+                                       // The AC will use GETs back to the PAP 
to get what it needs
+                                       // to fill in the screens.
+                                       //
+                                       
+                           //
+                           // Do the connect
+                           //
+                           connection.connect();
+                           if (connection.getResponseCode() == 204) {
+                               logger.info("Success. We updated correctly.");
+                           } else {
+                               logger.warn("Failed: " + 
connection.getResponseCode() + "  message: " + connection.getResponseMessage());
+                           }
+                                       
+                               } catch (Exception e) {
+                                       logger.error("Unable to sync config AC 
'" + acURL + "': " + e, e);
+                                       disconnectedACs.add(acURL);
+                               } finally {
+                                       // cleanup the connection
+                                       connection.disconnect();
+                               }
+                       }
+                       
+                       // remove any ACs that are no longer connected
+                       if (disconnectedACs.size() > 0) {
+                               
adminConsoleURLStringList.removeAll(disconnectedACs);
+                       }
+
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pap-rest/src/main/resources/log4j.properties 
b/openaz-xacml-pap-rest/src/main/resources/log4j.properties
new file mode 100755
index 0000000..b45fa2f
--- /dev/null
+++ b/openaz-xacml-pap-rest/src/main/resources/log4j.properties
@@ -0,0 +1,22 @@
+#
+# Use this properties for debugging and development.
+#
+#
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=DEBUG, MAIN_LOG
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.MAIN_LOG=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.MAIN_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.MAIN_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} 
[%t] %-5p %l- %m%n
+
+#
+# This is specifically for Xacml request/response logging
+#
+log4j.logger.xacml.request=INFO, REQUEST_LOG
+
+log4j.appender.REQUEST_LOG=org.apache.log4j.ConsoleAppender
+log4j.appender.REQUEST_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.REQUEST_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS}
 %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class
 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class
new file mode 100644
index 0000000..352e4c6
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class
 differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class
 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class
new file mode 100644
index 0000000..aac4b91
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class
 differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class
 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class
new file mode 100644
index 0000000..3d756fd
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class
 differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class
 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class
new file mode 100644
index 0000000..ffd1592
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class
 differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class
 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class
new file mode 100644
index 0000000..d8d63b5
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class
 differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/log4j.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pap-rest/target/classes/log4j.properties 
b/openaz-xacml-pap-rest/target/classes/log4j.properties
new file mode 100644
index 0000000..b45fa2f
--- /dev/null
+++ b/openaz-xacml-pap-rest/target/classes/log4j.properties
@@ -0,0 +1,22 @@
+#
+# Use this properties for debugging and development.
+#
+#
+# Set root logger level to DEBUG and its only appender to A1.
+log4j.rootLogger=DEBUG, MAIN_LOG
+
+# A1 is set to be a ConsoleAppender.
+log4j.appender.MAIN_LOG=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.MAIN_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.MAIN_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} 
[%t] %-5p %l- %m%n
+
+#
+# This is specifically for Xacml request/response logging
+#
+log4j.logger.xacml.request=INFO, REQUEST_LOG
+
+log4j.appender.REQUEST_LOG=org.apache.log4j.ConsoleAppender
+log4j.appender.REQUEST_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.REQUEST_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS}
 %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-archiver/pom.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pap-rest/target/maven-archiver/pom.properties 
b/openaz-xacml-pap-rest/target/maven-archiver/pom.properties
new file mode 100644
index 0000000..022f696
--- /dev/null
+++ b/openaz-xacml-pap-rest/target/maven-archiver/pom.properties
@@ -0,0 +1,5 @@
+#Generated by Maven
+#Tue Apr 07 07:42:37 EDT 2015
+version=0.0.1-SNAPSHOT
+groupId=org.openliberty.openaz
+artifactId=openaz-xacml-pap-rest

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
 
b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
new file mode 100644
index 0000000..4cfb3ef
--- /dev/null
+++ 
b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -0,0 +1,5 @@
+com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class
+com/att/research/xacml/rest/XACMLPapServlet$1.class
+com/att/research/xacml/rest/XACMLPapServlet.class
+com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class
+com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
 
b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
new file mode 100644
index 0000000..9a51391
--- /dev/null
+++ 
b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -0,0 +1 @@
+/Users/ajith/IdeaProjects/openaz/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
 
b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar
----------------------------------------------------------------------
diff --git 
a/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar 
b/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar
new file mode 100644
index 0000000..d8cdce7
Binary files /dev/null and 
b/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/xacml.pap.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pap-rest/xacml.pap.properties 
b/openaz-xacml-pap-rest/xacml.pap.properties
new file mode 100755
index 0000000..05fc0c5
--- /dev/null
+++ b/openaz-xacml-pap-rest/xacml.pap.properties
@@ -0,0 +1,35 @@
+#
+# This is our factory that will create our engine
+#
+xacml.PAP.papEngineFactory=com.att.research.xacml.std.pap.StdEngineFactory
+
+#
+# Where we store our PAP PDP Group/Node information
+#
+xacml.pap.pdps=pdps
+#
+# Need the PAP's url (how PDPs will reach it) configured here
+# because we need it to generate the URLs of the Policy Files
+# sent to the PDPs in the configuration when the PAP is first brought up.
+# (In other cases, such as the PDP calling the PAP, we could generate this 
URL, 
+# but for startup there is no other way to get it.)
+#
+#
+xacml.rest.pap.url=http://localhost:9090/pap/
+
+#
+# Upon startup, have the PAP servlet send latest configuration information to 
all
+# the PDP nodes it knows about.
+#
+xacml.rest.pap.initiate.pdp=true
+#
+# Heartbeat from PAP to PDPs
+#
+# How much time (in milliseconds) between heartbeats
+# (i.e. the time between completing the heartbeat with all PDPs and starting 
the next cycle)
+#
+xacml.rest.pap.heartbeat.interval=10000
+#
+# Heartbeat connection timeout (in milliseconds)
+#
+xacml.rest.pap.heartbeat.timeout=10000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF 
b/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..58630c0
--- /dev/null
+++ b/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar
----------------------------------------------------------------------
diff --git a/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar 
b/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar
new file mode 100755
index 0000000..d6b7f6d
Binary files /dev/null and 
b/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/config/xacml.pip.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pdp-rest/config/xacml.pip.properties 
b/openaz-xacml-pdp-rest/config/xacml.pip.properties
new file mode 100755
index 0000000..0c16eb3
--- /dev/null
+++ b/openaz-xacml-pdp-rest/config/xacml.pip.properties
@@ -0,0 +1,219 @@
+# PIP Engine Definition
+#
+xacml.pip.engines=csv1,csv2,hyper1,sql1,ldap1
+
+csv1.classname=com.att.research.xacml.std.pip.engines.csv.CSVEngine
+csv1.name=Master
+csv1.description=Sean Lahman Basebase stats - Player names, DOB, and 
biographical info
+csv1.issuer=com:att:research:xacml:test:csv
+csv1.source=../XACML-TEST/testsets/pip/configurable-csv/adminDB/Master.txt
+csv1.maxsize=4000000
+csv1.delimiter=,
+csv1.quote="
+csv1.skip=0
+
+csv1.resolvers=data
+
+csv1.resolver.data.classname=com.att.research.xacml.std.pip.engines.csv.ConfigurableCSVResolver
+csv1.resolver.data.name=Player Resolver
+csv1.resolver.data.description=This resolver finds player information in the 
Master table.
+csv1.resolver.data.fields=firstname,lastname,deathyear,deathmonth,deathday,debut,finalgame
+csv1.resolver.data.field.firstname.column=16
+csv1.resolver.data.field.firstname.id=com:att:research:xacml:test:csv:subject:firstname
+csv1.resolver.data.field.firstname.datatype=http://www.w3.org/2001/XMLSchema#string
+csv1.resolver.data.field.firstname.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.lastname.column=17
+csv1.resolver.data.field.lastname.id=com:att:research:xacml:test:csv:subject:lastname
+csv1.resolver.data.field.lastname.datatype=http://www.w3.org/2001/XMLSchema#string
+csv1.resolver.data.field.lastname.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.deathyear.column=10
+csv1.resolver.data.field.deathyear.id=com:att:research:xacml:test:csv:subject:deathyear
+csv1.resolver.data.field.deathyear.datatype=http://www.w3.org/2001/XMLSchema#integer
+csv1.resolver.data.field.deathyear.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.deathmonth.column=11
+csv1.resolver.data.field.deathmonth.id=com:att:research:xacml:test:csv:subject:deathmonth
+csv1.resolver.data.field.deathmonth.datatype=http://www.w3.org/2001/XMLSchema#integer
+csv1.resolver.data.field.deathmonth.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.deathday.column=12
+csv1.resolver.data.field.deathday.id=com:att:research:xacml:test:csv:subject:deathday
+csv1.resolver.data.field.deathday.datatype=http://www.w3.org/2001/XMLSchema#integer
+csv1.resolver.data.field.deathday.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.debut.column=25
+csv1.resolver.data.field.debut.id=com:att:research:xacml:test:csv:subject:debut
+csv1.resolver.data.field.debut.datatype=http://www.w3.org/2001/XMLSchema#date
+csv1.resolver.data.field.debut.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.field.finalgame.column=26
+csv1.resolver.data.field.finalgame.id=com:att:research:xacml:test:csv:subject:finalgame
+csv1.resolver.data.field.finalgame.datatype=http://www.w3.org/2001/XMLSchema#date
+csv1.resolver.data.field.finalgame.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv1.resolver.data.parameters=playerid
+csv1.resolver.data.parameter.playerid.column=1
+csv1.resolver.data.parameter.playerid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id
+csv1.resolver.data.parameter.playerid.datatype=http://www.w3.org/2001/XMLSchema#string
+csv1.resolver.data.parameter.playerid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+
+csv2.classname=com.att.research.xacml.std.pip.engines.csv.CSVEngine
+csv2.name=Appearances
+csv2.description=Sean Lahman Basebase stats - Player appearances for a team in 
a given year.
+#csv2.issuer=
+csv2.source=../XACML-TEST/testsets/pip/configurable-csv/adminDB/Appearances.txt
+csv2.maxsize=4000000
+csv2.delimiter=,
+csv2.quote="
+csv2.skip=0
+
+csv2.resolvers=data
+
+csv2.resolver.data.classname=com.att.research.xacml.std.pip.engines.csv.ConfigurableCSVResolver
+csv2.resolver.data.name=Appearance Resolver
+csv2.resolver.data.description=This resolver returns all the appearances for a 
player from the appearance table.
+csv2.resolver.data.fields=appearance
+csv2.resolver.data.field.appearance.column=0
+csv2.resolver.data.field.appearance.id=com:att:research:xacml:test:csv:subject:appearance
+csv2.resolver.data.field.appearance.datatype=http://www.w3.org/2001/XMLSchema#integer
+csv2.resolver.data.field.appearance.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+csv2.resolver.data.field.appearance.issuer=com:att:research:xacml:test:csv
+
+csv2.resolver.data.parameters=playerid
+csv2.resolver.data.parameter.playerid.column=3
+csv2.resolver.data.parameter.playerid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id
+csv2.resolver.data.parameter.playerid.datatype=http://www.w3.org/2001/XMLSchema#string
+csv2.resolver.data.parameter.playerid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+#csv1.resolver.data.parameter.playerid.issuer=
+
+hyper1.classname=com.att.research.xacml.std.pip.engines.csv.HyperCSVEngine
+hyper1.name=World Marriage Age Limits
+hyper1.description=Minimum age for female/male marriages with or without their 
parental consent.
+hyper1.source=../XACML-TEST/testsets/pip/configurable-csv-hyper/marriage.csv
+hyper1.target=marriage
+hyper1.definition=country VARCHAR(80) PRIMARY KEY, wofemale INT, womale INT, 
wfemale INT, wmale INT, year INT, source VARCHAR(20)
+
+hyper1.resolvers=age_consent
+
+hyper1.resolver.age_consent.classname=com.att.research.xacml.std.pip.engines.jdbc.ConfigurableJDBCResolver
+hyper1.resolver.age_consent.name=Ages
+hyper1.resolver.age_consent.description=This returns all the age's for consent 
or no consent for a country.
+hyper1.resolver.age_consent.select=SELECT wofemale,womale,wfemale,wmale FROM 
marriage WHERE country=?
+hyper1.resolver.age_consent.fields=wofemale,womale,wfemale,wmale
+
+hyper1.resolver.age_consent.field.wofemale.id=com:att:research:xacml:test:csv:country:no-consent:female
+hyper1.resolver.age_consent.field.wofemale.datatype=http://www.w3.org/2001/XMLSchema#integer
+hyper1.resolver.age_consent.field.wofemale.category=com:att:research:xacml:test:csv:category:country
+hyper1.resolver.age_consent.field.wofemale.issuer=com:att:research:xacml:test:csv
+
+hyper1.resolver.age_consent.field.womale.id=com:att:research:xacml:test:csv:country:no-consent:male
+hyper1.resolver.age_consent.field.womale.datatype=http://www.w3.org/2001/XMLSchema#integer
+hyper1.resolver.age_consent.field.womale.category=com:att:research:xacml:test:csv:category:country
+hyper1.resolver.age_consent.field.womale.issuer=com:att:research:xacml:test:csv
+
+hyper1.resolver.age_consent.field.wfemale.id=com:att:research:xacml:test:csv:country:consent:female
+hyper1.resolver.age_consent.field.wfemale.datatype=http://www.w3.org/2001/XMLSchema#integer
+hyper1.resolver.age_consent.field.wfemale.category=com:att:research:xacml:test:csv:category:country
+hyper1.resolver.age_consent.field.wfemale.issuer=com:att:research:xacml:test:csv
+
+hyper1.resolver.age_consent.field.wmale.id=com:att:research:xacml:test:csv:country:consent:male
+hyper1.resolver.age_consent.field.wmale.datatype=http://www.w3.org/2001/XMLSchema#integer
+hyper1.resolver.age_consent.field.wmale.category=com:att:research:xacml:test:csv:category:country
+hyper1.resolver.age_consent.field.wmale.issuer=com:att:research:xacml:test:csv
+
+hyper1.resolver.age_consent.parameters=country
+hyper1.resolver.age_consent.parameter.country.id=com:att:research:xacml:test:csv:country:name
+hyper1.resolver.age_consent.parameter.country.datatype=http://www.w3.org/2001/XMLSchema#string
+hyper1.resolver.age_consent.parameter.country.category=com:att:research:xacml:test:csv:category:country
+#hyper1.resolver.age_consent.parameter.country.issuer=
+
+sql1.classname=com.att.research.xacml.std.pip.engines.jdbc.JDBCEngine
+sql1.name=World
+sql1.description=World Database from MySQL website. Copyright Statistics 
Finland, http://www.stat.fi/worldinfigures.
+# This will be the default issuer for the resolvers. NOTE: Issuer only used 
for attributes provided by the engine.
+sql1.issuer=com:att:research:xacml:test:sql
+#
+# This is the configuration for JDBC. You will have to setup the database and 
run the data\world*.sql script to
+# create the tables and load the data. 
+#
+sql1.type=jdbc
+sql1.jdbc.driver=org.postgresql.Driver
+sql1.jdbc.url=jdbc:postgresql://localhost:5432/world
+sql1.jdbc.conn.user=sa
+sql1.jdbc.conn.password=
+#
+# This is the configuration for JNDI datasource.
+#
+#sql1.type=jndi
+#sql1.datasource=jdbc/xacml
+
+sql1.resolvers=langer
+
+sql1.resolver.langer.classname=com.att.research.xacml.std.pip.engines.jdbc.ConfigurableJDBCResolver
+sql1.resolver.langer.name=Language
+sql1.resolver.langer.description=This returns the language for a city.
+sql1.resolver.langer.select=SELECT language FROM city INNER JOIN 
countrylanguage ON city.countrycode = countrylanguage.countrycode WHERE name=?
+sql1.resolver.langer.fields=language
+sql1.resolver.langer.field.language.id=com:att:research:xacml:test:sql:resource:city:language
+sql1.resolver.langer.field.language.datatype=http://www.w3.org/2001/XMLSchema#string
+sql1.resolver.langer.field.language.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource
+#You can override the default issuer that is set in the JDBCEngine definition 
if you want.
+#sql1.resolver.langer.field.language.issuer=com:att:research:xacml:test:sql
+sql1.resolver.langer.parameters=name
+sql1.resolver.langer.parameter.name.id=urn:oasis:names:tc:xacml:1.0:resource:resource-id
+sql1.resolver.langer.parameter.name.datatype=http://www.w3.org/2001/XMLSchema#string
+sql1.resolver.langer.parameter.name.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource
+
+
+ldap1.classname=com.att.research.xacml.std.pip.engines.ldap.LDAPEngine
+ldap1.name=LDAP PIP
+ldap1.description=The LDAP containing the seven seas sample LDIF data.
+ldap1.issuer=com:att:research:xacml:test:ldap
+ldap1.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
+#
+# NOTE: You will have to setup a local LDAP server and load the 
data\apache-ds-tutorial.ldif before
+# this example will work.
+#
+ldap1.java.naming.provider.url=ldap://localhost:10389
+#ldap.java.naming.security.principal=
+#ldap.java.naming.security.credentials=
+ldap1.scope=subtree
+
+ldap1.resolvers=dn,ship
+
+ldap1.resolver.dn.classname=com.att.research.xacml.std.pip.engines.ldap.ConfigurableLDAPResolver
+ldap1.resolver.dn.name=Domain Names
+ldap1.resolver.dn.description=Find all the dn's for the subject id
+ldap1.resolver.dn.base=o=sevenseas
+ldap1.resolver.dn.base.parameters=
+ldap1.resolver.dn.filter=(|(uid=${uid})(mail=${uid}))
+ldap1.resolver.dn.filter.parameters=uid
+ldap1.resolver.dn.filter.parameters.uid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id
+ldap1.resolver.dn.filter.parameters.uid.datatype=http://www.w3.org/2001/XMLSchema#string
+ldap1.resolver.dn.filter.parameters.uid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
+#ldap1.resolver.dn.filter.parameters.uid.issuer=com:att:research:xacml:test:ldap
+ldap1.resolver.dn.filter.view=dn
+ldap1.resolver.dn.filter.view.dn.id=com:att:research:xacml:test:ldap:subject:dn
+ldap1.resolver.dn.filter.view.dn.datatype=http://www.w3.org/2001/XMLSchema#string
+ldap1.resolver.dn.filter.view.dn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource
+ldap1.resolver.dn.filter.view.dn.issuer=com:att:research:xacml:test:ldap
+
+ldap1.resolver.ship.classname=com.att.research.xacml.std.pip.engines.ldap.ConfigurableLDAPResolver
+ldap1.resolver.ship.name=Ship Resolver
+ldap1.resolver.ship.description=This resolves a subject's dn to a ship.
+ldap1.resolver.ship.base=o=sevenseas
+ldap1.resolver.ship.base.parameters=
+ldap1.resolver.ship.filter=uniquemember=${dn}
+ldap1.resolver.ship.filter.parameters=dn
+ldap1.resolver.ship.filter.parameters.dn.id=com:att:research:xacml:test:ldap:subject:dn
+ldap1.resolver.ship.filter.parameters.dn.datatype=http://www.w3.org/2001/XMLSchema#string
+ldap1.resolver.ship.filter.parameters.dn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource
+ldap1.resolver.ship.filter.parameters.dn.issuer=com:att:research:xacml:test:ldap
+ldap1.resolver.ship.filter.view=cn
+ldap1.resolver.ship.filter.view.cn.id=com:att:research:xacml:test:ldap:subject:ship
+ldap1.resolver.ship.filter.view.cn.datatype=http://www.w3.org/2001/XMLSchema#string
+ldap1.resolver.ship.filter.view.cn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource
+ldap1.resolver.ship.filter.view.cn.issuer=com:att:research:xacml:test:ldap
+

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/config/xacml.policy.properties
----------------------------------------------------------------------
diff --git a/openaz-xacml-pdp-rest/config/xacml.policy.properties 
b/openaz-xacml-pdp-rest/config/xacml.policy.properties
new file mode 100755
index 0000000..d42c84c
--- /dev/null
+++ b/openaz-xacml-pdp-rest/config/xacml.policy.properties
@@ -0,0 +1,8 @@
+xacml.rootPolicies=annotation,ldap,csv,csvhyper,sql
+xacml.referencedPolicies=
+
+annotation.file=../XACML-TEST/testsets/annotation/AnnotationPolicy.v1.xml
+ldap.file=../XACML-TEST/testsets/pip/configurable-ldap/LDAP-Seven-Seas-v1.xml
+csv.file=../XACML-TEST/testsets/pip/configurable-csv/CSV-Baseball-Hall-Of-Fame-v1.xml
+csvhyper.file=../XACML-TEST/testsets/pip/configurable-csv-hyper/CSV-Legal-Age-Marriage-v1.xml
+sql.file=../XACML-TEST/testsets/pip/configurable-sql/SQL-World-Languages-v1.xml

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/pom.xml
----------------------------------------------------------------------
diff --git a/openaz-xacml-pdp-rest/pom.xml b/openaz-xacml-pdp-rest/pom.xml
new file mode 100755
index 0000000..edb97b4
--- /dev/null
+++ b/openaz-xacml-pdp-rest/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>openaz</artifactId>
+        <groupId>org.openliberty.openaz</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>openaz-xacml-pdp-rest</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.openliberty.openaz</groupId>
+            <artifactId>openaz-xacml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openliberty.openaz</groupId>
+            <artifactId>openaz-xacml-rest</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.openliberty.openaz</groupId>
+            <artifactId>openaz-xacml-pdp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hsqldb</groupId>
+            <artifactId>hsqldb</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Reply via email to