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