2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
 
   6  * Modifications Copyright (C) 2021 Nordix Foundation.
 
   7  * ================================================================================
 
   8  * Licensed under the Apache License, Version 2.0 (the "License");
 
   9  * you may not use this file except in compliance with the License.
 
  10  * You may obtain a copy of the License at
 
  12  *      http://www.apache.org/licenses/LICENSE-2.0
 
  14  * Unless required by applicable law or agreed to in writing, software
 
  15  * distributed under the License is distributed on an "AS IS" BASIS,
 
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  17  * See the License for the specific language governing permissions and
 
  18  * limitations under the License.
 
  20  * SPDX-License-Identifier: Apache-2.0
 
  21  * ============LICENSE_END=========================================================
 
  24 package org.onap.policy.pdp.xacml.application.common.std;
 
  26 import com.att.research.xacml.api.Request;
 
  27 import com.att.research.xacml.api.Response;
 
  28 import com.att.research.xacml.api.pdp.PDPEngine;
 
  29 import com.att.research.xacml.api.pdp.PDPEngineFactory;
 
  30 import com.att.research.xacml.api.pdp.PDPException;
 
  31 import com.att.research.xacml.util.FactoryException;
 
  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.ArrayList;
 
  37 import java.util.Collections;
 
  38 import java.util.HashMap;
 
  39 import java.util.List;
 
  41 import java.util.Properties;
 
  43 import org.apache.commons.lang3.tuple.Pair;
 
  44 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
 
  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.ToscaConceptIdentifier;
 
  48 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
  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;
 
  57 public abstract class StdXacmlApplicationServiceProvider implements XacmlApplicationServiceProvider {
 
  59     private static final Logger LOGGER = LoggerFactory.getLogger(StdXacmlApplicationServiceProvider.class);
 
  61     protected String applicationName = "Please Override";
 
  62     protected List<String> actions = Collections.emptyList();
 
  63     protected List<ToscaConceptIdentifier> supportedPolicyTypes = new ArrayList<>();
 
  65     private Path pathForData = null;
 
  67     private BusTopicParams policyApiParameters;
 
  68     private Properties pdpProperties = null;
 
  69     private PDPEngine pdpEngine = null;
 
  70     private Map<ToscaPolicy, Path> mapLoadedPolicies = new HashMap<>();
 
  72     protected StdXacmlApplicationServiceProvider() {
 
  77     public String applicationName() {
 
  78         return applicationName;
 
  82     public List<String> actionDecisionsSupported() {
 
  87     public void initialize(Path pathForData, BusTopicParams policyApiParameters)
 
  88             throws XacmlApplicationException {
 
  92         this.pathForData = pathForData;
 
  93         LOGGER.info("New Path is {}", this.pathForData.toAbsolutePath());
 
  97         this.policyApiParameters = policyApiParameters;
 
  99         // Look for and load the properties object
 
 102             pdpProperties = XacmlPolicyUtils.loadXacmlProperties(XacmlPolicyUtils.getPropertiesPath(pathForData));
 
 103             LOGGER.info("{}", pdpProperties);
 
 104         } catch (IOException e) {
 
 105             throw new XacmlApplicationException("Failed to load " + XacmlPolicyUtils.XACML_PROPERTY_FILE, e);
 
 110         createEngine(pdpProperties);
 
 114     public List<ToscaConceptIdentifier> supportedPolicyTypes() {
 
 115         return supportedPolicyTypes;
 
 119     public boolean canSupportPolicyType(ToscaConceptIdentifier policyTypeId) {
 
 120         throw new UnsupportedOperationException("Please override and implement canSupportPolicyType");
 
 124     public synchronized void loadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
 
 127             // Convert the policies first
 
 129             Object xacmlPolicy = this.getTranslator(toscaPolicy.getType()).convertPolicy(toscaPolicy);
 
 130             if (xacmlPolicy == null) {
 
 131                 throw new ToscaPolicyConversionException("Failed to convert policy");
 
 134             // Create a copy of the properties object
 
 136             Properties newProperties = this.getProperties();
 
 138             // Construct the filename
 
 140             Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(xacmlPolicy, this.getDataPath());
 
 142             // Write the policy to disk
 
 143             // Maybe check for an error
 
 145             if (XacmlPolicyUtils.writePolicyFile(refPath, xacmlPolicy) == null) {
 
 146                 throw new ToscaPolicyConversionException("Unable to writePolicyFile");
 
 148             if (LOGGER.isInfoEnabled()) {
 
 149                 LOGGER.info("Xacml Policy is {}{}", XacmlPolicyUtils.LINE_SEPARATOR,
 
 150                     new String(Files.readAllBytes(refPath), StandardCharsets.UTF_8));
 
 153             // Add root policy to properties object
 
 155             XacmlPolicyUtils.addRootPolicy(newProperties, refPath);
 
 157             // Write the properties to disk
 
 159             XacmlPolicyUtils.storeXacmlProperties(newProperties,
 
 160                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
 
 164             this.createEngine(newProperties);
 
 166             // Save the properties
 
 168             this.pdpProperties = newProperties;
 
 172             this.mapLoadedPolicies.put(toscaPolicy, refPath);
 
 173         } catch (IOException | ToscaPolicyConversionException e) {
 
 174             throw new XacmlApplicationException("loadPolicy failed", e);
 
 179     public synchronized boolean unloadPolicy(ToscaPolicy toscaPolicy) throws XacmlApplicationException {
 
 181         // Find it in our map
 
 183         Path refPolicy = this.mapLoadedPolicies.get(toscaPolicy);
 
 184         if (refPolicy == null) {
 
 185             LOGGER.error("Failed to find ToscaPolicy {} in our map size {}", toscaPolicy.getMetadata(),
 
 186                     this.mapLoadedPolicies.size());
 
 190         // Create a copy of the properties object
 
 192         Properties newProperties = this.getProperties();
 
 194         // Remove it from the properties
 
 196         XacmlPolicyUtils.removeRootPolicy(newProperties, refPolicy);
 
 198         // We can delete the file
 
 201             Files.delete(refPolicy);
 
 202         } catch (IOException e) {
 
 203             LOGGER.error("Failed to delete policy {} from disk {}", toscaPolicy.getMetadata(),
 
 204                     refPolicy.toAbsolutePath(), e);
 
 207         // Write the properties to disk
 
 210             XacmlPolicyUtils.storeXacmlProperties(newProperties,
 
 211                     XacmlPolicyUtils.getPropertiesPath(this.getDataPath()));
 
 212         } catch (IOException e) {
 
 213             LOGGER.error("Failed to save the properties to disk {}", newProperties, e);
 
 218         this.createEngine(newProperties);
 
 220         // Save the properties
 
 222         this.pdpProperties = newProperties;
 
 226         if (this.mapLoadedPolicies.remove(toscaPolicy) == null) {
 
 227             LOGGER.error("Failed to remove toscaPolicy {} from internal map size {}", toscaPolicy.getMetadata(),
 
 228                     this.mapLoadedPolicies.size());
 
 231         // Not sure if any of the errors above warrant returning false
 
 237     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
 
 238             Map<String, String[]> requestQueryParams) {
 
 240         // Convert to a XacmlRequest
 
 242         Request xacmlRequest;
 
 244             xacmlRequest = this.getTranslator().convertRequest(request);
 
 245         } catch (ToscaPolicyConversionException e) {
 
 246             LOGGER.error("Failed to convert request", e);
 
 247             DecisionResponse response = new DecisionResponse();
 
 248             response.setStatus("error");
 
 249             response.setMessage(e.getLocalizedMessage());
 
 250             return Pair.of(response, null);
 
 253         // Now get a decision
 
 255         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
 
 257         // Convert to a DecisionResponse
 
 259         return Pair.of(this.getTranslator().convertResponse(xacmlResponse), xacmlResponse);
 
 262     protected abstract ToscaPolicyTranslator getTranslator(String type);
 
 264     protected ToscaPolicyTranslator getTranslator() {
 
 265         return this.getTranslator("");
 
 268     protected synchronized PDPEngine getEngine() {
 
 269         return this.pdpEngine;
 
 272     protected synchronized Properties getProperties() {
 
 273         Properties newProperties = new Properties();
 
 274         newProperties.putAll(pdpProperties);
 
 275         return newProperties;
 
 278     protected synchronized Path getDataPath() {
 
 283      * Creates an instance of PDP engine given the Properties object.
 
 285     protected synchronized void createEngine(Properties properties) {
 
 287         // Now initialize the XACML PDP Engine
 
 290             PDPEngineFactory factory = getPdpEngineFactory();
 
 291             PDPEngine engine = factory.newEngine(properties);
 
 292             if (engine != null) {
 
 294                 // If there is a previous engine have it shutdown.
 
 296                 this.destroyEngine();
 
 300                 this.pdpEngine = engine;
 
 302         } catch (FactoryException e) {
 
 303             LOGGER.error("Failed to create XACML PDP Engine", e);
 
 307     protected synchronized void destroyEngine() {
 
 308         if (this.pdpEngine == null) {
 
 312             this.pdpEngine.shutdown();
 
 313         } catch (Exception e) {
 
 314             LOGGER.warn("Exception thrown when destroying XACML PDP engine.", e);
 
 316         this.pdpEngine = null;
 
 320      * Make a decision call.
 
 322      * @param request Incoming request object
 
 323      * @return Response object
 
 325     protected synchronized Response xacmlDecision(Request request) {
 
 327         // This is what we need to return
 
 329         Response response = null;
 
 333         long timeStart = System.currentTimeMillis();
 
 335             response = this.pdpEngine.decide(request);
 
 336         } catch (PDPException e) {
 
 337             LOGGER.error("Xacml PDP Engine decide failed", e);
 
 340             // Track the end of timing
 
 342             long timeEnd = System.currentTimeMillis();
 
 343             LOGGER.info("Elapsed Time: {}ms", (timeEnd - timeStart));
 
 348     // these may be overridden by junit tests
 
 350     protected PDPEngineFactory getPdpEngineFactory() throws FactoryException {
 
 351         return PDPEngineFactory.newInstance();