aboutsummaryrefslogtreecommitdiffstats
path: root/applications/common/src/main/java/org
diff options
context:
space:
mode:
authorJorge Hernandez <jorge.hernandez-herrero@att.com>2019-11-13 13:55:40 +0000
committerGerrit Code Review <gerrit@onap.org>2019-11-13 13:55:40 +0000
commit2461d8507c22c7e46b46578f98e5fe916032ee4d (patch)
tree0304b4d847749db22a34fe6803f2048149b32eb0 /applications/common/src/main/java/org
parent8d28c6fc936eb4bd95ad1ebd013996cff4787e0e (diff)
parentfe3a8ec467beae89bca9d10b8b5b39f98c81ca01 (diff)
Merge "Implement closest match algorithm"
Diffstat (limited to 'applications/common/src/main/java/org')
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapObligation.java259
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java37
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java94
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java83
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java158
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;
}
/**