Add more junit coverage to xacml-pdp (round #2)
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdXacmlApplicationServiceProvider.java
index 19d8d82..8929956 100644 (file)
@@ -28,33 +28,36 @@ import com.att.research.xacml.api.pdp.PDPEngine;
 import com.att.research.xacml.api.pdp.PDPEngineFactory;
 import com.att.research.xacml.api.pdp.PDPException;
 import com.att.research.xacml.util.FactoryException;
-
+import com.att.research.xacml.util.XACMLPolicyWriter;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+import org.apache.commons.lang3.tuple.Pair;
 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 import org.onap.policy.models.decisions.concepts.DecisionResponse;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
+public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
     private Path pathForData = null;
     private Properties pdpProperties = null;
     private PDPEngine pdpEngine = null;
+    private Map<ToscaPolicy, Path> mapLoadedPolicies = new HashMap<>();
 
     public StdXacmlApplicationServiceProvider() {
         super();
@@ -78,29 +81,13 @@ public class StdXacmlApplicationServiceProvider implements XacmlApplicationServi
         this.pathForData = pathForData;
         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
         //
-        // Ensure properties exist
-        //
-        Path propertiesPath = XacmlPolicyUtils.getPropertiesPath(pathForData);
-        if (! propertiesPath.toFile().exists()) {
-            LOGGER.info("Copying src/main/resources/xacml.properties to path");
-            //
-            // Properties do not exist, by default we will copy ours over
-            // from src/main/resources
-            //
-            try {
-                Files.copy(Paths.get("src/main/resources/xacml.properties"), propertiesPath);
-            } catch (IOException e) {
-                throw new XacmlApplicationException("Failed to copy xacml.propertis", e);
-            }
-        }
-        //
         // Look for and load the properties object
         //
         try {
             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
-            LOGGER.debug("{}", pdpProperties);
+            LOGGER.info("{}", pdpProperties);
         } catch (IOException e) {
-            throw new XacmlApplicationException("Failed to load xacml.propertis", e);
+            throw new XacmlApplicationException("Failed to load " + XacmlPolicyUtils.XACML_PROPERTY_FILE, e);
         }
         //
         // Create an engine
@@ -110,25 +97,147 @@ public class StdXacmlApplicationServiceProvider implements XacmlApplicationServi
 
     @Override
     public List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
-        return Collections.emptyList();
+        throw new UnsupportedOperationException("Please override and implement supportedPolicyTypes");
     }
 
     @Override
     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
-        return false;
+        throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
     }
 
     @Override
