diff options
Diffstat (limited to 'applications/common/src/main/java')
5 files changed, 533 insertions, 98 deletions
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapObligation.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapObligation.java new file mode 100644 index 00000000..da2e7f10 --- /dev/null +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapObligation.java @@ -0,0 +1,259 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common; + +import com.att.research.xacml.api.AttributeAssignment; +import com.att.research.xacml.api.Identifier; +import com.att.research.xacml.api.Obligation; +import com.google.gson.Gson; +import java.util.Map; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.ToString; +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.ObjectFactory; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType; + +@Getter +@ToString +public class OnapObligation { + + @Getter(AccessLevel.NONE) + private static final ObjectFactory factory = new ObjectFactory(); + + @Getter(AccessLevel.NONE) + private static final Gson gson = new Gson(); + + private String policyId; + private String policyType; + private String policyContent; + private Integer weight; + + /** + * Constructor from an obligation. + * + * @param obligation Obligation object + */ + public OnapObligation(Obligation obligation) { + // + // Scan through the obligations for them + // + for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { + scanAttribute(assignment); + } + } + + /** + * Constructor for just the policy details. + * + * @param policyId String + * @param policyContent String + */ + public OnapObligation(String policyId, String policyContent) { + this.policyId = policyId; + this.policyContent = policyContent; + } + + + /** + * Constructor for policy details, type and weight. + * + * @param policyId String + * @param policyContent String + * @param policyType String + * @param weight int + */ + public OnapObligation(String policyId, String policyContent, String policyType, Integer weight) { + this.policyId = policyId; + this.policyContent = policyContent; + this.policyType = policyType; + this.weight = weight; + } + + /** + * getPolicyContentAsMap returns the policy as a map for convience. + * + * @return {@code Map<String, Object>} + */ + @SuppressWarnings("unchecked") + public Map<String, Object> getPolicyContentAsMap() { + if (this.policyContent == null) { + return null; + } + return gson.fromJson(this.policyContent, Map.class); + } + + /** + * Generates default obligation using default Permit and Obligation Id. + * + * @return ObligationExpressionType object + */ + public ObligationExpressionType generateObligation() { + return this.generateObligation(EffectType.PERMIT, ToscaDictionary.ID_OBLIGATION_REST_BODY); + } + + /** + * generateObligation - generates an obligation object with the attributes that exist. Note: + * any null values will result in NO attribute assignment for that attribute. + * + * @param effectType EffectType object + * @param obligationId Id for the obligation + * @return ObligationExpressionType object + */ + public ObligationExpressionType generateObligation(EffectType effectType, Identifier obligationId) { + // + // Create an ObligationExpression + // + ObligationExpressionType obligation = new ObligationExpressionType(); + obligation.setFulfillOn(effectType); + obligation.setObligationId(obligationId.stringValue()); + // + // Update the obligation + // + updateObligation(obligation); + // + // Convenience return + // + return obligation; + } + + /** + * Updates an existing Obligation object with the attributes that exist. Note: any null values + * will result in NO attribute assignment for that attribute. + * + * @param obligation ObligationExpressionType object + * @return ObligationExpressionType object + */ + public ObligationExpressionType updateObligation(ObligationExpressionType obligation) { + // + // Add policy-id + // + addOptionalAttributeToObligation(obligation, ToscaDictionary.ID_OBLIGATION_POLICY_ID, + ToscaDictionary.ID_OBLIGATION_POLICY_ID_DATATYPE, + ToscaDictionary.ID_OBLIGATION_POLICY_ID_CATEGORY, + policyId); + // + // Add policy contents + // + addOptionalAttributeToObligation(obligation, ToscaDictionary.ID_OBLIGATION_POLICY_CONTENT, + ToscaDictionary.ID_OBLIGATION_POLICY_CONTENT_DATATYPE, + ToscaDictionary.ID_OBLIGATION_POLICY_CONTENT_CATEGORY, + policyContent); + // + // Add the weight + // + addOptionalAttributeToObligation(obligation, ToscaDictionary.ID_OBLIGATION_POLICY_WEIGHT, + ToscaDictionary.ID_OBLIGATION_POLICY_WEIGHT_DATATYPE, + ToscaDictionary.ID_OBLIGATION_POLICY_WEIGHT_CATEGORY, + weight); + // + // Add the policy type + // + addOptionalAttributeToObligation(obligation, ToscaDictionary.ID_OBLIGATION_POLICY_TYPE, + ToscaDictionary.ID_OBLIGATION_POLICY_TYPE_DATATYPE, + ToscaDictionary.ID_OBLIGATION_POLICY_TYPE_CATEGORY, + policyType); + // + // Return as a convenience + // + return obligation; + } + + /** + * scanAttribute - scans the assignment for a supported obligation assignment. Applications + * can override this class and provide their own custom attribute assignments if desired. + * + * @param assignment AttributeAssignment object + * @return true if found an ONAP supported attribute + */ + protected boolean scanAttribute(AttributeAssignment assignment) { + // + // Check for our supported attributes. Note: Cannot use a switch + // as Identifier isn't a constant. + // + if (ToscaDictionary.ID_OBLIGATION_POLICY_ID.equals(assignment.getAttributeId())) { + policyId = assignment.getAttributeValue().getValue().toString(); + return true; + } else if (ToscaDictionary.ID_OBLIGATION_POLICY_TYPE.equals(assignment.getAttributeId())) { + policyType = assignment.getAttributeValue().getValue().toString(); + return true; + } else if (ToscaDictionary.ID_OBLIGATION_POLICY_CONTENT.equals(assignment.getAttributeId())) { + policyContent = assignment.getAttributeValue().getValue().toString(); + return true; + } else if (ToscaDictionary.ID_OBLIGATION_POLICY_WEIGHT.equals(assignment.getAttributeId())) { + weight = Integer.decode(assignment.getAttributeValue().getValue().toString()); + return true; + } + // + // By returning true, we indicate this isn't an attribute + // supported in the this class. Targeted for applications + // that derive from this class in order to extend it. + // + return false; + } + + /** + * Creates the necessary objects to insert into the obligation, if the value object is not null. + * + * @param obligation Incoming Obligation + * @param id Attribute Id + * @param datatype Attribute's Data type + * @param category Attributes Category + * @param theValue Attribute value + * @return obligation Incoming obligation + */ + protected ObligationExpressionType addOptionalAttributeToObligation(ObligationExpressionType obligation, + Identifier id, Identifier datatype, Identifier category, Object theValue) { + // + // Simple check for null + // + if (theValue == null) { + return obligation; + } + // + // Create an AttributeValue for it + // + AttributeValueType value = new AttributeValueType(); + value.setDataType(datatype.stringValue()); + value.getContent().add(theValue.toString()); + // + // Create our AttributeAssignmentExpression where we will + // store the contents of the policy id. + // + AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType(); + expressionType.setAttributeId(id.stringValue()); + expressionType.setCategory(category.stringValue()); + expressionType.setExpression(factory.createAttributeValue(value)); + // + // Add it to the obligation + // + obligation.getAttributeAssignmentExpression().add(expressionType); + // + // Return as convenience + // + return obligation; + } + +} diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java index 500be2e6..1a899971 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java @@ -112,20 +112,41 @@ public final class ToscaDictionary { public static final Identifier ID_OBLIGATION_REST_BODY = new IdentifierImpl(ID_URN_ONAP, "rest:body"); - public static final Identifier ID_OBLIGATION_POLICY_MONITORING = - new IdentifierImpl(ID_URN_ONAP, ":obligation:monitoring"); + public static final Identifier ID_OBLIGATION_POLICY_CONTENT = + new IdentifierImpl(ID_URN_ONAP, ":obligation:policycontent"); - public static final Identifier ID_OBLIGATION_POLICY_MONITORING_CONTENTS = - new IdentifierImpl(ID_URN_ONAP, ":obligation:monitoring:contents"); + public static final Identifier ID_OBLIGATION_POLICY_CONTENT_CATEGORY = + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE; + + public static final Identifier ID_OBLIGATION_POLICY_CONTENT_DATATYPE = + XACML3.ID_DATATYPE_STRING; - public static final Identifier ID_OBLIGATION_POLICY_MONITORING_CATEGORY = + public static final Identifier ID_OBLIGATION_POLICY_ID = + new IdentifierImpl(ID_URN_ONAP, ":obligation:policyid"); + + public static final Identifier ID_OBLIGATION_POLICY_ID_CATEGORY = XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE; - public static final Identifier ID_OBLIGATION_POLICY_MONITORING_DATATYPE = + public static final Identifier ID_OBLIGATION_POLICY_ID_DATATYPE = XACML3.ID_DATATYPE_STRING; - public static final Identifier ID_OBLIGATION_MONITORING_ISSUER = - new IdentifierImpl(ID_URN_ONAP, "issuer:monitoring"); + public static final Identifier ID_OBLIGATION_POLICY_WEIGHT = + new IdentifierImpl(ID_URN_ONAP, ":obligation:weight"); + + public static final Identifier ID_OBLIGATION_POLICY_WEIGHT_CATEGORY = + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE; + + public static final Identifier ID_OBLIGATION_POLICY_WEIGHT_DATATYPE = + XACML3.ID_DATATYPE_INTEGER; + + public static final Identifier ID_OBLIGATION_POLICY_TYPE = + new IdentifierImpl(ID_URN_ONAP, ":obligation:policytype"); + + public static final Identifier ID_OBLIGATION_POLICY_TYPE_CATEGORY = + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE; + + public static final Identifier ID_OBLIGATION_POLICY_TYPE_DATATYPE = + XACML3.ID_DATATYPE_STRING; diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java index d2d383b9..508bc245 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java @@ -22,24 +22,20 @@ package org.onap.policy.pdp.xacml.application.common.std; -import com.att.research.xacml.api.AttributeAssignment; import com.att.research.xacml.api.Decision; 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.google.gson.Gson; import java.util.Collection; import java.util.HashMap; import java.util.Map; import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType; -import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType; -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; @@ -50,6 +46,7 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType; 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.pdp.xacml.application.common.OnapObligation; 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; @@ -58,16 +55,16 @@ import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class StdBaseTranslator implements ToscaPolicyTranslator { +public abstract class StdBaseTranslator implements ToscaPolicyTranslator { private static final Logger LOGGER = LoggerFactory.getLogger(StdBaseTranslator.class); - private static Gson gson = new Gson(); + private static final ObjectFactory factory = new ObjectFactory(); public static final String POLICY_ID = "policy-id"; public static final String POLICY_VERSION = "policy-version"; @Override public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException { - throw new ToscaPolicyConversionException("Please override converPolicy"); + throw new ToscaPolicyConversionException("Please override convertPolicy"); } @Override @@ -95,8 +92,7 @@ public class StdBaseTranslator implements ToscaPolicyTranslator { // Go through obligations // scanObligations(xacmlResult.getObligations(), decisionResponse); - } else if (xacmlResult.getDecision() == Decision.DENY - || xacmlResult.getDecision() == Decision.INDETERMINATE) { + } else { // // TODO we have to return an ErrorResponse object instead // @@ -109,55 +105,13 @@ public class StdBaseTranslator implements ToscaPolicyTranslator { /** * scanObligations - scans the list of obligations and make appropriate method calls to process - * obligations. + * obligations. This method must be overridden and be implemented for the specific application as + * obligations may have different expected attributes per application. * * @param obligations Collection of obligation objects * @param decisionResponse DecisionResponse object used to store any results from obligations. */ - 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); - processObligationAttribute(assignment, decisionResponse); - } - } - } - - /** - * processObligationAttribute - processes an individual obligation attribute assignment object. - * - * @param assignment AttributeAssignment object - * @param decisionResponse DecisionResponse object used to store any results from attribute assignment. - */ - @SuppressWarnings("unchecked") - protected void processObligationAttribute(AttributeAssignment assignment, DecisionResponse decisionResponse) { - // - // We care about the content attribute - // - if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS - .equals(assignment.getAttributeId())) { - // - // The contents are in Json form - // - Object stringContents = assignment.getAttributeValue().getValue(); - LOGGER.info("DCAE contents: {}{}", XacmlPolicyUtils.LINE_SEPARATOR, stringContents); - // - // Let's parse it into a map using Gson - // - Map<String, Object> result; - result = gson.fromJson(stringContents.toString(), Map.class); - // - // Find the metadata section - // - 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."); - } - } - } + protected abstract void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse); /** * From the TOSCA metadata section, pull in values that are needed into the XACML policy. @@ -196,36 +150,27 @@ public class StdBaseTranslator implements ToscaPolicyTranslator { * But this is fine for now. * * @param <T> RuleType, PolicyType, PolicySetType object + * @Param policyId The policy-id * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object * @param jsonPolicy JSON String representation of policy. + * @param weight Weighting for the policy (optional) * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience. */ - protected <T> T addObligation(T ruleOrPolicy, String jsonPolicy) { + protected <T> T addObligation(T ruleOrPolicy, String policyId, String jsonPolicy, Integer weight, + String policyType) { // // Creating obligation for returning policy // - LOGGER.info("Obligation Policy {}{}", XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy); - // - // Create an AttributeValue for it - // - AttributeValueType value = new AttributeValueType(); - value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue()); - value.getContent().add(jsonPolicy); + LOGGER.info("Obligation Policy id: {} type: {} weight: {} policy:{}{}", policyId, policyType, weight, + XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy); // - // Create our AttributeAssignmentExpression where we will - // store the contents of the policy in JSON format. + // Create our OnapObligation // - AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType(); - expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue()); - ObjectFactory factory = new ObjectFactory(); - expressionType.setExpression(factory.createAttributeValue(value)); + OnapObligation onapObligation = new OnapObligation(policyId, jsonPolicy, policyType, weight); // - // Create an ObligationExpression for it + // Generate the obligation // - ObligationExpressionType obligation = new ObligationExpressionType(); - obligation.setFulfillOn(EffectType.PERMIT); - obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue()); - obligation.getAttributeAssignmentExpression().add(expressionType); + ObligationExpressionType obligation = onapObligation.generateObligation(); // // Now we can add it into the rule/policy/policyset // @@ -237,6 +182,8 @@ public class StdBaseTranslator implements ToscaPolicyTranslator { ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations); } else if (ruleOrPolicy instanceof PolicySetType) { ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations); + } else { + LOGGER.error("Unsupported class for adding obligation {}", ruleOrPolicy.getClass()); } // // Return as a convenience @@ -300,7 +247,6 @@ public class StdBaseTranslator implements ToscaPolicyTranslator { valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); valueZero.getContent().add("0"); // Yes really - represent as a string - ObjectFactory factory = new ObjectFactory(); applyBagSize.getExpression().add(factory.createAttributeDesignator(designator)); ApplyType applyGreaterThan = new ApplyType(); diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java index be0a507e..bcd594fb 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java @@ -23,9 +23,14 @@ package org.onap.policy.pdp.xacml.application.common.std; import com.att.research.xacml.api.DataTypeException; +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.XACML3; import com.att.research.xacml.std.annotations.RequestParser; +import com.google.common.base.Strings; +import java.util.Collection; +import java.util.Map; import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType; import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType; @@ -35,7 +40,9 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.common.utils.coder.StandardCoder; 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.pdp.xacml.application.common.OnapObligation; 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.ToscaPolicyTranslatorUtils; @@ -53,10 +60,23 @@ public class StdCombinedPolicyResultsTranslator extends StdBaseTranslator { @Override public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException { // + // Sanity checks + // + if (toscaPolicy == null) { + throw new ToscaPolicyConversionException("Cannot convert a NULL policy"); + } + if (toscaPolicy.getMetadata() == null) { + throw new ToscaPolicyConversionException("Cannot convert a policy with missing metadata section"); + } + // + // Get the policy Id + // + String policyId = toscaPolicy.getMetadata().get(POLICY_ID); + // // Set it as the policy ID // PolicyType newPolicyType = new PolicyType(); - newPolicyType.setPolicyId(toscaPolicy.getMetadata().get(POLICY_ID)); + newPolicyType.setPolicyId(policyId); // // Optional description // @@ -72,8 +92,7 @@ public class StdCombinedPolicyResultsTranslator extends StdBaseTranslator { // // Generate the TargetType // - TargetType target = this.generateTargetType(toscaPolicy.getMetadata().get(POLICY_ID), - toscaPolicy.getType(), toscaPolicy.getVersion()); + TargetType target = this.generateTargetType(policyId, toscaPolicy.getType(), toscaPolicy.getVersion()); newPolicyType.setTarget(target); // // Now create the Permit Rule @@ -82,7 +101,7 @@ public class StdCombinedPolicyResultsTranslator extends StdBaseTranslator { // RuleType rule = new RuleType(); rule.setDescription("Default is to PERMIT if the policy matches."); - rule.setRuleId(toscaPolicy.getMetadata().get(POLICY_ID) + ":rule"); + rule.setRuleId(policyId + ":rule"); rule.setEffect(EffectType.PERMIT); rule.setTarget(new TargetType()); // @@ -95,7 +114,7 @@ public class StdCombinedPolicyResultsTranslator extends StdBaseTranslator { } catch (CoderException e) { throw new ToscaPolicyConversionException(e); } - addObligation(rule, jsonPolicy); + addObligation(rule, policyId, jsonPolicy, null, toscaPolicy.getType()); // // Add the rule to the policy // @@ -120,6 +139,60 @@ public class StdCombinedPolicyResultsTranslator extends StdBaseTranslator { return null; } + /** + * 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) { + for (Obligation obligation : obligations) { + Identifier obligationId = obligation.getId(); + LOGGER.info("Obligation: {}", obligationId); + if (ToscaDictionary.ID_OBLIGATION_REST_BODY.equals(obligationId)) { + scanContentObligation(obligation, decisionResponse); + } + } + } + + /** + * scanContentObligation - scans the specific obligation for policy-id and policy-content. + * + * @param obligation Obligation incoming obligation object + * @param decisionResponse DecisionResponse object + */ + protected void scanContentObligation(Obligation obligation, DecisionResponse decisionResponse) { + // + // Create our OnapObligation which will scan for attributes + // + OnapObligation onapObligation = new OnapObligation(obligation); + // + // Get the attributes we care about + // + String policyId = onapObligation.getPolicyId(); + Map<String, Object> policyContent = onapObligation.getPolicyContentAsMap(); + // + // Sanity check that we got the attributes we care about. NOTE: This translator + // ensures that these are set when convertPolicy is called. + // + if (! Strings.isNullOrEmpty(policyId) && policyContent != null) { + decisionResponse.getPolicies().put(policyId, policyContent); + } else { + LOGGER.error("Missing obligation policyId {} or policyContent {}", policyId, + policyContent == null ? "null" : policyContent.size()); + } + } + + /** + * generateTargetType - Generates a TargetType object for the policy-id and policy-type. + * + * @param policyId String policy-id + * @param policyType String policy type + * @param policyTypeVersion String policy type version + * @return TargetType object + */ protected TargetType generateTargetType(String policyId, String policyType, String policyTypeVersion) { // // Create all the match's that are possible diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java index 66770e91..addb0df3 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java @@ -23,6 +23,7 @@ package org.onap.policy.pdp.xacml.application.common.std; 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.XACML3; import com.att.research.xacml.std.IdentifierImpl; @@ -38,6 +39,8 @@ 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; @@ -48,17 +51,20 @@ import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType; 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.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; @@ -104,6 +110,127 @@ public class StdMatchableTranslator extends StdBaseTranslator { return null; } + /** + * 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) { + // + // 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. + // + // 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()); + }) + ) + ); + } + + /** + * 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; + } + // + // 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) { + // + // Only need to check first one - as we will ensure there is only one weight + // + Entry<Integer, List<Pair<String, Map<String, Object>>>> firstEntry = + weightMap.entrySet().iterator().next(); + if (policyWeight < firstEntry.getKey()) { + // + // Existing policies have a greater weight, so we will not add it + // + LOGGER.info("{} is lesser weight {} than current policies, will not return it", policyWeight, + firstEntry.getKey()); + } else if (firstEntry.getKey().equals(policyWeight)) { + // + // Same weight - we will add it + // + LOGGER.info("Same weight {}, adding policy", policyWeight); + firstEntry.getValue().add(Pair.of(policyId, policyContent)); + } else { + // + // The weight is greater, so we need to remove the other policies + // and point to this one. + // + 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 { // @@ -143,7 +270,8 @@ public class StdMatchableTranslator extends StdBaseTranslator { // Generate the TargetType - the policy should not be evaluated // unless all the matchable properties it cares about are matched. // - newPolicyType.setTarget(generateTargetType(toscaPolicy.getProperties(), toscaPolicyTypes)); + Pair<TargetType, Integer> pairGenerated = generateTargetType(toscaPolicy.getProperties(), toscaPolicyTypes); + newPolicyType.setTarget(pairGenerated.getLeft()); // // Now represent the policy as Json // @@ -157,7 +285,7 @@ public class StdMatchableTranslator extends StdBaseTranslator { // // Add it as an obligation // - addObligation(newPolicyType, jsonPolicy); + addObligation(newPolicyType, policyName, jsonPolicy, pairGenerated.getRight(), toscaPolicy.getType()); // // Now create the Permit Rule. // @@ -196,24 +324,28 @@ public class StdMatchableTranslator extends StdBaseTranslator { * * @param properties Properties section of policy * @param policyTypes Collection of policy Type to find matchable metadata - * @return TargetType object + * @return {@code Pair<TargetType, Integer>} Returns a TargetType and a Total Weight of matchables. */ - protected TargetType generateTargetType(Map<String, Object> properties, Collection<ToscaPolicyType> policyTypes) { + protected Pair<TargetType, Integer> generateTargetType(Map<String, Object> properties, + Collection<ToscaPolicyType> policyTypes) { TargetType targetType = new TargetType(); // // Iterate the properties // + int totalWeight = 0; for (Entry<String, Object> entrySet : properties.entrySet()) { // // Find matchable properties // if (isMatchable(entrySet.getKey(), policyTypes)) { LOGGER.info("Found matchable property {}", entrySet.getKey()); - generateMatchable(targetType, entrySet.getKey(), entrySet.getValue()); + int weight = generateMatchable(targetType, entrySet.getKey(), entrySet.getValue()); + LOGGER.info("Weight is {}", weight); + totalWeight += weight; } } - - return targetType; + LOGGER.info("Total weight is {}", totalWeight); + return Pair.of(targetType, totalWeight); } /** @@ -259,29 +391,33 @@ public class StdMatchableTranslator extends StdBaseTranslator { /** * generateMatchable - Given the object, generates list of MatchType objects and add them - * to the TargetType object. + * to the TargetType object. Returns a weight which is the number of AnyOf's generated. The + * weight can be used to further filter the results for "closest match". * * @param targetType TargetType object to add matches to * @param key Property key * @param value Object is the value - which can be a Collection or single Object - * @return TargetType incoming TargetType returned as a convenience + * @return int Weight of the match. */ @SuppressWarnings("unchecked") - protected TargetType generateMatchable(TargetType targetType, String key, Object value) { + protected int generateMatchable(TargetType targetType, String key, Object value) { + int weight = 0; if (value instanceof Collection) { AnyOfType anyOf = generateMatches((Collection<Object>) value, new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key)); if (! anyOf.getAllOf().isEmpty()) { targetType.getAnyOf().add(anyOf); + weight = 1; } } else { AnyOfType anyOf = generateMatches(Arrays.asList(value), new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key)); if (! anyOf.getAllOf().isEmpty()) { targetType.getAnyOf().add(anyOf); + weight = 1; } } - return targetType; + return weight; } /** |