2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2019-2020 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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  19  * SPDX-License-Identifier: Apache-2.0
 
  20  * ============LICENSE_END=========================================================
 
  23 package org.onap.policy.xacml.pdp.application.optimization;
 
  25 import com.att.research.xacml.api.Advice;
 
  26 import com.att.research.xacml.api.AttributeAssignment;
 
  27 import com.att.research.xacml.api.Decision;
 
  28 import com.att.research.xacml.api.Request;
 
  29 import com.att.research.xacml.api.Response;
 
  30 import com.att.research.xacml.api.Result;
 
  31 import java.nio.file.Path;
 
  32 import java.util.ArrayList;
 
  33 import java.util.Arrays;
 
  34 import java.util.Collection;
 
  35 import java.util.Collections;
 
  36 import java.util.List;
 
  38 import org.apache.commons.lang3.tuple.Pair;
 
  39 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
 
  40 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 
  41 import org.onap.policy.models.decisions.concepts.DecisionResponse;
 
  42 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
 
  43 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
 
  44 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
 
  45 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
 
  46 import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider;
 
  47 import org.slf4j.Logger;
 
  48 import org.slf4j.LoggerFactory;
 
  50 public class OptimizationPdpApplication extends StdXacmlApplicationServiceProvider {
 
  52     private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplication.class);
 
  53     private static final String STRING_VERSION100 = "1.0.0";
 
  54     private static final String RESOURCE_SUBSCRIBERNAME = "subscriberName";
 
  55     private static final String RESOURCE_POLICYTYPE = "policy-type";
 
  56     private static final String RESOURCE_SCOPE = "scope";
 
  58     public static final String POLICYTYPE_AFFINITY = "onap.policies.optimization.resource.AffinityPolicy";
 
  59     public static final String POLICYTYPE_SUBSCRIBER = "onap.policies.optimization.service.SubscriberPolicy";
 
  60     public static final String POLICYTYPE_DISTANCE = "onap.policies.optimization.resource.DistancePolicy";
 
  61     public static final String POLICYTYPE_HPA = "onap.policies.optimization.resource.HpaPolicy";
 
  62     public static final String POLICYTYPE_OPTIMIZATION = "onap.policies.optimization.resource.OptimizationPolicy";
 
  63     public static final String POLICYTYPE_PCI = "onap.policies.optimization.resource.PciPolicy";
 
  64     public static final String POLICYTYPE_QUERY = "onap.policies.optimization.service.QueryPolicy";
 
  65     public static final String POLICYTYPE_VIMFIT = "onap.policies.optimization.resource.Vim_fit";
 
  66     public static final String POLICYTYPE_VNF = "onap.policies.optimization.resource.VnfPolicy";
 
  68     private OptimizationPdpApplicationTranslator translator = new OptimizationPdpApplicationTranslator();
 
  69     private List<ToscaPolicyTypeIdentifier> supportedPolicyTypes = new ArrayList<>();
 
  74     public OptimizationPdpApplication() {
 
  75         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_AFFINITY, STRING_VERSION100));
 
  76         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_DISTANCE, STRING_VERSION100));
 
  77         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_HPA, STRING_VERSION100));
 
  78         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_OPTIMIZATION, STRING_VERSION100));
 
  79         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_PCI, STRING_VERSION100));
 
  80         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_QUERY, STRING_VERSION100));
 
  81         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_SUBSCRIBER, STRING_VERSION100));
 
  82         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_VIMFIT, STRING_VERSION100));
 
  83         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(POLICYTYPE_VNF, STRING_VERSION100));
 
  87     public String applicationName() {
 
  88         return "optimization";
 
  92     public List<String> actionDecisionsSupported() {
 
  93         return Arrays.asList("optimize");
 
  97     public void initialize(Path pathForData, RestServerParameters policyApiParameters)
 
  98             throws XacmlApplicationException {
 
 100         // Store our API parameters and path for translator so it
 
 101         // can go get Policy Types
 
 103         this.translator.setPathForData(pathForData);
 
 104         this.translator.setApiRestParameters(policyApiParameters);
 
 106         // Let our super class do its thing
 
 108         super.initialize(pathForData, policyApiParameters);
 
 112     public synchronized List<ToscaPolicyTypeIdentifier> supportedPolicyTypes() {
 
 113         return Collections.unmodifiableList(supportedPolicyTypes);
 
 117     public boolean canSupportPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
 
 119         // For the time being, restrict this if the version isn't known.
 
 120         // Could be too difficult to support changing of versions dynamically.
 
 123         // For the time being, restrict this if the version isn't known.
 
 124         // Could be too difficult to support changing of versions dynamically.
 
 126         for (ToscaPolicyTypeIdentifier supported : this.supportedPolicyTypes) {
 
 127             if (policyTypeId.equals(supported)) {
 
 128                 LOGGER.info("optimization can support {}", supported);
 
 136     public Pair<DecisionResponse, Response> makeDecision(DecisionRequest request,
 
 137             Map<String, String[]> requestQueryParams) {
 
 139         // In case we have a subcriber policy
 
 141         Response xacmlSubscriberResponse = null;
 
 143         // Check if there are subject attributes for subscriber
 
 145         if (hasSubscriberAttributes(request)) {
 
 147             // We must do an initial request to pull subscriber attributes
 
 149             LOGGER.info("Request Subscriber attributes");
 
 151             // Convert the request
 
 153             DecisionRequest subscriberRequest = new DecisionRequest(request);
 
 155             // Override the PolicyType to ensure we are only looking at Subscriber Policies
 
 157             if (subscriberRequest.getResource().containsKey(RESOURCE_POLICYTYPE)) {
 
 158                 subscriberRequest.getResource().remove(RESOURCE_POLICYTYPE);
 
 160             subscriberRequest.getResource().put(RESOURCE_POLICYTYPE, POLICYTYPE_SUBSCRIBER);
 
 162             // Convert to a XacmlRequest and get a decision
 
 165                 xacmlSubscriberResponse =
 
 166                         this.xacmlDecision(OptimizationSubscriberRequest.createInstance(subscriberRequest));
 
 167             } catch (XacmlApplicationException e) {
 
 168                 LOGGER.error("Could not create subscriberName request", e);
 
 171             // Check the response for subscriber attributes and add them
 
 172             // to the initial request.
 
 174             if (xacmlSubscriberResponse != null && ! addSubscriberAttributes(xacmlSubscriberResponse, request)) {
 
 175                 LOGGER.error("Failed to get subscriber role attributes");
 
 177                 // Convert to a DecisionResponse
 
 179                 return Pair.of(this.getTranslator().convertResponse(xacmlSubscriberResponse), xacmlSubscriberResponse);
 
 183         // Convert to a XacmlRequest
 
 185         Request xacmlRequest = this.getTranslator().convertRequest(request);
 
 187         // Now get a decision
 
 189         Response xacmlResponse = this.xacmlDecision(xacmlRequest);
 
 191         // Convert to a DecisionResponse
 
 193         Pair<DecisionResponse, Response> returnPair = Pair.of(this.getTranslator().convertResponse(xacmlResponse),
 
 196         // Add back in advice from subscriber
 
 198         if (xacmlSubscriberResponse != null) {
 
 199             addSubscriberAdvice(xacmlSubscriberResponse, returnPair.getLeft());
 
 205     protected ToscaPolicyTranslator getTranslator(String type) {
 
 212     @SuppressWarnings("unchecked")
 
 213     private boolean hasSubscriberAttributes(DecisionRequest request) {
 
 214         return request.getContext() != null
 
 215                 && request.getContext().containsKey(RESOURCE_SUBSCRIBERNAME)
 
 216                 && request.getContext().get(RESOURCE_SUBSCRIBERNAME) instanceof List
 
 217                 && ! ((List<String>) request.getContext().get(RESOURCE_SUBSCRIBERNAME)).isEmpty();
 
 220     private boolean addSubscriberAttributes(Response xacmlResponse, DecisionRequest initialRequest) {
 
 222         // This has multiple results right now because of how the attributes were added to the
 
 223         // request. That will have to be fixed in the future, for now find the Permit result
 
 224         // and add the role attributes as they will be used in the next request.
 
 226         for (Result result : xacmlResponse.getResults()) {
 
 230             if (result.getStatus().isOk() && result.getDecision().equals(Decision.PERMIT)) {
 
 232                 // Pull out the advice which has attributes
 
 234                 scanAdvice(result.getAssociatedAdvice(), initialRequest);
 
 236                 // PLD this is an assumption that all is good
 
 240                 LOGGER.error("XACML result not ok {} or Permit {}", result.getStatus(), result.getDecision());
 
 246     private void addSubscriberAdvice(Response xacmlResponse, DecisionResponse response) {
 
 248         // Again find the Permit result
 
 250         for (Result result : xacmlResponse.getResults()) {
 
 254             if (result.getStatus().isOk() && Decision.PERMIT.equals(result.getDecision())) {
 
 255                 this.translator.scanAdvice(result.getAssociatedAdvice(), response);
 
 261     @SuppressWarnings("unchecked")
 
 262     private void scanAdvice(Collection<Advice> adviceCollection, DecisionRequest initialRequest) {
 
 264         // There really should only be one advice object
 
 266         for (Advice advice : adviceCollection) {
 
 268             // Look for the optimization specific advice
 
 270             if (! ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER.equals(advice.getId())) {
 
 271                 LOGGER.error("Unsupported advice id {}", advice.getId());
 
 275             // Get the attributes and add them
 
 277             for (AttributeAssignment attribute : advice.getAttributeAssignments()) {
 
 279                 // If this is subscriber role
 
 281                 if (ToscaDictionary.ID_ADVICE_OPTIMIZATION_SUBSCRIBER_ROLE.equals(attribute.getAttributeId())) {
 
 282                     ((List<String>) initialRequest.getResource().get(RESOURCE_SCOPE))
 
 283                             .add(attribute.getAttributeValue().getValue().toString());