Upgrade to oparent 3.2.1
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdMatchableTranslator.java
index 9d3c626..5672295 100644 (file)
@@ -2,7 +2,8 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2021 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.pdp.xacml.application.common.std;
 
-import com.att.research.xacml.api.AttributeAssignment;
-import com.att.research.xacml.api.DataTypeException;
-import com.att.research.xacml.api.Decision;
+import com.att.research.xacml.api.Advice;
 import com.att.research.xacml.api.Identifier;
 import com.att.research.xacml.api.Obligation;
 import com.att.research.xacml.api.Request;
-import com.att.research.xacml.api.Response;
-import com.att.research.xacml.api.Result;
 import com.att.research.xacml.api.XACML3;
-import com.att.research.xacml.std.annotations.RequestParser;
-import com.google.gson.Gson;
-
-import java.util.ArrayList;
-import java.util.Arrays;
+import com.att.research.xacml.std.IdentifierImpl;
+import com.att.research.xacml.util.XACMLPolicyWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-
+import lombok.Setter;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
-
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.endpoints.parameters.RestServerParameters;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardYamlCoder;
 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 import org.onap.policy.models.decisions.concepts.DecisionResponse;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
+import org.onap.policy.pdp.xacml.application.common.OnapObligation;
+import org.onap.policy.pdp.xacml.application.common.PolicyApiCaller;
+import org.onap.policy.pdp.xacml.application.common.PolicyApiException;
 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
 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.ToscaPolicyTranslatorUtils;
+import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
+import org.onap.policy.pdp.xacml.application.common.matchable.MatchableCallback;
+import org.onap.policy.pdp.xacml.application.common.matchable.MatchablePolicyType;
+import org.onap.policy.pdp.xacml.application.common.matchable.MatchableProperty;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class StdMatchableTranslator implements ToscaPolicyTranslator {
+/**
+ * This standard matchable translator uses Policy Types that contain "matchable" field in order
+ * to translate policies.
+ *
+ * @author pameladragosh
+ *
+ */
+public class StdMatchableTranslator  extends StdBaseTranslator implements MatchableCallback {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class);
+    private static final StandardYamlCoder standardYamlCoder = new StandardYamlCoder();
+
+    private final Map<ToscaConceptIdentifier, ToscaServiceTemplate> matchablePolicyTypes = new HashMap<>();
+    private final Map<ToscaConceptIdentifier, MatchablePolicyType> matchableCache = new HashMap<>();
+
+    @Setter
+    private RestServerParameters apiRestParameters;
+    @Setter
+    private Path pathForData;
 
     public StdMatchableTranslator() {
         super();
     }
 
     @Override
-    public Request convertRequest(DecisionRequest request) {
-        LOGGER.debug("Converting Request {}", request);
+    public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
+        LOGGER.info("Converting Request {}", request);
         try {
-            return RequestParser.parseRequest(StdMatchablePolicyRequest.createInstance(request));
-        } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
-            LOGGER.error("Failed to convert DecisionRequest: {}", e);
+            return StdMatchablePolicyRequest.createInstance(request);
+        } catch (XacmlApplicationException e) {
+            throw new ToscaPolicyConversionException("Failed to convert DecisionRequest", e);
         }
+    }
+
+    /**
+     * scanObligations - scans the list of obligations and make appropriate method calls to process
+     * obligations.
+     *
+     * @param obligations Collection of obligation objects
+     * @param decisionResponse DecisionResponse object used to store any results from obligations.
+     */
+    @Override
+    protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
         //
-        // TODO throw exception
+        // Implementing a crude "closest match" on the results, which means we will strip out
+        // any policies that has the lower weight than any of the others.
         //
