aboutsummaryrefslogtreecommitdiffstats
path: root/applications/common/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'applications/common/src/main')
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java53
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java64
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java129
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java87
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java75
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java141
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java400
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java110
8 files changed, 880 insertions, 179 deletions
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java
index 7da455c0..66352010 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java
@@ -20,16 +20,24 @@
package org.onap.policy.pdp.xacml.application.common;
+import com.att.research.xacml.std.IdentifierImpl;
import com.att.research.xacml.std.StdStatusCode;
+import com.att.research.xacml.std.StdVersion;
import com.att.research.xacml.std.dom.DOMStructureException;
import com.att.research.xacml.util.FactoryException;
import com.att.research.xacml.util.XACMLProperties;
+import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithm;
+import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithmFactory;
import com.att.research.xacmlatt.pdp.policy.Policy;
import com.att.research.xacmlatt.pdp.policy.PolicyDef;
import com.att.research.xacmlatt.pdp.policy.PolicyFinder;
import com.att.research.xacmlatt.pdp.policy.PolicyFinderFactory;
+import com.att.research.xacmlatt.pdp.policy.PolicySet;
+import com.att.research.xacmlatt.pdp.policy.PolicySetChild;
+import com.att.research.xacmlatt.pdp.policy.Target;
import com.att.research.xacmlatt.pdp.policy.dom.DOMPolicyDef;
import com.att.research.xacmlatt.pdp.std.StdPolicyFinder;
+import com.att.research.xacmlatt.pdp.util.ATTPDPProperties;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
@@ -43,6 +51,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
+import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -212,7 +221,49 @@ public class OnapPolicyFinderFactory extends PolicyFinderFactory {
protected synchronized void init() {
if (this.needsInit) {
logger.debug("Initializing OnapPolicyFinderFactory Properties ");
- this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES);
+
+ //
+ // Check for property that combines root policies into one policyset
+ //
+ String combiningAlgorithm = properties.getProperty(
+ ATTPDPProperties.PROP_POLICYFINDERFACTORY_COMBINEROOTPOLICIES);
+ if (combiningAlgorithm != null) {
+ try {
+ logger.info("Combining root policies with {}", combiningAlgorithm);
+ //
+ // Find the combining algorithm
+ //
+ CombiningAlgorithm<PolicySetChild> algorithm = CombiningAlgorithmFactory.newInstance()
+ .getPolicyCombiningAlgorithm(new IdentifierImpl(combiningAlgorithm));
+ //
+ // Create our root policy
+ //
+ PolicySet root = new PolicySet();
+ root.setIdentifier(new IdentifierImpl(UUID.randomUUID().toString()));
+ root.setVersion(StdVersion.newInstance("1.0"));
+ root.setTarget(new Target());
+ //
+ // Set the algorithm
+ //
+ root.setPolicyCombiningAlgorithm(algorithm);
+ //
+ // Load all our root policies
+ //
+ for (PolicyDef policy : this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES)) {
+ root.addChild(policy);
+ }
+ //
+ // Set this policy as the root
+ //
+ this.rootPolicies = new ArrayList<>();
+ this.rootPolicies.add(root);
+ } catch (Exception e) {
+ logger.error("Failed to load Combining Algorithm Factory: {}", e.getLocalizedMessage());
+ }
+ } else {
+ logger.info("Loading root policies");
+ this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES);
+ }
this.referencedPolicies = this.getPolicyDefs(XACMLProperties.PROP_REFERENCEDPOLICIES);
logger.debug("Root Policies: {}", this.rootPolicies.size());
logger.debug("Referenced Policies: {}", this.referencedPolicies.size());
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 352e51d8..0dcafa00 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
@@ -43,6 +43,68 @@ public final class ToscaDictionary {
public static final Identifier ID_RESOURCE_POLICY_TYPE_VERSION =
new IdentifierImpl(URN_ONAP, "policy-type-version");
+ /*
+ * These ID's are for identifying Subjects
+ */
+
+ public static final Identifier ID_SUBJECT_ONAP_NAME =
+ XACML3.ID_SUBJECT_SUBJECT_ID;
+
+ public static final Identifier ID_SUBJECT_ONAP_COMPONENT =
+ new IdentifierImpl(URN_ONAP, "onap-component");
+
+ public static final Identifier ID_SUBJECT_ONAP_INSTANCE =
+ new IdentifierImpl(URN_ONAP, "onap-instance");
+
+ /*
+ * These 2 ID's are for Optimization policies
+ */
+
+ public static final Identifier ID_RESOURCE_POLICY_SCOPE_PROPERTY =
+ new IdentifierImpl(URN_ONAP, "policy-scope-property");
+
+ public static final Identifier ID_RESOURCE_POLICY_TYPE_PROPERTY =
+ new IdentifierImpl(URN_ONAP, "policy-type-property");
+
+ /*
+ * These ID's are for Legacy Guard Policies
+ */
+ public static final Identifier ID_RESOURCE_GUARD_ACTOR =
+ new IdentifierImpl(URN_ONAP, "guard:actor:actor-id");
+ public static final Identifier ID_RESOURCE_GUARD_RECIPE =
+ new IdentifierImpl(URN_ONAP, "guard:operation:operation-id");
+ public static final Identifier ID_RESOURCE_GUARD_CLNAME =
+ new IdentifierImpl(URN_ONAP, "guard:clname:clname-id");
+ public static final Identifier ID_RESOURCE_GUARD_TARGETID =
+ new IdentifierImpl(URN_ONAP, "guard:target:target-id");
+ public static final Identifier ID_SUBJECT_GUARD_REQUESTID =
+ new IdentifierImpl(URN_ONAP, "guard:request:request-id");
+ public static final Identifier ID_RESOURCE_GUARD_VFCOUNT =
+ new IdentifierImpl(URN_ONAP, "guard:target:vf-count");
+ public static final Identifier ID_RESOURCE_GUARD_MIN =
+ new IdentifierImpl(URN_ONAP, "guard:target:min");
+ public static final Identifier ID_RESOURCE_GUARD_MAX =
+ new IdentifierImpl(URN_ONAP, "guard:target:max");
+
+ /*
+ * This id specifically for guard is provided by the
+ * operational history database PIP.
+ */
+ public static final Identifier ID_RESOURCE_GUARD_OPERATIONCOUNT =
+ new IdentifierImpl(URN_ONAP, "guard:operation:operation-count");
+
+ /*
+ * This id is specifically for advice returned from guard
+ */
+ public static final Identifier ID_ADVICE_GUARD =
+ new IdentifierImpl(URN_ONAP, "guard:advice");
+ public static final Identifier ID_ADVICE_GUARD_REQUESTID =
+ new IdentifierImpl(URN_ONAP, "guard:advice:request-id");
+
+ /*
+ * Obligation specific ID's
+ */
+
public static final Identifier ID_OBLIGATION_REST_BODY =
new IdentifierImpl(URN_ONAP, "rest:body");
@@ -61,6 +123,8 @@ public final class ToscaDictionary {
public static final Identifier ID_OBLIGATION_MONITORING_ISSUER =
new IdentifierImpl(URN_ONAP, "issuer:monitoring");
+
+
private ToscaDictionary() {
super();
}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java
index ca327b90..46742af9 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java
@@ -23,11 +23,11 @@
package org.onap.policy.pdp.xacml.application.common;
import com.att.research.xacml.api.Identifier;
-import com.att.research.xacml.api.pdp.PDPEngine;
-import com.att.research.xacml.api.pdp.PDPEngineFactory;
-import com.att.research.xacml.util.FactoryException;
import com.att.research.xacml.util.XACMLProperties;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -146,6 +146,40 @@ public class XacmlPolicyUtils {
}
/**
+ * Adds in the root policy to the PDP properties object.
+ *
+ * @param properties Input properties
+ * @param rootPolicyPath Path to the root policy file
+ * @return Properties object
+ */
+ public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) {
+ //
+ // Get the current set of referenced policy ids
+ //
+ Set<String> rootPolicies = XACMLProperties.getRootPolicyIDs(properties);
+ //
+ // Construct a unique id
+ //
+ int id = 1;
+ while (true) {
+ String refId = "ref" + id;
+ if (rootPolicies.contains(refId)) {
+ id++;
+ } else {
+ rootPolicies.add(refId);
+ properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString());
+ break;
+ }
+ }
+ //
+ // Set the new comma separated list
+ //
+ properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES,
+ rootPolicies.stream().collect(Collectors.joining(",")));
+ return properties;
+ }
+
+ /**
* Adds in the referenced policy to the PDP properties object.
*
* @param properties Input properties
@@ -318,23 +352,90 @@ public class XacmlPolicyUtils {
return Paths.get(rootPath.toAbsolutePath().toString(), "xacml.properties");
}
+ public interface FileCreator {
+ public File createAFile(String filename) throws IOException;
+
+ }
/**
- * Creates an instance of PDP engine given the Properties object.
+ * Copies a xacml.properties file to another location and all the policies defined within it.
*
- * @param properties Incoming Properties object
- * @return PDPEngine instance or null if failed
+ * @param propertiesPath Path to an existing properties file
+ * @param properties Properties object
+ * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder
+ * @return File object that points to new Properties file
+ * @throws IOException Could not read/write files
*/
- public static PDPEngine createEngine(Properties properties) {
+ public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties,
+ FileCreator creator) throws IOException {
//
- // Now initialize the XACML PDP Engine
+ // Open the properties file
//
- try {
- PDPEngineFactory factory = PDPEngineFactory.newInstance();
- return factory.newEngine(properties);
- } catch (FactoryException e) {
- LOGGER.error("Failed to create XACML PDP Engine {}", e);
+ try (InputStream is = new FileInputStream(propertiesPath)) {
+ //
+ // Load in the properties
+ //
+ properties.load(is);
+ //
+ // Now we create a new xacml.properties in the temporary folder location
+ //
+ File propertiesFile = creator.createAFile("xacml.properties");
+ //
+ // Iterate through any root policies defined
+ //
+ for (String root : XACMLProperties.getRootPolicyIDs(properties)) {
+ //
+ // Get a file
+ //
+ Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX));
+ LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName());
+ //
+ // Construct new path for the root policy
+ //
+ File newRootPath = creator.createAFile(rootPath.getFileName().toString());
+ //
+ // Copy the policy file to the temporary folder
+ //
+ com.google.common.io.Files.copy(rootPath.toFile(), newRootPath);
+ //
+ // Change the properties object to point to where the new policy is
+ // in the temporary folder
+ //
+ properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath());
+ }
+ //
+ // Iterate through any referenced policies defined
+ //
+ for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) {
+ //
+ // Get a file
+ //
+ Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX));
+ LOGGER.debug("Referenced file {} {}", refPath, refPath.getFileName());
+ //
+ // Construct new path for the root policy
+ //
+ File newReferencedPath = creator.createAFile(refPath.getFileName().toString());
+ //
+ // Copy the policy file to the temporary folder
+ //
+ com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath);
+ //
+ // Change the properties object to point to where the new policy is
+ // in the temporary folder
+ //
+ properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath());
+ }
+ //
+ // Save the new properties file to the temporary folder
+ //
+ try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) {
+ properties.store(os, "");
+ }
+ //
+ // Return the new path to the properties folder
+ //
+ return propertiesFile;
}
- return null;
}
}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java
index 3914ba60..3038b651 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java
@@ -27,27 +27,41 @@ import com.att.research.xacml.std.annotations.XACMLRequest;
import com.att.research.xacml.std.annotations.XACMLResource;
import com.att.research.xacml.std.annotations.XACMLSubject;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
import org.onap.policy.models.decisions.concepts.DecisionRequest;
+@Getter
+@Setter
+@ToString
@XACMLRequest(ReturnPolicyIdList = true)
public class StdCombinedPolicyRequest {
- public StdCombinedPolicyRequest() {
- super();
- }
-
@XACMLSubject(includeInResults = true)
- String onapName = "DCAE";
+ private String onapName;
- @XACMLResource(includeInResults = true)
- String resource = "onap.policies.Monitoring";
+ @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true)
+ private String onapComponent;
+
+ @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true)
+ private String onapInstance;
@XACMLAction()
- String action = "configure";
+ private String action;
+
+ @XACMLResource(includeInResults = true)
+ private Collection<String> resource = new ArrayList<>();
+ public StdCombinedPolicyRequest() {
+ super();
+ }
/**
* Parses the DecisionRequest into a MonitoringRequest.
@@ -55,30 +69,57 @@ public class StdCombinedPolicyRequest {
* @param decisionRequest Input DecisionRequest
* @return MonitoringRequest
*/
+ @SuppressWarnings({"unchecked", "rawtypes"})
public static StdCombinedPolicyRequest createInstance(DecisionRequest decisionRequest) {
+ //
+ // Create our request object
+ //
StdCombinedPolicyRequest request = new StdCombinedPolicyRequest();
+ //
+ // Add the subject attributes
+ //
request.onapName = decisionRequest.getOnapName();
+ request.onapComponent = decisionRequest.getOnapComponent();
+ request.onapInstance = decisionRequest.getOnapInstance();
+ //
+ // Add the action attribute
+ //
request.action = decisionRequest.getAction();
-
+ //
+ // Add the resource attributes
+ //
Map<String, Object> resources = decisionRequest.getResource();
- for (Entry<String, Object> entry : resources.entrySet()) {
- if ("policy-id".equals(entry.getKey())) {
- //
- // TODO handle lists of policies
- //
- request.resource = entry.getValue().toString();
+ for (Entry<String, Object> entrySet : resources.entrySet()) {
+ if ("policy-id".equals(entrySet.getKey())) {
+ if (entrySet.getValue() instanceof Collection) {
+ addPolicyIds(request, (Collection) entrySet.getValue());
+ } else if (entrySet.getValue() instanceof String) {
+ request.resource.add(entrySet.getValue().toString());
+ }
continue;
}
- if ("policy-type".equals(entry.getKey())) {
- //
- // TODO handle lists of policies
- //
- request.resource = entry.getValue().toString();
+ if ("policy-type".equals(entrySet.getKey())) {
+ if (entrySet.getValue() instanceof Collection) {
+ addPolicyTypes(request, (Collection) entrySet.getValue());
+ } else if (entrySet.getValue() instanceof String) {
+ request.resource.add(entrySet.getValue().toString());
+ }
}
}
- //
- // TODO handle a bad incoming request. Do that here?
- //
+ return request;
+ }
+
+ private static StdCombinedPolicyRequest addPolicyIds(StdCombinedPolicyRequest request, Collection<Object> ids) {
+ for (Object id : ids) {
+ request.resource.add(id.toString());
+ }
+ return request;
+ }
+
+ private static StdCombinedPolicyRequest addPolicyTypes(StdCombinedPolicyRequest request, Collection<Object> types) {
+ for (Object type : types) {
+ request.resource.add(type.toString());
+ }
return request;
}
}
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 b39c2e60..16798379 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
@@ -37,6 +37,7 @@ import com.google.gson.Gson;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -144,40 +145,55 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator
//
// Go through obligations
//
- for (Obligation obligation : xacmlResult.getObligations()) {
- LOGGER.debug("Obligation: {}", obligation);
- for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
- LOGGER.debug("Attribute Assignment: {}", assignment);
- //
- // 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();
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
- }
- //
- // Let's parse it into a map using Gson
- //
- Gson gson = new Gson();
- @SuppressWarnings("unchecked")
- Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
- decisionResponse.getPolicies().add(result);
- }
- }
- }
- } else {
- decisionResponse.setErrorMessage("A better error message");
+ scanObligations(xacmlResult.getObligations(), decisionResponse);
+ }
+ if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
+ //
+ // There is no policy
+ //
+ decisionResponse.setPolicies(new ArrayList<>());
+ }
+ if (xacmlResult.getDecision() == Decision.DENY
+ || xacmlResult.getDecision() == Decision.INDETERMINATE) {
+ //
+ // TODO we have to return an ErrorResponse object instead
+ //
+ decisionResponse.setStatus("A better error message");
}
}
return decisionResponse;
}
+ protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
+ for (Obligation obligation : obligations) {
+ LOGGER.debug("Obligation: {}", obligation);
+ for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
+ LOGGER.debug("Attribute Assignment: {}", assignment);
+ //
+ // 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();
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
+ }
+ //
+ // Let's parse it into a map using Gson
+ //
+ Gson gson = new Gson();
+ @SuppressWarnings("unchecked")
+ Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
+ decisionResponse.getPolicies().add(result);
+ }
+ }
+ }
+ }
+
@SuppressWarnings("unchecked")
protected PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
//
@@ -211,9 +227,6 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator
//
// Generate the TargetType
//
- //
- // There should be a metadata section
- //
if (! policyDefinition.containsKey("type")) {
throw new ToscaPolicyConversionException(policyName + " missing type value");
}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java
new file mode 100644
index 00000000..086d21db
--- /dev/null
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java
@@ -0,0 +1,141 @@
+/*-
+ * ============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.std;
+
+import com.att.research.xacml.std.annotations.XACMLAction;
+import com.att.research.xacml.std.annotations.XACMLRequest;
+import com.att.research.xacml.std.annotations.XACMLResource;
+import com.att.research.xacml.std.annotations.XACMLSubject;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import org.onap.policy.models.decisions.concepts.DecisionRequest;
+
+@Getter
+@Setter
+@ToString
+@XACMLRequest(ReturnPolicyIdList = true)
+public class StdMatchablePolicyRequest {
+
+ @XACMLSubject(includeInResults = true)
+ private String onapName;
+
+ @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true)
+ private String onapComponent;
+
+ @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true)
+ private String onapInstance;
+
+ @XACMLAction()
+ private String action;
+
+ //
+ // Unfortunately the annotations won't take an object.toString()
+ // So I could not use the ToscaDictionary class to put these id's
+ // into the annotations.
+ //
+ @XACMLResource(attributeId = "urn:org:onap:policy-scope-property", includeInResults = true)
+ Collection<String> policyScopes = new ArrayList<>();
+
+ @XACMLResource(attributeId = "urn:org:onap:policy-type-property", includeInResults = true)
+ Collection<String> policyTypes = new ArrayList<>();
+
+ public StdMatchablePolicyRequest() {
+ super();
+ }
+
+ /**
+ * Parses the DecisionRequest into a MonitoringRequest.
+ *
+ * @param decisionRequest Input DecisionRequest
+ * @return MonitoringRequest
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static StdMatchablePolicyRequest createInstance(DecisionRequest decisionRequest) {
+ //
+ // Create our request object
+ //
+ StdMatchablePolicyRequest request = new StdMatchablePolicyRequest();
+ //
+ // Add the subject attributes
+ //
+ request.onapName = decisionRequest.getOnapName();
+ request.onapComponent = decisionRequest.getOnapComponent();
+ request.onapInstance = decisionRequest.getOnapInstance();
+ //
+ // Add the action attribute
+ //
+ request.action = decisionRequest.getAction();
+ //
+ // Add the resource attributes
+ //
+ Map<String, Object> resources = decisionRequest.getResource();
+ for (Entry<String, Object> entrySet : resources.entrySet()) {
+ //
+ // Making an assumption that these two fields are matchable.
+ // Its possible we may have to load the policy type model
+ // and use that to find the fields that are matchable.
+ //
+ if ("policyScope".equals(entrySet.getKey())) {
+ if (entrySet.getValue() instanceof Collection) {
+ addPolicyScopes(request, (Collection) entrySet.getValue());
+ } else if (entrySet.getValue() instanceof String) {
+ request.policyScopes.add(entrySet.getValue().toString());
+ }
+ continue;
+ }
+ if ("policyType".equals(entrySet.getKey())) {
+ if (entrySet.getValue() instanceof Collection) {
+ addPolicyTypes(request, (Collection) entrySet.getValue());
+ }
+ if (entrySet.getValue() instanceof String) {
+ request.policyTypes.add(entrySet.getValue().toString());
+ }
+ }
+ }
+ return request;
+ }
+
+ private static StdMatchablePolicyRequest addPolicyScopes(StdMatchablePolicyRequest request,
+ Collection<Object> scopes) {
+ for (Object scope : scopes) {
+ request.policyScopes.add(scope.toString());
+ }
+ return request;
+ }
+
+ private static StdMatchablePolicyRequest addPolicyTypes(StdMatchablePolicyRequest request,
+ Collection<Object> types) {
+ for (Object type : types) {
+ request.policyTypes.add(type.toString());
+ }
+ return request;
+ }
+}
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
new file mode 100644
index 00000000..8550b12e
--- /dev/null
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java
@@ -0,0 +1,400 @@
+/*-
+ * ============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.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.Identifier;
+import com.att.research.xacml.api.Obligation;
+import com.att.research.xacml.api.Request;
+import com.att.research.xacml.api.Response;
+import com.att.research.xacml.api.Result;
+import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.annotations.RequestParser;
+import com.att.research.xacml.util.XACMLPolicyWriter;
+import com.google.gson.Gson;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+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.json.JSONObject;
+import org.onap.policy.models.decisions.concepts.DecisionRequest;
+import org.onap.policy.models.decisions.concepts.DecisionResponse;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StdMatchableTranslator implements ToscaPolicyTranslator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class);
+
+ public StdMatchableTranslator() {
+ super();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject)
+ throws ToscaPolicyConversionException {
+ //
+ // Our return object
+ //
+ List<PolicyType> scannedPolicies = new ArrayList<>();
+ //
+ // Iterate each of the Policies
+ //
+ List<Object> policies = (List<Object>) toscaObject.get("policies");
+ for (Object policyObject : policies) {
+ //
+ // Get the contents
+ //
+ LOGGER.debug("Found policy {}", policyObject.getClass());
+ Map<String, Object> policyContents = (Map<String, Object>) policyObject;
+ for (Entry<String, Object> entrySet : policyContents.entrySet()) {
+ LOGGER.debug("Entry set {}", entrySet);
+ //
+ // Convert this policy
+ //
+ PolicyType policy = this.convertPolicy(entrySet);
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ XACMLPolicyWriter.writePolicyFile(os, policy);
+ LOGGER.debug("{}", os);
+ } catch (IOException e) {
+ LOGGER.error("Failed to convert {}", e);
+ }
+ //
+ // Convert and add in the new policy
+ //
+ scannedPolicies.add(policy);
+ }
+ }
+
+ return scannedPolicies;
+ }
+
+ @Override
+ public Request convertRequest(DecisionRequest request) {
+ LOGGER.debug("Converting Request {}", request);
+ try {
+ return RequestParser.parseRequest(StdMatchablePolicyRequest.createInstance(request));
+ } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) {
+ LOGGER.error("Failed to convert DecisionRequest: {}", e);
+ }
+ //
+ // TODO throw exception
+ //
+ return null;
+ }
+
+ @Override
+ public DecisionResponse convertResponse(Response xacmlResponse) {
+ LOGGER.debug("Converting Response {}", xacmlResponse);
+ DecisionResponse decisionResponse = new DecisionResponse();
+ //
+ // Iterate through all the results
+ //
+ for (Result xacmlResult : xacmlResponse.getResults()) {
+ //
+ // Check the result
+ //
+ if (xacmlResult.getDecision() == Decision.PERMIT) {
+ //
+ // Setup policies
+ //
+ decisionResponse.setPolicies(new ArrayList<>());
+ //
+ // Go through obligations
+ //
+ scanObligations(xacmlResult.getObligations(), decisionResponse);
+ }
+ if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) {
+ //
+ // There is no policy
+ //
+ decisionResponse.setPolicies(new ArrayList<>());
+ }
+ if (xacmlResult.getDecision() == Decision.DENY
+ || xacmlResult.getDecision() == Decision.INDETERMINATE) {
+ //
+ // TODO we have to return an ErrorResponse object instead
+ //
+ decisionResponse.setStatus("A better error message");
+ }
+ }
+
+ return decisionResponse;
+ }
+
+ protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
+ for (Obligation obligation : obligations) {
+ LOGGER.debug("Obligation: {}", obligation);
+ for (AttributeAssignment assignment : obligation.getAttributeAssignments()) {
+ LOGGER.debug("Attribute Assignment: {}", assignment);
+ //
+ // 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();
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents);
+ }
+ //
+ // Let's parse it into a map using Gson
+ //
+ Gson gson = new Gson();
+ @SuppressWarnings("unchecked")
+ Map<String, Object> result = gson.fromJson(stringContents.toString() ,Map.class);
+ decisionResponse.getPolicies().add(result);
+ }
+ }
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ protected PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
+ //
+ // Policy name should be at the root
+ //
+ String policyName = entrySet.getKey();
+ Map<String, Object> policyDefinition = (Map<String, Object>) entrySet.getValue();
+ //
+ // Set it as the policy ID
+ //
+ PolicyType newPolicyType = new PolicyType();
+ newPolicyType.setPolicyId(policyName);
+ //
+ // Optional description
+ //
+ if (policyDefinition.containsKey("description")) {
+ newPolicyType.setDescription(policyDefinition.get("description").toString());
+ }
+ //
+ // There should be a metadata section
+ //
+ if (! policyDefinition.containsKey("metadata")) {
+ throw new ToscaPolicyConversionException(policyName + " missing metadata section");
+ }
+ this.fillMetadataSection(newPolicyType,
+ (Map<String, Object>) policyDefinition.get("metadata"));
+ //
+ // Set the combining rule
+ //
+ newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
+ //
+ // Generate the TargetType
+ //
+ if (! policyDefinition.containsKey("properties")) {
+ throw new ToscaPolicyConversionException(policyName + " missing properties section");
+ }
+ policyDefinition.get("properties");
+ newPolicyType.setTarget(generateTargetType((Map<String, Object>) policyDefinition.get("properties")));
+ //
+ // 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());
+ //
+ // Now represent the policy as Json
+ //
+ JSONObject jsonObligation = new JSONObject();
+ jsonObligation.put(policyName, policyDefinition);
+ addObligation(rule, jsonObligation);
+ //
+ // Add the rule to the policy
+ //
+ newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
+ //
+ // Return our new policy
+ //
+ 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 metadata 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, Object> metadata) throws ToscaPolicyConversionException {
+ if (! metadata.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 (! metadata.containsKey("policy-version")) {
+ throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version");
+ } else {
+ //
+ // Add in the Policy Version
+ //
+ policy.setVersion(metadata.get("policy-version").toString());
+ }
+ return policy;
+ }
+
+ /**
+ * For generating target type, we are making an assumption that the
+ * policyScope and policyType are the fields that OOF wants to match on.
+ *
+ * <P>In the future, we would need to receive the Policy Type specification
+ * from the PAP so we can dynamically see which fields are matchable.
+ *
+ * <P>Note: I am making an assumption that the matchable fields are what
+ * the OOF wants to query a policy on.
+ *
+ * @param properties Properties section of policy
+ * @return TargetType object
+ */
+ @SuppressWarnings("unchecked")
+ protected TargetType generateTargetType(Map<String, Object> properties) {
+ TargetType targetType = new TargetType();
+ //
+ // Iterate the properties
+ //
+ for (Entry<String, Object> entrySet : properties.entrySet()) {
+ //
+ // Find policyScope and policyType
+ //
+ if (entrySet.getKey().equals("policyScope")) {
+ LOGGER.debug("Found policyScope: {}", entrySet.getValue());
+ if (entrySet.getValue() instanceof Collection) {
+ targetType.getAnyOf().add(generateMatches((Collection<Object>) entrySet.getValue(),
+ ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY));
+ } else if (entrySet.getValue() instanceof String) {
+ targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()),
+ ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY));
+ }
+ }
+ if (entrySet.getKey().equals("policyType")) {
+ LOGGER.debug("Found policyType: {}", entrySet.getValue());
+ if (entrySet.getValue() instanceof Collection) {
+ targetType.getAnyOf().add(generateMatches((Collection<Object>) entrySet.getValue(),
+ ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY));
+ } else if (entrySet.getValue() instanceof String) {
+ targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()),
+ ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY));
+ }
+ }
+ }
+
+ return targetType;
+ }
+
+ 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) {
+ //
+ // Create a match for this
+ //
+ MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+ XACML3.ID_FUNCTION_STRING_EQUAL,
+ matchable.toString(),
+ XACML3.ID_DATATYPE_STRING,
+ attributeId,
+ XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+ //
+ // Now create an anyOf (OR)
+ //
+ anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
+ }
+ return anyOf;
+ }
+
+ protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) {
+ //
+ // Convert the YAML Policy to JSON Object
+ //
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("JSON Optimization Policy {}{}", System.lineSeparator(), jsonPolicy);
+ }
+ //
+ // Create an AttributeValue for it
+ //
+ AttributeValueType value = new AttributeValueType();
+ value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue());
+ value.getContent().add(jsonPolicy.toString());
+ //
+ // 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;
+ }
+
+}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java
deleted file mode 100644
index 11651f4f..00000000
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-
- * ============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.std;
-
-import com.att.research.xacml.api.Request;
-import com.att.research.xacml.api.Response;
-import com.att.research.xacml.util.XACMLPolicyWriter;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
-
-import org.onap.policy.models.decisions.concepts.DecisionRequest;
-import org.onap.policy.models.decisions.concepts.DecisionResponse;
-import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
-import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class StdMetadataTranslator implements ToscaPolicyTranslator {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(StdMetadataTranslator.class);
-
- public StdMetadataTranslator() {
- super();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public List<PolicyType> scanAndConvertPolicies(Map<String, Object> toscaObject)
- throws ToscaPolicyConversionException {
- //
- // Our return object
- //
- List<PolicyType> scannedPolicies = new ArrayList<>();
- //
- // Iterate each of the Policies
- //
- List<Object> policies = (List<Object>) toscaObject.get("policies");
- for (Object policyObject : policies) {
- //
- // Get the contents
- //
- LOGGER.debug("Found policy {}", policyObject.getClass());
- Map<String, Object> policyContents = (Map<String, Object>) policyObject;
- for (Entry<String, Object> entrySet : policyContents.entrySet()) {
- LOGGER.debug("Entry set {}", entrySet);
- //
- // Convert this policy
- //
- PolicyType policy = this.convertPolicy(entrySet);
- try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
- XACMLPolicyWriter.writePolicyFile(os, policy);
- LOGGER.debug("{}", os);
- } catch (IOException e) {
- LOGGER.error("Failed to convert {}", e);
- }
- //
- // Convert and add in the new policy
- //
- scannedPolicies.add(policy);
- }
- }
-
- return scannedPolicies;
- }
-
- @Override
- public Request convertRequest(DecisionRequest request) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public DecisionResponse convertResponse(Response xacmlResponse) {
- // TODO Auto-generated method stub
- return null;
- }
-
- private PolicyType convertPolicy(Entry<String, Object> entrySet) throws ToscaPolicyConversionException {
-
- return null;
- }
-
-}