Change RestServerParameters to BusTopicParams
[policy/xacml-pdp.git] / applications / optimization / src / main / java / org / onap / policy / xacml / pdp / application / optimization / OptimizationPdpApplication.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2021 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * SPDX-License-Identifier: Apache-2.0
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.policy.xacml.pdp.application.optimization;
25
26 import com.att.research.xacml.api.Advice;
27 import com.att.research.xacml.api.AttributeAssignment;
28 import com.att.research.xacml.api.Decision;
29 import com.att.research.xacml.api.Response;
30 import com.att.research.xacml.api.Result;
31 import java.nio.file.Path;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Map;
36 import org.apache.commons.lang3.tuple.Pair;
37 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
38 import org.onap.policy.models.decisions.concepts.DecisionRequest;
39 import org.onap.policy.models.decisions.concepts.DecisionResponse;
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
41 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
42 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
43 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
44 import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class OptimizationPdpApplication extends StdXacmlApplicationServiceProvider {
49
50     private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplication.class);
51     private static final String STRING_VERSION100 = "1.0.0";
52     private static final String RESOURCE_SUBSCRIBERNAME = "subscriberName";
53     private static final String RESOURCE_POLICYTYPE = "policy-type";
54     private static final String RESOURCE_SCOPE = "scope";
55
56     public static final String POLICYTYPE_AFFINITY = "onap.policies.optimization.resource.AffinityPolicy";
57     public static final String POLICYTYPE_SUBSCRIBER = "onap.policies.optimization.service.SubscriberPolicy";
58     public static final String POLICYTYPE_DISTANCE = "onap.policies.optimization.resource.DistancePolicy";
59     public static final String POLICYTYPE_HPA = "onap.policies.optimization.resource.HpaPolicy";
60     public static final String POLICYTYPE_OPTIMIZATION = "onap.policies.optimization.resource.OptimizationPolicy";
61     public static final String POLICYTYPE_PCI = "onap.policies.optimization.resource.PciPolicy";
62     public static final String POLICYTYPE_QUERY = "onap.policies.optimization.service.QueryPolicy";
63     public static final String POLICYTYPE_VIMFIT = "onap.policies.optimization.resource.Vim_fit";
64     public static final String POLICYTYPE_VNF = "onap.policies.optimization.resource.VnfPolicy";
65     public static final String ONAP_OPTIMIZATION_DERIVED_POLICY_TYPE = "onap.policies.optimization.";
66
67     private OptimizationPdpApplicationTranslator translator = new OptimizationPdpApplicationTranslator();
68
69     /**
70      * Constructor.
71      */
72     public OptimizationPdpApplication() {
73         super();
74
75         applicationName = "optimization";
76         actions = Arrays.asList("optimize");
77
78         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_AFFINITY, STRING_VERSION100));
79         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_DISTANCE, STRING_VERSION100));
80         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_HPA, STRING_VERSION100));
81         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_OPTIMIZATION, STRING_VERSION100));
82         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_PCI, STRING_VERSION100));
83         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_QUERY, STRING_VERSION100));
84         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_SUBSCRIBER, STRING_VERSION100));
85         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_VIMFIT, STRING_VERSION100));
86         this.supportedPolicyTypes.add(new ToscaConceptIdentifier(POLICYTYPE_VNF, STRING_VERSION100));
87     }
88
89     @Override
90     public void initialize(Path pathForData, BusTopicParams policyApiParameters)
91             throws XacmlApplicationException {
92         //
93         // Store our API parameters and path for translator so it
94         // can go get Policy Types
95         //
96         this.translator.setPathForData(pathForData);
97         this.translator.setApiRestParameters(policyApiParameters);
98         //
99         // Let our super class do its thing
100         //
101         super.initialize(pathForData, policyApiParameters);
102     }
103
104     @Override
105     public boolean canSupportPolicyType(ToscaConceptIdentifier policyTypeId) {
106         //
107         // For the time being, restrict this if the version isn't known.
108         // Could be too difficult to support changing of versions dynamically.
109         //
110         for (ToscaConceptIdentifier supported : this.supportedPolicyTypes) {
111             if (policyTypeId.equals(supported)) {
112                 LOGGER.info("optimization can support {}", supported);
113                 return true;
114             }
115         }
116         //
117         // Support derived types
118         //
119         return policyTypeId.getName().startsWith(ONAP_OPTIMIZATION_DERIVED_POLICY_TYPE);
120     }
121
122     @Override
123     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
124             Map<String, String[]> requestQueryParams) {
125         //
126         // In case we have a subcriber policy
127         //
128         Response xacmlSubscriberResponse = null;
129         //
130         // Check if there are subject attributes for subscriber
131         //
132         if (hasSubscriberAttributes(request)) {
133             //
134             // We must do an initial request to pull subscriber attributes
135             //
136             LOGGER.info("Request Subscriber attributes");
137             //
138             // Convert the request
139             //
140             DecisionRequest subscriberRequest = new DecisionRequest(request);
141             //
142             // Override the PolicyType to ensure we are only looking at Subscriber Policies
143             //
144             if (subscriberRequest.getResource().containsKey(RESOURCE_POLICYTYPE)) {
145                 subscriberRequest.getResource().remove(RESOURCE_POLICYTYPE);
146             }
147             subscriberRequest.getResource().put(RESOURCE_POLICYTYPE, POLICYTYPE_SUBSCRIBER);
148             //
149             // Convert to a XacmlRequest and get a decision
150             //
151             try {
152                 xacmlSubscriberResponse =
153                         this.xacmlDecision(OptimizationSubscriberRequest.createInstance(subscriberRequest));
154             } catch (XacmlApplicationException e) {
155                 LOGGER.error("Could not create subscriberName request", e);
156             }
157             //
158             // Check the response for subscriber attributes and add them
159             // to the initial request.
160             //
161             if (xacmlSubscriberResponse != null && ! addSubscriberAttributes(xacmlSubscriberResponse, request)) {
162                 LOGGER.error("Failed to get subscriber role attributes");
163                 //
164                 // Convert to a DecisionResponse
165                 //
166                 return Pair.of(this.getTranslator().convertResponse(xacmlSubscriberResponse), xacmlSubscriberResponse);
167             }
168         }
169         //
170         // Make the decision
171         //
172         Pair<DecisionResponse, Response> decisionPair = super.makeDecision(request, requestQueryParams);
173         //
174         // Add back in advice from subscriber
175         //
176         if (xacmlSubscriberResponse != null) {
177             addSubscriberAdvice(xacmlSubscriberResponse, decisionPair.getLeft());
178         }
179         return decisionPair;
180     }
181
182     @Override
183     protected ToscaPolicyTranslator getTranslator(String type) {
184         //
185         // Return translator
186         //
187         return translator;
188     }
189
190     @SuppressWarnings("unchecked")
191     private boolean hasSubscriberAttributes(DecisionRequest request) {
192         return request.getContext() != null
193                 && request.getContext().containsKey(RESOURCE_SUBSCRIBERNAME)
194                 && request.getContext().get(RESOURCE_SUBSCRIBERNAME) instanceof List
195                 && ! ((List<String>) request.getContext().get(RESOURCE_SUBSCRIBERNAME)).isEmpty();
196     }
197
198     private boolean addSubscriberAttributes(Response xacmlResponse, DecisionRequest initialRequest) {
199         //
200         // This has multiple results right now because of how the attributes were added to the
201         // request. That will have to be fixed in the future, for now find the Permit result
202         // and add the role attributes as they will be used in the next request.
203         //
204         for (Result result : xacmlResponse.getResults()) {
205             //
206             // Check the result
207             //
208             if (result.getStatus().isOk() && result.getDecision().equals(Decision.PERMIT)) {
209                 //
210                 // Pull out the advice which has attributes
211                 //
212                 scanAdvice(result.getAssociatedAdvice(), initialRequest);
213                 //
214                 // PLD this is an assumption that all is good
215                 //
216                 return true;
217             } else {
218                 LOGGER.error("XACML result not ok {} or Permit {}", result.getStatus(), result.getDecision());
219             }
220         }
221         return false;
222     }
223
224     private void addSubscriberAdvice(Response xacmlResponse, DecisionResponse response) {
225         //
226         // Again find the Permit result
227         //
228         for (Result result : xacmlResponse.getResults()) {
229             //
230             // Check the result
231             //
232             if (result.getStatus().isOk() && Decision.PERMIT.equals(result.getDecision())) {
233                 this.translator.scanAdvice(result.getAssociatedAdvice(), response);
234             }
235         }
236     }
237
238
239     @SuppressWarnings("unchecked")
240     private void scanAdvice(Collection<Advice> adviceCollection, DecisionRequest initialRequest) {
241         //
242         // There really should only be one advice object
243         //
244         for (Advice advice : adviceCollection) {
245             //
246             // Look for the optimization specific advice
247             //
248             if (! ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER.equals(advice.getId())) {
249                 LOGGER.error("Unsupported advice id {}", advice.getId());
250                 continue;
251             }
252             //
253             // Get the attributes and add them
254             //
255             for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
256                 //
257                 // If this is subscriber role
258                 //
259                 if (ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_ROLE.equals(attribute.getAttributeId())) {
260                     ((List<String>) initialRequest.getResource().get(RESOURCE_SCOPE))
261                             .add(attribute.getAttributeValue().getValue().toString());
262                 }
263             }
264         }
265     }
266
267 }