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