Add Control Loop Coordination policy.
[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
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.nio.file.Paths;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Properties;
42
43 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
44
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     private Properties pdpProperties = null;
62     private PDPEngine pdpEngine = null;
63
64     public StdXacmlApplicationServiceProvider() {
65         super();
66     }
67
68     @Override
69     public String applicationName() {
70         return "Please Override";
71     }
72
73     @Override
74     public List<String> actionDecisionsSupported() {
75         return Collections.emptyList();
76     }
77
78     @Override
79     public void initialize(Path pathForData) throws XacmlApplicationException {
80         //
81         // Save our path
82         //
83         this.pathForData = pathForData;
84         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
85         //
86         // Ensure properties exist
87         //
88         Path propertiesPath = XacmlPolicyUtils.getPropertiesPath(pathForData);
89         if (! propertiesPath.toFile().exists()) {
90             LOGGER.info("Copying src/main/resources/xacml.properties to path");
91             //
92             // Properties do not exist, by default we will copy ours over
93             // from src/main/resources
94             //
95             try {
96                 Files.copy(Paths.get("src/main/resources/xacml.properties"), propertiesPath);
97             } catch (IOException e) {
98                 throw new XacmlApplicationException("Failed to copy xacml.propertis", e);
99             }
100         }
101         //
102         // Look for and load the properties object
103         //
104         try {
105             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
106             LOGGER.debug("{}", pdpProperties);
107         } catch (IOException e) {
108             throw new XacmlApplicationException("Failed to load xacml.propertis", e);
109         }
110         //
111         // Create an engine
112         //
113         createEngine(pdpProperties);
114     }
115
116     @Override
117     public List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
118         return Collections.emptyList();
119     }
120
121     @Override
122     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
123         throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
124     }
125
126     @Override
127     public synchronized void loadPolicy(ToscaPolicy toscaPolicy) {
128         try {
129             //
130             // Convert the policies first
131             //
132             PolicyType xacmlPolicy = this.getTranslator(toscaPolicy.getType())
133                 .convertPolicy(toscaPolicy);
134             if (xacmlPolicy == null) {
135                 throw new ToscaPolicyConversionException("Failed to convert policy");
136             }
137             //
138             // Create a copy of the properties object
139             //
140             Properties newProperties = this.getProperties();
141             //
142             // Construct the filename
143             //
144             Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
145             //
146             // Write the policy to disk
147             // Maybe check for an error
148             //
149             XACMLPolicyWriter.writePolicyFile(refPath, xacmlPolicy);
150             if (LOGGER.isDebugEnabled()) {
151                 LOGGER.debug("Xacml Policy is {}{}", System.lineSeparator(), new String(Files.readAllBytes(refPath)));
152             }
153             //
154             // Add root policy to properties object
155             //
156             XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
157             //
158             // Write the properties to disk
159             //
160             XacmlPolicyUtils.storeXacmlProperties(newProperties,
161                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
162             //
163             // Reload the engine
164             //
165             this.createEngine(newProperties);
166             //
167             // Save the properties
168             //
169             this.pdpProperties = newProperties;
170         } catch (IOException | ToscaPolicyConversionException e) {
171             LOGGER.error("Failed to loadPolicies {}", e);
172         }
173     }
174
175     @Override
176     public synchronized DecisionResponse makeDecision(DecisionRequest request) {
177         //
178         // Convert to a XacmlRequest
179         //
180         Request xacmlRequest = this.getTranslator().convertRequest(request);
181         //
182         // Now get a decision
183         //
184         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
185         //
186         // Convert to a DecisionResponse
187         //
188         return this.getTranslator().convertResponse(xacmlResponse);
189     }
190
191     protected abstract ToscaPolicyTranslator getTranslator(String type);
192
193     protected ToscaPolicyTranslator getTranslator() {
194         return this.getTranslator("");
195     }
196
197     protected synchronized PDPEngine getEngine() {
198         return this.pdpEngine;
199     }
200
201     protected synchronized Properties getProperties() {
202         Properties newProperties = new Properties();
203         newProperties.putAll(pdpProperties);
204         return newProperties;
205     }
206
207     protected synchronized Path getDataPath() {
208         return pathForData;
209     }
210
211     /**
212      * Load properties from given file.
213      *
214      * @throws IOException If unable to read file
215      */
216     protected synchronized Properties loadXacmlProperties() throws IOException {
217         LOGGER.debug("Loading xacml properties {}", pathForData);
218         try (InputStream is = Files.newInputStream(pathForData)) {
219             Properties properties = new Properties();
220             properties.load(is);
221             return properties;
222         }
223     }
224
225     /**
226      * Stores the XACML Properties to the given file location.
227      *
228      * @throws IOException If unable to store the file.
229      */
230     protected synchronized void storeXacmlProperties() throws IOException {
231         try (OutputStream os = Files.newOutputStream(pathForData)) {
232             String strComments = "#";
233             pdpProperties.store(os, strComments);
234         }
235     }
236
237     /**
238      * Appends 'xacml.properties' to a root Path object
239      *
240      * @return Path to rootPath/xacml.properties file
241      */
242     protected synchronized Path getPropertiesPath() {
243         return Paths.get(pathForData.toAbsolutePath().toString(), "xacml.properties");
244     }
245
246     /**
247      * Creates an instance of PDP engine given the Properties object.
248      */
249     protected synchronized void createEngine(Properties properties) {
250         //
251         // Now initialize the XACML PDP Engine
252         //
253         try {
254             PDPEngineFactory factory = PDPEngineFactory.newInstance();
255             PDPEngine engine = factory.newEngine(properties);
256             if (engine != null) {
257                 this.pdpEngine = engine;
258             }
259         } catch (FactoryException e) {
260             LOGGER.error("Failed to create XACML PDP Engine {}", e);
261         }
262     }
263
264     /**
265      * Make a decision call.
266      *
267      * @param request Incoming request object
268      * @return Response object
269      */
270     protected synchronized Response xacmlDecision(Request request) {
271         //
272         // This is what we need to return
273         //
274         Response response = null;
275         //
276         // Track some timing
277         //
278         long timeStart = System.currentTimeMillis();
279         try {
280             response = this.pdpEngine.decide(request);
281         } catch (PDPException e) {
282             LOGGER.error("Xacml PDP Engine failed {}", e);
283         } finally {
284             //
285             // Track the end of timing
286             //
287             long timeEnd = System.currentTimeMillis();
288             LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));
289         }
290         return response;
291     }
292
293 }