-        return null;
+        // Most likely these are "default" policies with a weight of zero, but not always.
+        //
+        // It is possible to have multiple policies with an equal weight, that is desired.
+        //
+        // So we need to track each policy type separately and the weights for each policy.
+        //
+        // policy-type -> weight -> List({policy-id, policy-content}, {policy-id, policy-content})
+        //
+        Map<String, Map<Integer, List<Pair<String, Map<String, Object>>>>> closestMatches = new LinkedHashMap<>();
+        //
+        // Now scan the list of obligations
+        //
+        for (Obligation obligation : obligations) {
+            Identifier obligationId = obligation.getId();
+            LOGGER.info("Obligation: {}", obligationId);
+            if (ToscaDictionary.ID_OBLIGATION_REST_BODY.equals(obligationId)) {
+                scanClosestMatchObligation(closestMatches, obligation);
+            } else {
+                LOGGER.warn("Unsupported Obligation Id {}", obligation.getId());
+            }
+        }
+        //
+        // Now add all the policies to the DecisionResponse
+        //
+        closestMatches.forEach((thePolicyType, weightMap) ->
+            weightMap.forEach((weight, policies) ->
+                policies.forEach(policy -> {
+                    LOGGER.info("Policy {}", policy);
+                    decisionResponse.getPolicies().put(policy.getLeft(), policy.getRight());
+                })
+            )
+        );
     }
 
     @Override
-    public DecisionResponse convertResponse(Response xacmlResponse) {
-        LOGGER.debug("Converting Response {}", xacmlResponse);
-        DecisionResponse decisionResponse = new DecisionResponse();
+    protected void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse) {
+        LOGGER.warn("scanAdvice not supported by {}", this.getClass());
+    }
+
+    /**
+     * scanClosestMatchObligation - scans for the obligation specifically holding policy
+     * contents and their details.
+     *
+     * @param closestMatches Map holding the current set of highest weight policy types
+     * @param obligation Obligation object
+     */
+    protected void scanClosestMatchObligation(
+            Map<String, Map<Integer, List<Pair<String, Map<String, Object>>>>> closestMatches, Obligation obligation) {
         //
-        // Iterate through all the results
+        // Create our OnapObligation object
         //
-        for (Result xacmlResult : xacmlResponse.getResults()) {
+        OnapObligation onapObligation = new OnapObligation(obligation);
+        //
+        // All 4 *should* be there
+        //
+        if (onapObligation.getPolicyId() == null || onapObligation.getPolicyContent() == null
+                || onapObligation.getPolicyType() == null || onapObligation.getWeight() == null) {
+            LOGGER.error("Missing an expected attribute in obligation.");
+            return;
+        }
+        //
+        // Save the values
+        //
+        String policyId = onapObligation.getPolicyId();
+        String policyType = onapObligation.getPolicyType();
+        Map<String, Object> policyContent = onapObligation.getPolicyContentAsMap();
+        int policyWeight = onapObligation.getWeight();
+        //
+        // If the Policy Type exists, get the weight map.
+        //
+        Map<Integer, List<Pair<String, Map<String, Object>>>> weightMap = closestMatches.get(policyType);
+        if (weightMap != null) {
             //
-            // Check the result
+            // Only need to check first one - as we will ensure there is only one weight
             //
-            if (xacmlResult.getDecision() == Decision.PERMIT) {
-                //
-                // Setup policies
+            Entry<Integer, List<Pair<String, Map<String, Object>>>> firstEntry =
+                    weightMap.entrySet().iterator().next();
+            if (policyWeight < firstEntry.getKey()) {
                 //
-                decisionResponse.setPolicies(new ArrayList<>());
+                // Existing policies have a greater weight, so we will not add it
                 //
-                // Go through obligations
+                LOGGER.info("{} is lesser weight {} than current policies, will not return it", policyWeight,
+                        firstEntry.getKey());
+            } else if (firstEntry.getKey().equals(policyWeight)) {
                 //
-                scanObligations(xacmlResult.getObligations(), decisionResponse);
-            }
-            if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
+                // Same weight - we will add it
                 //
-                // There is no policy
-                //
-                decisionResponse.setPolicies(new ArrayList<>());
-            }
-            if (xacmlResult.getDecision() == Decision.DENY
-                    || xacmlResult.getDecision() == Decision.INDETERMINATE) {
-                //
-                // TODO we have to return an ErrorResponse object instead
-                //
-                decisionResponse.setStatus("A better error message");
-            }
-        }
-
-        return decisionResponse;
-    }
-
-    protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
-        for (Obligation obligation : obligations) {
-            LOGGER.debug("Obligation: {}", obligation);
-            for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
-                LOGGER.debug("Attribute Assignment: {}", assignment);
+                LOGGER.info("Same weight {}, adding policy", policyWeight);
+                firstEntry.getValue().add(Pair.of(policyId, policyContent));
+            } else {
                 //
-                // We care about the content attribute
+                // The weight is greater, so we need to remove the other policies
+                // and point to this one.
                 //
-                if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS
-                        .equals(assignment.getAttributeId())) {
-                    //
-                    // The contents are in Json form
-                    //
-                    Object stringContents = assignment.getAttributeValue().getValue();
-                    if (LOGGER.isDebugEnabled()) {
-                        LOGGER.debug("Policy contents: {}{}", System.lineSeparator(), stringContents);
-                    }
-                    //
-                    // Let's parse it into a map using Gson
-                    //
-                    Gson gson = new Gson();
-                    @SuppressWarnings("unchecked")
-                    Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
-                    decisionResponse.getPolicies().add(result);
-                }
+                LOGGER.info("New policy has greater weight {}, replacing {}", policyWeight, firstEntry.getKey());
+                List<Pair<String, Map<String, Object>>> listPolicies = new LinkedList<>();
+                listPolicies.add(Pair.of(policyId, policyContent));
+                weightMap.clear();
+                weightMap.put(policyWeight, listPolicies);
             }
