Consolidate common translatable code some sonar
[policy/xacml-pdp.git] / applications / common / src / main / java / org / onap / policy / pdp / xacml / application / common / std / StdXacmlApplicationServiceProvider.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019 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.pdp.xacml.application.common.std;
24
25 import com.att.research.xacml.api.Request;
26 import com.att.research.xacml.api.Response;
27 import com.att.research.xacml.api.pdp.PDPEngine;
28 import com.att.research.xacml.api.pdp.PDPEngineFactory;
29 import com.att.research.xacml.api.pdp.PDPException;
30 import com.att.research.xacml.util.FactoryException;
31 import com.att.research.xacml.util.XACMLPolicyWriter;
32 import java.io.IOException;
33 import java.nio.charset.StandardCharsets;
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Properties;
41 import lombok.Getter;
42 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
43 import org.apache.commons.lang3.tuple.Pair;
44 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
45 import org.onap.policy.models.decisions.concepts.DecisionRequest;
46 import org.onap.policy.models.decisions.concepts.DecisionResponse;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
49 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
50 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
51 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
52 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
53 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
58
59     private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
60     private Path pathForData = null;
61     @Getter
62     private RestServerParameters policyApiParameters;
63     private Properties pdpProperties = null;
64     private PDPEngine pdpEngine = null;
65     private Map<ToscaPolicy, Path> mapLoadedPolicies = new HashMap<>();
66
67     public StdXacmlApplicationServiceProvider() {
68         super();
69     }
70
71     @Override
72     public String applicationName() {
73         return "Please Override";
74     }
75
76     @Override
77     public List<String> actionDecisionsSupported() {
78         return Collections.emptyList();
79     }
80
81     @Override
82     public void initialize(Path pathForData, RestServerParameters policyApiParameters)
83             throws XacmlApplicationException {
84         //
85         // Save our path
86         //
87         this.pathForData = pathForData;
88         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
89         //
90         // Save our params
91         //
92         this.policyApiParameters = policyApiParameters;
93         //
94         // Look for and load the properties object
95         //
96         try {
97             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
98             LOGGER.info("{}", pdpProperties);
99         } catch (IOException e) {
100             throw new XacmlApplicationException("Failed to load " + XacmlPolicyUtils.XACML_PROPERTY_FILE, e);
101         }
102         //
103         // Create an engine
104         //
105         createEngine(pdpProperties);
106     }
107
108     @Override
109     public List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
110         throw new UnsupportedOperationException("Please override and implement supportedPolicyTypes");
111     }
112
113     @Override
114     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
115         throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
116     }
117
118     @Override
119     public synchronized boolean loadPolicy(ToscaPolicy toscaPolicy) {
120         try {
121             //
122             // Convert the policies first
123             //
124             PolicyType xacmlPolicy = this.getTranslator(toscaPolicy.getType())
125                 .convertPolicy(toscaPolicy);
126             if (xacmlPolicy == null) {
127                 throw new ToscaPolicyConversionException("Failed to convert policy");
128             }
129             //
130             // Create a copy of the properties object
131             //
132             Properties newProperties = this.getProperties();
133             //
134             // Construct the filename
135             //
136             Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
137             //
138             // Write the policy to disk
139             // Maybe check for an error
140             //
141             XACMLPolicyWriter.writePolicyFile(refPath, xacmlPolicy);
142             if (LOGGER.isInfoEnabled()) {
143                 LOGGER.info("Xacml Policy is {}{}", XacmlPolicyUtils.LINE_SEPARATOR,
144                     new String(Files.readAllBytes(refPath), StandardCharsets.UTF_8));
145             }
146             //
147             // Add root policy to properties object
148             //
149             XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
150             //
151             // Write the properties to disk
152             //
153             XacmlPolicyUtils.storeXacmlProperties(newProperties,
154                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
155             //
156             // Reload the engine
157             //
158             this.createEngine(newProperties);
159             //
160             // Save the properties
161             //
162             this.pdpProperties = newProperties;
163             //
164             // Save in our map
165             //
166             this.mapLoadedPolicies.put(toscaPolicy, refPath);
167         } catch (IOException | ToscaPolicyConversionException e) {
168             LOGGER.error("Failed to loadPolicies {}", e);
169             return false;
170         }
171         return true;
172     }
173
174     @Override
175     public synchronized boolean unloadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
176         //
177         // Find it in our map
178         //
179         Path refPolicy = this.mapLoadedPolicies.get(toscaPolicy);
180         if (refPolicy == null) {
181             LOGGER.error("Failed to find ToscaPolicy {} in our map size {}", toscaPolicy.getMetadata(),
182                     this.mapLoadedPolicies.size());
183             return false;
184         }
185         //
186         // Create a copy of the properties object
187         //
188         Properties newProperties = this.getProperties();
189         //
190         // Remove it from the properties
191         //
192         XacmlPolicyUtils.removeRootPolicy(newProperties, refPolicy);
193         //
194         // We can delete the file
195         //
196         try {
197             Files.delete(refPolicy);
198         } catch (IOException e) {
199             LOGGER.error("Failed to delete policy {} from disk {}", toscaPolicy.getMetadata(),
200                     refPolicy.toAbsolutePath().toString(), e);
201         }
202         //
203         // Write the properties to disk
204         //
205         try {
206             XacmlPolicyUtils.storeXacmlProperties(newProperties,
207                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
208         } catch (IOException e) {
209             LOGGER.error("Failed to save the properties to disk {}", newProperties, e);
210         }
211         //
212         // Reload the engine
213         //
214         this.createEngine(newProperties);
215         //
216         // Save the properties
217         //
218         this.pdpProperties = newProperties;
219         //
220         // Save in our map
221         //
222         if (this.mapLoadedPolicies.remove(toscaPolicy) == null) {
223             LOGGER.error("Failed to remove toscaPolicy {} from internal map size {}", toscaPolicy.getMetadata(),
224                     this.mapLoadedPolicies.size());
225         }
226         //
227         // Not sure if any of the errors above warrant returning false
228         //
229         return true;
230     }
231
232     @Override
233     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
234             Map<String, String[]> requestQueryParams) {
235         //
236         // Convert to a XacmlRequest
237         //
238         Request xacmlRequest = this.getTranslator().convertRequest(request);
239         //
240         // Now get a decision
241         //
242         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
243         //
244         // Convert to a DecisionResponse
245         //
246         return Pair.of(this.getTranslator().convertResponse(xacmlResponse), xacmlResponse);
247     }
248
249     protected abstract ToscaPolicyTranslator getTranslator(String type);
250
251     protected ToscaPolicyTranslator getTranslator() {
252         return this.getTranslator("");
253     }
254
255     protected synchronized PDPEngine getEngine() {
256         return this.pdpEngine;
257     }
258
259     protected synchronized Properties getProperties() {
260         Properties newProperties = new Properties();
261         newProperties.putAll(pdpProperties);
262         return newProperties;
263     }
264
265     protected synchronized Path getDataPath() {
266         return pathForData;
267     }
268
269     /**
270      * Creates an instance of PDP engine given the Properties object.
271      */
272     protected synchronized void createEngine(Properties properties) {
273         //
274         // Now initialize the XACML PDP Engine
275         //
276         try {
277             PDPEngineFactory factory = getPdpEngineFactory();
278             PDPEngine engine = factory.newEngine(properties);
279             if (engine != null) {
280                 this.pdpEngine = engine;
281             }
282         } catch (FactoryException e) {
283             LOGGER.error("Failed to create XACML PDP Engine {}", e);
284         }
285     }
286
287     /**
288      * Make a decision call.
289      *
290      * @param request Incoming request object
291      * @return Response object
292      */
293     protected synchronized Response xacmlDecision(Request request) {
294         //
295         // This is what we need to return
296         //
297         Response response = null;
298         //
299         // Track some timing
300         //
301         long timeStart = System.currentTimeMillis();
302         try {
303             response = this.pdpEngine.decide(request);
304         } catch (PDPException e) {
305             LOGGER.error("Xacml PDP Engine failed {}", e);
306         } finally {
307             //
308             // Track the end of timing
309             //
310             long timeEnd = System.currentTimeMillis();
311             LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));
312         }
313         return response;
314     }
315
316     // these may be overridden by junit tests
317
318     protected PDPEngineFactory getPdpEngineFactory() throws FactoryException {
319         return PDPEngineFactory.newInstance();
320     }
321 }