-    public void loadPolicies(Map<String, Object> toscaPolicies) throws XacmlApplicationException {
-        throw new UnsupportedOperationException("Please override and implement loadPolicies");
+    public synchronized boolean loadPolicy(ToscaPolicy toscaPolicy) {
+        try {
+            //
+            // Convert the policies first
+            //
+            PolicyType xacmlPolicy = this.getTranslator(toscaPolicy.getType())
+                .convertPolicy(toscaPolicy);
+            if (xacmlPolicy == null) {
+                throw new ToscaPolicyConversionException("Failed to convert policy");
+            }
+            //
+            // Create a copy of the properties object
+            //
+            Properties newProperties = this.getProperties();
+            //
+            // Construct the filename
+            //
+            Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
+            //
+            // Write the policy to disk
+            // Maybe check for an error
+            //
+            XACMLPolicyWriter.writePolicyFile(refPath, xacmlPolicy);
+            if (LOGGER.isInfoEnabled()) {
+                LOGGER.info("Xacml Policy is {}{}", System.lineSeparator(), new String(Files.readAllBytes(refPath)));
+            }
+            //
+            // Add root policy to properties object
+            //
+            XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
+            //
+            // Write the properties to disk
+            //
+            XacmlPolicyUtils.storeXacmlProperties(newProperties,
+                    XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
+            //
+            // Reload the engine
+            //
+            this.createEngine(newProperties);
+            //
+            // Save the properties
+            //
+            this.pdpProperties = newProperties;
+            //
+            // Save in our map
+            //
+            this.mapLoadedPolicies.put(toscaPolicy, refPath);
+        } catch (IOException | ToscaPolicyConversionException e) {
+            LOGGER.error("Failed to loadPolicies {}", e);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public synchronized boolean unloadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
+        //
+        // Find it in our map
+        //
+        Path refPolicy = this.mapLoadedPolicies.get(toscaPolicy);
+        if (refPolicy == null) {
+            LOGGER.error("Failed to find ToscaPolicy {} in our map size {}", toscaPolicy.getMetadata(),
+                    this.mapLoadedPolicies.size());
+            return false;
+        }
+        //
+        // Create a copy of the properties object
+        //
+        Properties newProperties = this.getProperties();
+        //
+        // Remove it from the properties
+        //
+        XacmlPolicyUtils.removeRootPolicy(newProperties, refPolicy);
+        //
+        // We can delete the file
+        //
+        try {
+            Files.delete(refPolicy);
+        } catch (IOException e) {
+            LOGGER.error("Failed to delete policy {} from disk {}", toscaPolicy.getMetadata(),
+                    refPolicy.toAbsolutePath().toString(), e);
+        }
+        //
+        // Write the properties to disk
+        //
+        try {
+            XacmlPolicyUtils.storeXacmlProperties(newProperties,
+                    XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
+        } catch (IOException e) {
+            LOGGER.error("Failed to save the properties to disk {}", newProperties, e);
+        }
+        //
+        // Reload the engine
+        //
+        this.createEngine(newProperties);
+        //
+        // Save the properties
+        //
+        this.pdpProperties = newProperties;
+        //
+        // Save in our map
+        //
+        if (this.mapLoadedPolicies.remove(toscaPolicy) == null) {
+            LOGGER.error("Failed to remove toscaPolicy {} from internal map size {}", toscaPolicy.getMetadata(),
+                    this.mapLoadedPolicies.size());
+        }
+        //
+        // Not sure if any of the errors above warrant returning false
+        //
+        return true;
     }
 
     @Override
-    public DecisionResponse makeDecision(DecisionRequest request) {
+    public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request) {
         //
-        // We should have a standard error response to return
+        // Convert to a XacmlRequest
         //
-        return null;
+        Request xacmlRequest = this.getTranslator().convertRequest(request);
+        //
+        // Now get a decision
+        //
+        Response xacmlResponse = this.xacmlDecision(xacmlRequest);
+        //
+        // Convert to a DecisionResponse
+        //
+        return Pair.of(this.getTranslator().convertResponse(xacmlResponse), xacmlResponse);
+    }
+
+    protected abstract ToscaPolicyTranslator getTranslator(String type);
+
+    protected ToscaPolicyTranslator getTranslator() {
+        return this.getTranslator("");
     }
 
     protected synchronized PDPEngine getEngine() {
@@ -136,48 +245,15 @@ public class StdXacmlApplicationServiceProvider implements XacmlApplicationServi
     }
 
     protected synchronized Properties getProperties() {
-        return new Properties(pdpProperties);
+        Properties newProperties = new Properties();
+        newProperties.putAll(pdpProperties);
+        return newProperties;
     }
 
     protected synchronized Path getDataPath() {
         return pathForData;
     }
 
-    /**
-     * Load properties from given file.
-     *
-     * @throws IOException If unable to read file
-     */
-    protected synchronized Properties loadXacmlProperties() throws IOException {
-        LOGGER.debug("Loading xacml properties {}", pathForData);
-        try (InputStream is = Files.newInputStream(pathForData)) {
-            Properties properties = new Properties();
-            properties.load(is);
-            return properties;
-        }
-    }
-
-    /**
-     * Stores the XACML Properties to the given file location.
-     *
-     * @throws IOException If unable to store the file.
-     */
-    protected synchronized void storeXacmlProperties() throws IOException {
-        try (OutputStream os = Files.newOutputStream(pathForData)) {
-            String strComments = "#";
-            pdpProperties.store(os, strComments);
-        }
-    }
-
-    /**
-     * Appends 'xacml.properties' to a root Path object
-     *
-     * @return Path to rootPath/xacml.properties file
-     */
-    protected synchronized Path getPropertiesPath() {
-        return Paths.get(pathForData.toAbsolutePath().toString(), "xacml.properties");
-    }
-
     /**
      * Creates an instance of PDP engine given the Properties object.
      */
@@ -186,11 +262,10 @@ public class StdXacmlApplicationServiceProvider implements XacmlApplicationServi
         // Now initialize the XACML PDP Engine
         //
         try {
-            PDPEngineFactory factory = PDPEngineFactory.newInstance();
+            PDPEngineFactory factory = getPdpEngineFactory();
             PDPEngine engine = factory.newEngine(properties);
             if (engine != null) {
                 this.pdpEngine = engine;
-                this.pdpProperties = new Properties(properties);
             }
         } catch (FactoryException e) {
             LOGGER.error("Failed to create XACML PDP Engine {}", e);
@@ -226,4 +301,9 @@ public class StdXacmlApplicationServiceProvider implements XacmlApplicationServi
         return response;
     }
 
+    // these may be overridden by junit tests
+
+    protected PDPEngineFactory getPdpEngineFactory() throws FactoryException {
+        return PDPEngineFactory.newInstance();
+    }
 }