+        } else {
+            //
+            // Create a new entry
+            //
+            LOGGER.info("New entry {} weight {}", policyType, policyWeight);
+            List<Pair<String, Map<String, Object>>> listPolicies = new LinkedList<>();
+            listPolicies.add(Pair.of(policyId, policyContent));
+            Map<Integer, List<Pair<String, Map<String, Object>>>> newWeightMap = new LinkedHashMap<>();
+            newWeightMap.put(policyWeight, listPolicies);
+            closestMatches.put(policyType, newWeightMap);
         }
-
     }
 
     @Override
-    public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
+    public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
+        //
+        // Get the TOSCA Policy Type for this policy
+        //
+        ToscaServiceTemplate toscaPolicyTypeTemplate = this.findPolicyType(toscaPolicy.getTypeIdentifier());
+        //
+        // If we don't have any TOSCA policy types, then we cannot know
+        // which properties are matchable.
+        //
+        if (toscaPolicyTypeTemplate == null) {
+            throw new ToscaPolicyConversionException(
+                    "Cannot retrieve Policy Type definition for policy " + toscaPolicy.getName());
+        }
         //
         // Policy name should be at the root
         //
-        String policyName = toscaPolicy.getMetadata().get("policy-id");
+        String policyName = toscaPolicy.getMetadata().get(POLICY_ID);
         //
         // Set it as the policy ID
         //
