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