* ============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.IdentifierImpl;
-import com.att.research.xacml.std.annotations.RequestParser;
import com.att.research.xacml.util.XACMLPolicyWriter;
-import com.google.gson.Gson;
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.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
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.onap.policy.common.endpoints.parameters.RestServerParameters;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
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.ToscaPolicyTypeIdentifier;
-import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty;
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;
* @author pameladragosh
*
*/
-public class StdMatchableTranslator implements ToscaPolicyTranslator {
+public class StdMatchableTranslator extends StdBaseTranslator implements MatchableCallback {
private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class);
- private static final String POLICY_ID = "policy-id";
- private static final StandardCoder standardCoder = new StandardCoder();
+ private static final StandardYamlCoder standardYamlCoder = new StandardYamlCoder();
+
+ private final Map<ToscaConceptIdentifier, ToscaServiceTemplate> matchablePolicyTypes = new HashMap<>();
+ private final Map<ToscaConceptIdentifier, MatchablePolicyType> matchableCache = new HashMap<>();
- private final Map<ToscaPolicyTypeIdentifier, ToscaPolicyType> matchablePolicyTypes = new HashMap<>();
@Setter
- private RestServerParameters apiRestParameters;
+ private BusTopicParams apiRestParameters;
@Setter
private Path pathForData;
}
@Override
- public Request convertRequest(DecisionRequest request) {
+ public Request convertRequest(DecisionRequest request) throws ToscaPolicyConversionException {
LOGGER.info("Converting Request {}", request);
try {
return StdMatchablePolicyRequest.createInstance(request);
- } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
- LOGGER.error("Failed to convert DecisionRequest: {}", e);
+ } 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.info("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) {
+ //
+ // Create our OnapObligation object
+ //
+ 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;
+ }
//
- // Setup policies
+ // Save the values
//
- decisionResponse.setPolicies(new HashMap<>());
+ String policyId = onapObligation.getPolicyId();
+ String policyType = onapObligation.getPolicyType();
+ Map<String, Object> policyContent = onapObligation.getPolicyContentAsMap();
+ int policyWeight = onapObligation.getWeight();
//
- // Iterate through all the results
+ // If the Policy Type exists, get the weight map.
//
- for (Result xacmlResult : xacmlResponse.getResults()) {
+ 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) {
+ Entry<Integer, List<Pair<String, Map<String, Object>>>> firstEntry =
+ weightMap.entrySet().iterator().next();
+ if (policyWeight < firstEntry.getKey()) {
//
- // Go through obligations
+ // Existing policies have a greater weight, so we will not add it
//
- scanObligations(xacmlResult.getObligations(), decisionResponse);
- }
- if (xacmlResult.getDecision() == Decision.DENY
- || xacmlResult.getDecision() == Decision.INDETERMINATE) {
+ LOGGER.info("{} is lesser weight {} than current policies, will not return it", policyWeight,
+ firstEntry.getKey());
+ } else if (firstEntry.getKey().equals(policyWeight)) {
//
- // TODO we have to return an ErrorResponse object instead
+ // Same weight - we will add it
//
- decisionResponse.setStatus("A better error message");
- }
- }
-
- return decisionResponse;
- }
-
- protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
- for (Obligation obligation : obligations) {
- LOGGER.info("Obligation: {}", obligation);
- for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
- LOGGER.info("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.isInfoEnabled()) {
- LOGGER.info("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);
- //
- // Find the metadata section
- //
- @SuppressWarnings("unchecked")
- Map<String, Object> metadata = (Map<String, Object>) result.get("metadata");
- if (metadata != null) {
- decisionResponse.getPolicies().put(metadata.get(POLICY_ID).toString(), result);
- } else {
- LOGGER.error("Missing metadata section in policy contained in obligation.");
- }
- }
+ 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
//
- Collection<ToscaPolicyType> policyTypes = this.getPolicyTypes(toscaPolicy.getTypeIdentifier());
+ ToscaServiceTemplate toscaPolicyTypeTemplate = this.findPolicyType(toscaPolicy.getTypeIdentifier());
//
- // If we don't have any policy types, then we cannot know
+ // If we don't have any TOSCA policy types, then we cannot know
// which properties are matchable.
//
- if (policyTypes.isEmpty()) {
+ if (toscaPolicyTypeTemplate == null) {
throw new ToscaPolicyConversionException(
"Cannot retrieve Policy Type definition for policy " + toscaPolicy.getName());
}
//
// 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(), policyTypes));
+ // 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
//
} catch (CoderException 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);
} catch (IOException e) {
LOGGER.error("Failed to create byte array stream", e);
}
+ //
+ // Done
+ //
return newPolicyType;
}
- /**
- * From the TOSCA metadata section, pull in values that are needed into the XACML 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
- */
- 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 {
- //
- // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field
- //
- }
- if (! map.containsKey("policy-version")) {
- throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
- } else {
- //
- // Add in the Policy Version
- //
- policy.setVersion(map.get("policy-version"));
+ @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 policy;
+ return template.getPolicyTypes().get(derivedFrom);
}
- /**
- * For generating target type, we are scan for matchable properties
- * and use those to build the policy.
- *
- * @param properties Properties section of policy
- * @param policyTypes Collection of policy Type to find matchable metadata
- * @return TargetType object
- */
- @SuppressWarnings("unchecked")
- protected TargetType generateTargetType(Map<String, Object> properties, Collection<ToscaPolicyType> policyTypes) {
- TargetType targetType = new TargetType();
+ @Override
+ public ToscaDataType retrieveDataType(String datatype) {
//
- // Iterate the properties
+ // Our outer class is not storing the current template being scanned
//
- for (Entry<String, Object> entrySet : properties.entrySet()) {
- //
- // Find matchable properties
- //
- if (isMatchable(entrySet.getKey(), policyTypes)) {
- LOGGER.info("Found matchable property {}", entrySet.getValue());
- if (entrySet.getValue() instanceof Collection) {
- AnyOfType anyOf = generateMatches((Collection<Object>) entrySet.getValue(),
- new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + entrySet.getKey()));
- if (! anyOf.getAllOf().isEmpty()) {
- targetType.getAnyOf().add(anyOf);
- }
- } else {
- AnyOfType anyOf = generateMatches(Arrays.asList(entrySet.getValue()),
- new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + entrySet.getKey()));
- if (! anyOf.getAllOf().isEmpty()) {
- targetType.getAnyOf().add(anyOf);
- }
- }
- }
- }
-
- return targetType;
+ LOGGER.error("this retrieveDataType should not be called.");
+ return null;
}
- protected boolean isMatchable(String propertyName, Collection<ToscaPolicyType> policyTypes) {
- for (ToscaPolicyType policyType : policyTypes) {
- for (Entry<String, ToscaProperty> propertiesEntry : policyType.getProperties().entrySet()) {
- if (! propertiesEntry.getKey().equals(propertyName)
- || propertiesEntry.getValue().getMetadata() == null) {
- continue;
- }
- for (Entry<String, String> entrySet : propertiesEntry.getValue().getMetadata().entrySet()) {
- if (entrySet.getKey().equals("matchable") && entrySet.getValue().equals("true")) {
- return true;
- }
- }
- }
+ private class MyMatchableCallback implements MatchableCallback {
+ private StdMatchableTranslator translator;
+ private ToscaServiceTemplate template;
+
+ public MyMatchableCallback(StdMatchableTranslator translator, ToscaServiceTemplate template) {
+ this.translator = translator;
+ this.template = template;
}
- return false;
- }
- protected AnyOfType generateMatches(Collection<Object> matchables, Identifier attributeId) {
- //
- // This is our outer AnyOf - which is an OR
- //
- AnyOfType anyOf = new AnyOfType();
- for (Object matchable : matchables) {
- //
- // Default to string
- //
- Identifier idFunction = XACML3.ID_FUNCTION_STRING_EQUAL;
- Identifier idDatatype = XACML3.ID_DATATYPE_STRING;
- //
- // See if we are another datatype
- //
- // TODO We should add datetime support. But to do that we need
- // probably more metadata to describe how that would be translated.
- //
- if (matchable instanceof Integer) {
- idFunction = XACML3.ID_FUNCTION_INTEGER_EQUAL;
- idDatatype = XACML3.ID_DATATYPE_INTEGER;
- } else if (matchable instanceof Double) {
- idFunction = XACML3.ID_FUNCTION_DOUBLE_EQUAL;
- idDatatype = XACML3.ID_DATATYPE_DOUBLE;
- } else if (matchable instanceof Boolean) {
- idFunction = XACML3.ID_FUNCTION_BOOLEAN_EQUAL;
- idDatatype = XACML3.ID_DATATYPE_BOOLEAN;
+ @Override
+ public ToscaPolicyType retrievePolicyType(String derivedFrom) {
+ ToscaPolicyType policyType = this.template.getPolicyTypes().get(derivedFrom);
+ if (policyType != null) {
+ return policyType;
}
- //
- // Create a match for this
- //
- MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
- idFunction,
- matchable.toString(),
- idDatatype,
- attributeId,
- XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
- //
- // Now create an anyOf (OR)
- //
- anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
+ return translator.retrievePolicyType(derivedFrom);
}
- return anyOf;
- }
- protected RuleType addObligation(RuleType rule, String jsonPolicy) {
- //
- // Convert the YAML Policy to JSON Object
- //
- if (LOGGER.isInfoEnabled()) {
- LOGGER.info("JSON Optimization Policy {}{}", System.lineSeparator(), jsonPolicy);
+ @Override
+ public ToscaDataType retrieveDataType(String datatype) {
+ return this.template.getDataTypes().get(datatype);
}
- //
- // Create an AttributeValue for it
- //
- AttributeValueType value = new AttributeValueType();
- value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
- value.getContent().add(jsonPolicy);
- //
- // Create our AttributeAssignmentExpression where we will
- // store the contents of the policy in JSON format.
- //
- AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType();
- expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue());
- ObjectFactory factory = new ObjectFactory();
- expressionType.setExpression(factory.createAttributeValue(value));
- //
- // Create an ObligationExpression for it
- //
- ObligationExpressionType obligation = new ObligationExpressionType();
- obligation.setFulfillOn(EffectType.PERMIT);
- obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
- obligation.getAttributeAssignmentExpression().add(expressionType);
- //
- // Now we can add it into the rule
- //
- ObligationExpressionsType obligations = new ObligationExpressionsType();
- obligations.getObligationExpression().add(obligation);
- rule.setObligationExpressions(obligations);
- return rule;
- }
+ }
/**
- * Get Policy Type definitions. This could be previously loaded, or could be
- * stored in application path, or may need to be pulled from the API.
- *
+ * For generating target type, we scan for matchable properties
+ * and use those to build the policy.
*
- * @param policyTypeId Policy Type Id
- * @return A list of PolicyTypes
+ * @param properties Properties section of policy
+ * @param policyTypes Collection of policy Type to find matchable metadata
+ * @return {@code Pair<TargetType, Integer>} Returns a TargetType and a Total Weight of matchables.
*/
- private List<ToscaPolicyType> getPolicyTypes(ToscaPolicyTypeIdentifier policyTypeId) {
- //
- // Create identifier from the policy
+ protected Pair<TargetType, Integer> generateTargetType(ToscaPolicy policy, ToscaServiceTemplate template) {
//
- ToscaPolicyTypeIdentifier typeId = new ToscaPolicyTypeIdentifier(policyTypeId);
+ // Our return object
//
- // Find the Policy Type
+ TargetType target = new TargetType();
//
- ToscaPolicyType policyType = findPolicyType(typeId);
- if (policyType == null) {
- return Collections.emptyList();
- }
+ // See if we have a matchable in the cache already
//
- // Create our return object
+ MatchablePolicyType matchablePolicyType = matchableCache.get(policy.getTypeIdentifier());
//
- List<ToscaPolicyType> listTypes = new ArrayList<>();
- listTypes.add(policyType);
+ // If not found, create one
//
- // Look for parent policy types that could also contain matchable properties
- //
- ToscaPolicyType childPolicyType = policyType;
- while (! childPolicyType.getDerivedFrom().startsWith("tosca.policies.Root")) {
- //
- // Create parent policy type id.
+ if (matchablePolicyType == null) {
//
- // We will have to assume the same version between child and the
- // parent policy type it derives from.
+ // Our callback
//
- // Or do we assume 1.0.0?
+ MyMatchableCallback myCallback = new MyMatchableCallback(this, template);
//
- String strDerivedFrom = childPolicyType.getDerivedFrom();
+ // Create the matchable
//
- // Hack that fixes policy/models appending 0.0.0 to the derivedFrom name
+ matchablePolicyType = new MatchablePolicyType(
+ template.getPolicyTypes().get(policy.getType()), myCallback);
//
- if (strDerivedFrom.endsWith("0.0.0")) {
- strDerivedFrom = strDerivedFrom.substring(0, strDerivedFrom.length() - "0.0.0".length() - 1);
- }
- ToscaPolicyTypeIdentifier parentId = new ToscaPolicyTypeIdentifier(strDerivedFrom, "1.0.0");
+ // Cache it
//
- // Find the policy type
- //
- ToscaPolicyType parentPolicyType = findPolicyType(parentId);
- if (parentPolicyType == null) {
- //
- // Probably would be best to throw an exception and
- // return nothing back.
+ matchableCache.put(policy.getTypeIdentifier(), matchablePolicyType);
+ }
+ //
+ // 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);
+ }
+
+ @SuppressWarnings("unchecked")
+ 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) {
//
- // But instead we will log a warning
+ // Construct attribute id
//
- LOGGER.warn("Missing parent policy type - proceeding anyway {}", parentId);
+ Identifier id = new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + propertyName);
//
- // Break the loop
+ // Depending on what type it is, add it into the target
//
- break;
+ ToscaPolicyTranslatorUtils.buildAndAppendTarget(target,
+ matchable.getType().generate(propertyValue, id));
+
+ continue;
}
//
- // Great save it
- //
- listTypes.add(parentPolicyType);
+ // Here is the special case where we look for a Collection of values that may
+ // contain potential matchables
//
- // Move to the next parent
- //
- childPolicyType = parentPolicyType;
+ 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);
+ }
}
+ }
+ protected int calculateWeight(TargetType target) {
+ int weight = 0;
+ for (AnyOfType anyOf : target.getAnyOf()) {
+ for (AllOfType allOf : anyOf.getAllOf()) {
+ weight += allOf.getMatch().size();
+ }
+ }
- return listTypes;
+ return weight;
}
- private ToscaPolicyType findPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
+ /**
+ * 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.
+ */
+ private ToscaServiceTemplate findPolicyType(ToscaConceptIdentifier policyTypeId) {
//
// Is it loaded in memory?
//
- ToscaPolicyType policyType = this.matchablePolicyTypes.get(policyTypeId);
- if (policyType == null) {
+ ToscaServiceTemplate policyTemplate = this.matchablePolicyTypes.get(policyTypeId);
+ if (policyTemplate == null) {
//
// Load the policy
//
- policyType = this.loadPolicyType(policyTypeId);
+ policyTemplate = this.loadPolicyType(policyTypeId);
+ //
+ // Save it
+ //
+ if (policyTemplate != null) {
+ this.matchablePolicyTypes.put(policyTypeId, policyTemplate);
+ }
}
//
// Yep return it
//
- return policyType;
+ return policyTemplate;
}
- private ToscaPolicyType loadPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
+ /**
+ * 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.
+ */
+ private ToscaServiceTemplate loadPolicyType(ToscaConceptIdentifier policyTypeId) {
//
// Construct what the file name should be
//
//
return this.pullPolicyType(policyTypeId, policyTypePath);
}
+ //
+ // Success - we have read locally the policy type. Now bring it into our
+ // return object.
+ //
LOGGER.info("Read in local policy type {}", policyTypePath.toAbsolutePath());
try {
- ToscaServiceTemplate serviceTemplate = standardCoder.decode(new String(bytes, StandardCharsets.UTF_8),
- ToscaServiceTemplate.class);
- JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
- jtst.fromAuthorative(serviceTemplate);
- ToscaServiceTemplate completedJtst = jtst.toAuthorative();
//
- // Search for our Policy Type, there really only should be one but
- // this is returned as a map.
+ // Decode the template
//
- for ( Entry<String, ToscaPolicyType> entrySet : completedJtst.getPolicyTypes().entrySet()) {
- ToscaPolicyType entryPolicyType = entrySet.getValue();
- if (policyTypeId.getName().equals(entryPolicyType.getName())
- && policyTypeId.getVersion().equals(entryPolicyType.getVersion())) {
- LOGGER.info("Found existing local policy type {} {}", entryPolicyType.getName(),
- entryPolicyType.getVersion());
- //
- // Just simply return the policy type right here
- //
- return entryPolicyType;
- } else {
- LOGGER.warn("local policy type contains different name version {} {}", entryPolicyType.getName(),
- entryPolicyType.getVersion());
- }
- }
+ ToscaServiceTemplate template = standardYamlCoder.decode(new String(bytes, StandardCharsets.UTF_8),
+ ToscaServiceTemplate.class);
//
- // This would be an error, if the file stored does not match what its supposed to be
+ // Ensure all the fields are setup correctly
//
- LOGGER.error("Existing policy type file does not contain right name and version");
+ JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
+ jtst.fromAuthorative(template);
+ return jtst.toAuthorative();
} catch (CoderException e) {
LOGGER.error("Failed to decode tosca template for {}", policyTypePath, e);
}
return null;
}
- private synchronized ToscaPolicyType pullPolicyType(ToscaPolicyTypeIdentifier policyTypeId, Path policyTypePath) {
+ /**
+ * 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.
+ */
+ private synchronized ToscaServiceTemplate pullPolicyType(ToscaConceptIdentifier policyTypeId,
+ Path policyTypePath) {
//
// This is what we return
//
- ToscaPolicyType policyType = null;
+ ToscaServiceTemplate policyTemplate = null;
try {
PolicyApiCaller api = new PolicyApiCaller(this.apiRestParameters);
- policyType = api.getPolicyType(policyTypeId);
+ 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);
//
// Store it locally
//
try {
- standardCoder.encode(policyTypePath.toFile(), policyType);
+ standardYamlCoder.encode(policyTypePath.toFile(), policyTemplate);
} catch (CoderException e) {
LOGGER.error("Failed to store {} locally to {}", policyTypeId, policyTypePath, e);
}
//
// Done return the policy type
//
- return policyType;
+ return policyTemplate;
}
- private Path constructLocalFilePath(ToscaPolicyTypeIdentifier policyTypeId) {
+ /**
+ * constructLocalFilePath - common method to ensure the name of the local file for the
+ * policy type is the same.
+ *
+ * @param policyTypeId ToscaConceptIdentifier
+ * @return Path object
+ */
+ private Path constructLocalFilePath(ToscaConceptIdentifier policyTypeId) {
return Paths.get(this.pathForData.toAbsolutePath().toString(), policyTypeId.getName() + "-"
- + policyTypeId.getVersion() + ".json");
+ + policyTypeId.getVersion() + ".yaml");
}
}