@@ -173,25 +266,17 @@ public class StdMatchableTranslator implements ToscaPolicyTranslator {
         //
         // There should be a metadata section
         //
-        this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
+        fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
         //
         // Set the combining rule
         //
         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
         //
-        // Generate the TargetType
-        //
-        newPolicyType.setTarget(generateTargetType(toscaPolicy.getProperties()));
+        // Generate the TargetType - the policy should not be evaluated
+        // unless all the matchable properties it cares about are matched.
         //
-        // Now create the Permit Rule
-        // No target since the policy has a target
-        // With obligations.
-        //
-        RuleType rule = new RuleType();
-        rule.setDescription("Default is to PERMIT if the policy matches.");
-        rule.setRuleId(policyName + ":rule");
-        rule.setEffect(EffectType.PERMIT);
-        rule.setTarget(new TargetType());
+        Pair<TargetType, Integer> pairGenerated = generateTargetType(toscaPolicy, toscaPolicyTypeTemplate);
+        newPolicyType.setTarget(pairGenerated.getLeft());
         //
         // Now represent the policy as Json
         //
@@ -200,154 +285,327 @@ public class StdMatchableTranslator implements ToscaPolicyTranslator {
         try {
             jsonPolicy = coder.encode(toscaPolicy);
         } catch (CoderException e) {
-            LOGGER.error("Failed to encode policy to json", e);
-            throw new ToscaPolicyConversionException(e);
+            throw new ToscaPolicyConversionException("Failed to encode policy to json", e);
         }
-        addObligation(rule, jsonPolicy);
+        //
+        // Add it as an obligation
+        //
+        addObligation(newPolicyType, policyName, jsonPolicy, pairGenerated.getRight(), toscaPolicy.getType());
+        //
+        // Now create the Permit Rule.
+        //
+        RuleType rule = new RuleType();
+        rule.setDescription("Default is to PERMIT if the policy matches.");
+        rule.setRuleId(policyName + ":rule");
+        rule.setEffect(EffectType.PERMIT);
+        rule.setTarget(new TargetType());
+        //
+        // The rule contains the Condition which adds logic for
+        // optional policy-type filtering.
+        //
+        rule.setCondition(generateConditionForPolicyType(toscaPolicy.getType()));
         //
         // Add the rule to the policy
         //
         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
         //
-        // Return our new policy
+        // Log output of the policy
+        //
+        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            XACMLPolicyWriter.writePolicyFile(os, newPolicyType);
+            LOGGER.info("{}", os);
+        } catch (IOException e) {
+            LOGGER.error("Failed to create byte array stream", e);
+        }
+        //
+        // Done
         //
         return newPolicyType;
     }
 
+    @Override
+    public ToscaPolicyType retrievePolicyType(String derivedFrom) {
+        ToscaServiceTemplate template = this.findPolicyType(new ToscaConceptIdentifier(derivedFrom, "1.0.0"));
+        if (template == null) {
+            LOGGER.error("Could not retrieve Policy Type {}", derivedFrom);
+            return null;
+        }
+        return template.getPolicyTypes().get(derivedFrom);
+    }
+
+    @Override
+    public ToscaDataType retrieveDataType(String datatype) {
+        //
+        // Our outer class is not storing the current template being scanned
+        //
+        LOGGER.error("this retrieveDataType should not be called.");
+        return null;
+    }
+
+    private class MyMatchableCallback implements MatchableCallback {
+        private StdMatchableTranslator translator;
+        private ToscaServiceTemplate template;
+
+        public MyMatchableCallback(StdMatchableTranslator translator, ToscaServiceTemplate template) {
+            this.translator = translator;
+            this.template = template;
+        }
+
+        @Override
+        public ToscaPolicyType retrievePolicyType(String derivedFrom) {
+            ToscaPolicyType policyType = this.template.getPolicyTypes().get(derivedFrom);
+            if (policyType != null) {
+                return policyType;
+            }
+            return translator.retrievePolicyType(derivedFrom);
+        }
+
+        @Override
+        public ToscaDataType retrieveDataType(String datatype) {
+            return this.template.getDataTypes().get(datatype);
+        }
+
+    }
+
     /**
-     * From the TOSCA metadata section, pull in values that are needed into the XACML policy.
+     * For generating target type, we scan for matchable properties
+     * and use those to build the policy.
      *
-     * @param policy Policy Object to store the metadata
-     * @param map The Metadata TOSCA Map
-     * @return Same Policy Object
-     * @throws ToscaPolicyConversionException If there is something missing from the metadata
+     * @param policy Tosca Policy to generate Target Type
+     * @param template Toca Template
+     * @return {@code Pair<TargetType, Integer>} Returns a TargetType and a Total Weight of matchables.
      */
