e1fe2dcd1360ca9383511870fafddeae8a73b0ec
[policy/xacml-pdp.git] / applications / optimization / src / main / java / org / onap / policy / xacml / pdp / application / optimization / OptimizationPdpApplicationTranslator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.xacml.pdp.application.optimization;
24
25 import com.att.research.xacml.api.Advice;
26 import com.att.research.xacml.api.AttributeAssignment;
27 import com.att.research.xacml.api.Identifier;
28 import com.att.research.xacml.api.XACML3;
29 import com.att.research.xacml.util.XACMLPolicyWriter;
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
39 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
40 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
41 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
44 import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
45 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
46 import org.apache.commons.lang3.StringUtils;
47 import org.onap.policy.models.decisions.concepts.DecisionResponse;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
49 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
50 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
51 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
52 import org.onap.policy.pdp.xacml.application.common.std.StdMatchableTranslator;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public class OptimizationPdpApplicationTranslator extends StdMatchableTranslator {
57     private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplicationTranslator.class);
58
59     private static final String OPTIMIZATION_POLICYTYPE_SUBSCRIBER =
60             "onap.policies.optimization.service.SubscriberPolicy";
61
62     private static final String FIELD_SUBSCRIBER_ROLE = "subscriberRole";
63     private static final String FIELD_PROV_STATUS = "provStatus";
64
65     @SuppressWarnings("unchecked")
66     @Override
67     public Object convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
68         //
69         // Have our superclass do the work - NOTE we are assuming
70         // that we are getting a PolicyType converted.
71         //
72         PolicyType policy = (PolicyType) super.convertPolicy(toscaPolicy);
73         //
74         // Check if this is the subscriber policy
75         //
76         if (OPTIMIZATION_POLICYTYPE_SUBSCRIBER.equals(toscaPolicy.getType())) {
77             //
78             // Ensure the policy has the subscriber properties
79             //
80             Map<String, Object> subscriberProperties = (Map<String, Object>) toscaPolicy.getProperties()
81                     .get("subscriberProperties");
82             if (subscriberProperties == null) {
83                 throw new ToscaPolicyConversionException("Missing subscriberProperties from subscriber policy");
84             }
85             //
86             // Add subscriber name to the target so the policy
87             // only matches for the given subscriberName.
88             //
89             addSubscriberNameIntoTarget(policy, subscriberProperties);
90             //
91             // Add subscriber advice
92             //
93             policy.setAdviceExpressions(generateSubscriberAdvice(subscriberProperties));
94             //
95             // Dump our revised policy out
96             //
97             try (var os = new ByteArrayOutputStream()) {
98                 XACMLPolicyWriter.writePolicyFile(os, policy);
99                 LOGGER.info("{}", os);
100             } catch (IOException e) {
101                 LOGGER.error("Failed to create byte array stream", e);
102             }
103         }
104         return policy;
105     }
106
107     @Override
108     protected void scanAdvice(Collection<Advice> advice, DecisionResponse decisionResponse) {
109         for (Advice adv : advice) {
110             if (! ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER.equals(adv.getId())) {
111                 LOGGER.warn("Unknown advice id {}", adv.getId());
112                 continue;
113             }
114             //
115             // Get the existing advice if any, we are appending to it.
116             //
117             Map<String, Object> mapAdvice = decisionResponse.getAdvice();
118             //
119             // If there's nothing, create a map
120             //
121             if (mapAdvice == null) {
122                 mapAdvice = new HashMap<>();
123             }
124             for (AttributeAssignment assignment : adv.getAttributeAssignments()) {
125                 if (ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_ROLE.equals(assignment.getAttributeId())) {
126                     addValuesToMap(assignment.getAttributeValue().getValue(), FIELD_SUBSCRIBER_ROLE, mapAdvice);
127                 } else if (ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_STATUS.equals(
128                         assignment.getAttributeId())) {
129                     addValuesToMap(assignment.getAttributeValue().getValue(), FIELD_PROV_STATUS, mapAdvice);
130                 }
131             }
132             if (! mapAdvice.isEmpty()) {
133                 decisionResponse.setAdvice(mapAdvice);
134             }
135         }
136     }
137
138     @SuppressWarnings("unchecked")
139     private static void addValuesToMap(Object values, String key, Map<String, Object> mapAdvice) {
140         if (values instanceof Collection) {
141             List<String> valueList = new ArrayList<>();
142             ((Collection<Object>) values).forEach(val -> valueList.add(val.toString()));
143             mapAdvice.put(key, valueList);
144         } else {
145             mapAdvice.put(key, values.toString());
146         }
147
148     }
149
150     private static PolicyType addSubscriberNameIntoTarget(PolicyType policy,
151             Map<String, Object> subscriberProperties) throws ToscaPolicyConversionException {
152         //
153         // Iterate through all the subscriber names
154         //
155         var anyOf = new AnyOfType();
156         for (Object subscriberName : getPropAsList(subscriberProperties, "subscriberName")) {
157
158             var match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
159                     XACML3.ID_FUNCTION_STRING_EQUAL,
160                     subscriberName,
161                     XACML3.ID_DATATYPE_STRING,
162                     ToscaDictionary.ID_SUBJECT_OPTIMIZATION_SUBSCRIBER_NAME,
163                     XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT);
164
165             anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
166         }
167         //
168         // Add to the target
169         //
170         policy.getTarget().getAnyOf().add(anyOf);
171         //
172         // Return for convenience
173         //
174         return policy;
175     }
176
177     private static AdviceExpressionsType generateSubscriberAdvice(Map<String, Object> subscriberProperties)
178             throws ToscaPolicyConversionException {
179         //
180         // Create our subscriber advice expression
181         //
182         var adviceExpression = new AdviceExpressionType();
183         adviceExpression.setAppliesTo(EffectType.PERMIT);
184         adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER.stringValue());
185         //
186         // Add in subscriber role advice attributes
187         //
188         generateSubscriberAdviceAttributes(
189                 adviceExpression,
190                 ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_ROLE,
191                 getPropAsList(subscriberProperties, FIELD_SUBSCRIBER_ROLE));
192         //
193         // Get the provision status
194         //
195         generateSubscriberAdviceAttributes(
196                 adviceExpression,
197                 ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_STATUS,
198                 getPropAsList(subscriberProperties, FIELD_PROV_STATUS));
199         //
200         // Add it to the overall expressions
201         //
202         var adviceExpressions = new AdviceExpressionsType();
203         adviceExpressions.getAdviceExpression().add(adviceExpression);
204         //
205         // Done return our advice expressions
206         //
207         return adviceExpressions;
208     }
209
210     private static void generateSubscriberAdviceAttributes(AdviceExpressionType adviceExpression,
211             Identifier attributeId, Collection<Object> adviceAttribute) {
212         for (Object attribute : adviceAttribute) {
213             var value = new AttributeValueType();
214             value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
215             value.getContent().add(attribute.toString());
216
217             var assignment = new AttributeAssignmentExpressionType();
218             assignment.setAttributeId(attributeId.stringValue());
219             assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue());
220             assignment.setExpression(new ObjectFactory().createAttributeValue(value));
221
222             adviceExpression.getAttributeAssignmentExpression().add(assignment);
223         }
224     }
225
226     @SuppressWarnings("unchecked")
227     private static List<Object> getPropAsList(Map<String, Object> properties, String fieldName)
228                     throws ToscaPolicyConversionException {
229
230         Object raw = properties.get(fieldName);
231         if (raw == null || StringUtils.isBlank(raw.toString())) {
232             throw new ToscaPolicyConversionException("Missing " + fieldName);
233         }
234
235         return raw instanceof Collection ? (List<Object>) raw : Arrays.asList(raw);
236     }
237 }