-    protected PolicyType fillMetadataSection(PolicyType policy,
-            Map<String, String> map) throws ToscaPolicyConversionException {
-        if (! map.containsKey("policy-id")) {
-            throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id");
-        } else {
+    protected Pair<TargetType, Integer> generateTargetType(ToscaPolicy policy, ToscaServiceTemplate template) {
+        //
+        // Our return object
+        //
+        TargetType target = new TargetType();
+        //
+        // See if we have a matchable in the cache already
+        //
+        MatchablePolicyType matchablePolicyType = matchableCache.get(policy.getTypeIdentifier());
+        //
+        // If not found, create one
+        //
+        if (matchablePolicyType == null) {
             //
-            // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
+            // Our callback
             //
-        }
-        if (! map.containsKey("policy-version")) {
-            throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
-        } else {
+            MyMatchableCallback myCallback = new MyMatchableCallback(this, template);
+            //
+            // Create the matchable
+            //
+            matchablePolicyType = new MatchablePolicyType(
+                    template.getPolicyTypes().get(policy.getType()), myCallback);
             //
-            // Add in the Policy Version
+            // Cache it
             //
-            policy.setVersion(map.get("policy-version").toString());
+            matchableCache.put(policy.getTypeIdentifier(), matchablePolicyType);
         }
-        return policy;
+        //
+        // Fill in the target type with potential matchables
+        //
+        try {
+            fillTargetTypeWithMatchables(target, matchablePolicyType, policy.getProperties());
+        } catch (ToscaPolicyConversionException e) {
+            LOGGER.error("Could not generate target type", e);
+        }
+        //
+        // There may be a case for default policies there is no weight - need to clean
+        // up the target then else PDP will report bad policy missing AnyOf
+        //
+        int weight = calculateWeight(target);
+        LOGGER.debug("Weight is {} for policy {}", weight, policy.getName());
+        //
+        // Assume the number of AllOf's is the weight for now
+        //
+        return Pair.of(target, weight);
     }
 
-    /**
-     * For generating target type, we are making an assumption that the
-     * policyScope and policyType are the fields that OOF wants to match on.
-     *
-     * <P>In the future, we would need to receive the Policy Type specification
-     * from the PAP so we can dynamically see which fields are matchable.
-     *
-     * <P>Note: I am making an assumption that the matchable fields are what
-     * the OOF wants to query a policy on.
-     *
-     * @param properties Properties section of policy
-     * @return TargetType object
-     */
     @SuppressWarnings("unchecked")
-    protected TargetType generateTargetType(Map<String, Object> properties) {
-        TargetType targetType = new TargetType();
-        //
-        // Iterate the properties
-        //
+    protected void fillTargetTypeWithMatchables(TargetType target, MatchablePolicyType matchablePolicyType,
+            Map<String, Object> properties) throws ToscaPolicyConversionException {
         for (Entry<String, Object> entrySet : properties.entrySet()) {
+            String propertyName = entrySet.getKey();
+            Object propertyValue = entrySet.getValue();
+            MatchableProperty matchable = matchablePolicyType.get(propertyName);
+            if (matchable != null) {
+                //
+                // Construct attribute id
+                //
+                Identifier id = new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + propertyName);
+                //
+                // Depending on what type it is, add it into the target
+                //
+                ToscaPolicyTranslatorUtils.buildAndAppendTarget(target,
+                        matchable.getType().generate(propertyValue, id));
+
+                continue;
+            }
             //
-            // Find policyScope and policyType
+            // Here is the special case where we look for a Collection of values that may
+            // contain potential matchables
             //
-            if (entrySet.getKey().equals("policyScope")) {
-                LOGGER.debug("Found policyScope: {}", entrySet.getValue());
-                if (entrySet.getValue() instanceof Collection) {
-                    targetType.getAnyOf().add(generateMatches((Collection<Object>) entrySet.getValue(),
-                            ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY));
-                } else if (entrySet.getValue() instanceof String) {
-                    targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()),
-                            ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY));
+            if (propertyValue instanceof List) {
+                for (Object listValue : ((List<?>) propertyValue)) {
+                    if (listValue instanceof Map) {
+                        fillTargetTypeWithMatchables(target, matchablePolicyType, (Map<String, Object>) listValue);
+                    }
                 }
+            } else if (propertyValue instanceof Map) {
+                fillTargetTypeWithMatchables(target, matchablePolicyType, (Map<String, Object>) propertyValue);
             }
-            if (entrySet.getKey().equals("policyType")) {
-                LOGGER.debug("Found policyType: {}", entrySet.getValue());
-                if (entrySet.getValue() instanceof Collection) {
-                    targetType.getAnyOf().add(generateMatches((Collection<Object>) entrySet.getValue(),
-                            ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY));
-                } else if (entrySet.getValue() instanceof String) {
-                    targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()),
-                            ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY));
-                }
+        }
+    }
+
+    protected int calculateWeight(TargetType target) {
+        int weight = 0;
+        for (AnyOfType anyOf : target.getAnyOf()) {
+            for (AllOfType allOf : anyOf.getAllOf()) {
+                weight += allOf.getMatch().size();
             }
         }
 
-        return targetType;
+        return weight;
     }
 
-    protected AnyOfType generateMatches(Collection<Object> matchables, Identifier attributeId) {
+    /**
+     * findPolicyType - given the ToscaConceptIdentifier, finds it in memory, or
+     * then tries to find it either locally on disk or pull it from the Policy
+     * Lifecycle API the given TOSCA Policy Type.
+     *
+     * @param policyTypeId ToscaConceptIdentifier to find
+     * @return ToscaPolicyType object. Can be null if failure.
+     */
+    protected ToscaServiceTemplate findPolicyType(ToscaConceptIdentifier policyTypeId) {
         //
-        // This is our outer AnyOf - which is an OR
+        // Is it loaded in memory?
         //
-        AnyOfType anyOf = new AnyOfType();
-        for (Object matchable : matchables) {
+        ToscaServiceTemplate policyTemplate = this.matchablePolicyTypes.get(policyTypeId);
+        if (policyTemplate == null)  {
             //
-            // Create a match for this
+            // Load the policy
             //
-            MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
-                    XACML3.ID_FUNCTION_STRING_EQUAL,
-                    matchable.toString(),
-                    XACML3.ID_DATATYPE_STRING,
-                    attributeId,
-                    XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+            policyTemplate = this.loadPolicyType(policyTypeId);
             //
-            // Now create an anyOf (OR)
+            // Save it
             //
-            anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
+            if (policyTemplate != null) {
+                this.matchablePolicyTypes.put(policyTypeId, policyTemplate);
+            }
         }
-        return anyOf;
+        //
+        // Yep return it
+        //
+        return policyTemplate;
     }
 
-    protected RuleType addObligation(RuleType rule, String jsonPolicy) {
+    /**
+     * loadPolicyType - Tries to load the given ToscaConceptIdentifier from local
+     * storage. If it does not exist, will then attempt to pull from Policy Lifecycle
+     * API.
+     *
+     * @param policyTypeId ToscaConceptIdentifier input
+     * @return ToscaPolicyType object. Null if failure.
+     */
+    protected ToscaServiceTemplate loadPolicyType(ToscaConceptIdentifier policyTypeId) {
+        //
+        // Construct what the file name should be
+        //
+        Path policyTypePath = this.constructLocalFilePath(policyTypeId);
+        //
+        // See if it exists
+        //
+        byte[] bytes;
+        try {
+            //
+            // If it exists locally, read the bytes in
+            //
+            bytes = Files.readAllBytes(policyTypePath);
+        } catch (IOException e) {
+            //
+            // Does not exist locally, so let's GET it from the policy api
+            //
+            LOGGER.error("PolicyType not found in data area yet {}", policyTypePath, e);
+            //
+            // So let's pull it from API REST call and save it locally
+            //
+            return this.pullPolicyType(policyTypeId, policyTypePath);
+        }
         //
-        // Convert the YAML Policy to JSON Object
+        // Success - we have read locally the policy type. Now bring it into our
+        // return object.
         //
-        if (LOGGER.isDebugEnabled()) {
-            LOGGER.debug("JSON Optimization Policy {}{}", System.lineSeparator(), jsonPolicy);
+        LOGGER.info("Read in local policy type {}", policyTypePath.toAbsolutePath());
+        try {
+            //
+            // Decode the template
+            //
+            ToscaServiceTemplate template = standardYamlCoder.decode(new String(bytes, StandardCharsets.UTF_8),
+                    ToscaServiceTemplate.class);
+            //
+            // Ensure all the fields are setup correctly
+            //
+            JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
+            jtst.fromAuthorative(template);
+            return jtst.toAuthorative();
+        } catch (CoderException e) {
+            LOGGER.error("Failed to decode tosca template for {}", policyTypePath, e);
         }
         //
-        // Create an AttributeValue for it
+        // Hopefully we never get here
         //
-        AttributeValueType value = new AttributeValueType();
-        value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
-        value.getContent().add(jsonPolicy.toString());
+        LOGGER.error("Failed to find/load policy type {}", policyTypeId);
+        return null;
+    }
+
+    /**
+     * pullPolicyType - pulls the given ToscaConceptIdentifier from the Policy Lifecycle API.
+     * If successful, will store it locally given the policyTypePath.
+     *
+     * @param policyTypeId ToscaConceptIdentifier
+     * @param policyTypePath Path object to store locally
+     * @return ToscaPolicyType object. Null if failure.
+     */
+    protected synchronized ToscaServiceTemplate pullPolicyType(ToscaConceptIdentifier policyTypeId,
+            Path policyTypePath) {
         //
-        // Create our AttributeAssignmentExpression where we will
-        // store the contents of the policy in JSON format.
+        // This is what we return
         //
-        AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType();
-        expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue());
-        ObjectFactory factory = new ObjectFactory();
-        expressionType.setExpression(factory.createAttributeValue(value));
+        ToscaServiceTemplate policyTemplate = null;
+        try {
+            PolicyApiCaller api = new PolicyApiCaller(this.apiRestParameters);
+
+            policyTemplate = api.getPolicyType(policyTypeId);
+        } catch (PolicyApiException e) {
+            LOGGER.error("Failed to make API call", e);
+            LOGGER.error("parameters: {} ", this.apiRestParameters);
+            return null;
+        }
+        LOGGER.info("Successfully pulled {}", policyTypeId);
         //
-        // Create an ObligationExpression for it
+        // Store it locally
         //
-        ObligationExpressionType obligation = new ObligationExpressionType();
-        obligation.setFulfillOn(EffectType.PERMIT);
-        obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
-        obligation.getAttributeAssignmentExpression().add(expressionType);
+        try {
+            standardYamlCoder.encode(policyTypePath.toFile(), policyTemplate);
+        } catch (CoderException e) {
+            LOGGER.error("Failed to store {} locally to {}", policyTypeId, policyTypePath, e);
+        }
         //
-        // Now we can add it into the rule
+        // Done return the policy type
         //
-        ObligationExpressionsType obligations = new ObligationExpressionsType();
-        obligations.getObligationExpression().add(obligation);
-        rule.setObligationExpressions(obligations);
-        return rule;
+        return policyTemplate;
     }
 
+    /**
+     * constructLocalFilePath - common method to ensure the name of the local file for the
+     * policy type is the same.
+     *
+     * @param policyTypeId ToscaConceptIdentifier
+     * @return Path object
+     */
+    protected Path constructLocalFilePath(ToscaConceptIdentifier policyTypeId) {
+        return Paths.get(this.pathForData.toAbsolutePath().toString(), policyTypeId.getName() + "-"
+                + policyTypeId.getVersion() + ".yaml");
+    }
 }