2  * ============LICENSE_START=======================================================
 
   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
 
  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.pdp.xacml.application.common.std;
 
  25 import com.att.research.xacml.api.Identifier;
 
  26 import com.att.research.xacml.api.Obligation;
 
  27 import com.att.research.xacml.api.Request;
 
  28 import com.att.research.xacml.api.XACML3;
 
  29 import com.att.research.xacml.std.IdentifierImpl;
 
  30 import com.att.research.xacml.util.XACMLPolicyWriter;
 
  31 import java.io.ByteArrayOutputStream;
 
  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.nio.file.Paths;
 
  37 import java.util.ArrayList;
 
  38 import java.util.Arrays;
 
  39 import java.util.Collection;
 
  40 import java.util.Collections;
 
  41 import java.util.HashMap;
 
  42 import java.util.LinkedHashMap;
 
  43 import java.util.LinkedList;
 
  44 import java.util.List;
 
  46 import java.util.Map.Entry;
 
  48 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
 
  49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
 
  50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
 
  51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
 
  52 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
 
  53 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
 
  54 import org.apache.commons.lang3.tuple.Pair;
 
  55 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
 
  56 import org.onap.policy.common.utils.coder.CoderException;
 
  57 import org.onap.policy.common.utils.coder.StandardCoder;
 
  58 import org.onap.policy.common.utils.coder.StandardYamlCoder;
 
  59 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 
  60 import org.onap.policy.models.decisions.concepts.DecisionResponse;
 
  61 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
 
  62 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
 
  63 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
 
  64 import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty;
 
  65 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
 
  66 import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
 
  67 import org.onap.policy.pdp.xacml.application.common.OnapObligation;
 
  68 import org.onap.policy.pdp.xacml.application.common.PolicyApiCaller;
 
  69 import org.onap.policy.pdp.xacml.application.common.PolicyApiException;
 
  70 import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
 
  71 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
 
  72 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
 
  73 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
 
  74 import org.slf4j.Logger;
 
  75 import org.slf4j.LoggerFactory;
 
  78  * This standard matchable translator uses Policy Types that contain "matchable" field in order
 
  79  * to translate policies.
 
  81  * @author pameladragosh
 
  84 public class StdMatchableTranslator  extends StdBaseTranslator {
 
  86     private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class);
 
  87     private static final StandardYamlCoder standardYamlCoder = new StandardYamlCoder();
 
  89     private final Map<ToscaPolicyTypeIdentifier, ToscaPolicyType> matchablePolicyTypes = new HashMap<>();
 
  91     private RestServerParameters apiRestParameters;
 
  93     private Path pathForData;
 
  95     public StdMatchableTranslator() {
 
 100     public Request convertRequest(DecisionRequest request) {
 
 101         LOGGER.info("Converting Request {}", request);
 
 103             return StdMatchablePolicyRequest.createInstance(request);
 
 104         } catch (XacmlApplicationException e) {
 
 105             LOGGER.error("Failed to convert DecisionRequest: {}", e);
 
 108         // TODO throw exception
 
 114      * scanObligations - scans the list of obligations and make appropriate method calls to process
 
 117      * @param obligations Collection of obligation objects
 
 118      * @param decisionResponse DecisionResponse object used to store any results from obligations.
 
 121     protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
 
 123         // Implementing a crude "closest match" on the results, which means we will strip out
 
 124         // any policies that has the lower weight than any of the others.
 
 126         // Most likely these are "default" policies with a weight of zero, but not always.
 
 128         // It is possible to have multiple policies with an equal weight, that is desired.
 
 130         // So we need to track each policy type separately and the weights for each policy.
 
 132         // policy-type -> weight -> List({policy-id, policy-content}, {policy-id, policy-content})
 
 134         Map<String, Map<Integer, List<Pair<String, Map<String, Object>>>>> closestMatches = new LinkedHashMap<>();
 
 136         // Now scan the list of obligations
 
 138         for (Obligation obligation : obligations) {
 
 139             Identifier obligationId = obligation.getId();
 
 140             LOGGER.info("Obligation: {}", obligationId);
 
 141             if (ToscaDictionary.ID_OBLIGATION_REST_BODY.equals(obligationId)) {
 
 142                 scanClosestMatchObligation(closestMatches, obligation);
 
 144                 LOGGER.warn("Unsupported Obligation Id {}", obligation.getId());
 
 148         // Now add all the policies to the DecisionResponse
 
 150         closestMatches.forEach((thePolicyType, weightMap) ->
 
 151             weightMap.forEach((weight, policies) ->
 
 152                 policies.forEach(policy -> {
 
 153                     LOGGER.info("Policy {}", policy);
 
 154                     decisionResponse.getPolicies().put(policy.getLeft(), policy.getRight());
 
 161      * scanClosestMatchObligation - scans for the obligation specifically holding policy
 
 162      * contents and their details.
 
 164      * @param closestMatches Map holding the current set of highest weight policy types
 
 165      * @param Obligation Obligation object
 
 167     protected void scanClosestMatchObligation(
 
 168             Map<String, Map<Integer, List<Pair<String, Map<String, Object>>>>> closestMatches, Obligation obligation) {
 
 170         // Create our OnapObligation object
 
 172         OnapObligation onapObligation = new OnapObligation(obligation);
 
 174         // All 4 *should* be there
 
 176         if (onapObligation.getPolicyId() == null || onapObligation.getPolicyContent() == null
 
 177                 || onapObligation.getPolicyType() == null || onapObligation.getWeight() == null) {
 
 178             LOGGER.error("Missing an expected attribute in obligation.");
 
 184         String policyId = onapObligation.getPolicyId();
 
 185         String policyType = onapObligation.getPolicyType();
 
 186         Map<String, Object> policyContent = onapObligation.getPolicyContentAsMap();
 
 187         int policyWeight = onapObligation.getWeight();
 
 189         // If the Policy Type exists, get the weight map.
 
 191         Map<Integer, List<Pair<String, Map<String, Object>>>> weightMap = closestMatches.get(policyType);
 
 192         if (weightMap != null) {
 
 194             // Only need to check first one - as we will ensure there is only one weight
 
 196             Entry<Integer, List<Pair<String, Map<String, Object>>>> firstEntry =
 
 197                     weightMap.entrySet().iterator().next();
 
 198             if (policyWeight < firstEntry.getKey()) {
 
 200                 // Existing policies have a greater weight, so we will not add it
 
 202                 LOGGER.info("{} is lesser weight {} than current policies, will not return it", policyWeight,
 
 203                         firstEntry.getKey());
 
 204             } else if (firstEntry.getKey().equals(policyWeight)) {
 
 206                 // Same weight - we will add it
 
 208                 LOGGER.info("Same weight {}, adding policy", policyWeight);
 
 209                 firstEntry.getValue().add(Pair.of(policyId, policyContent));
 
 212                 // The weight is greater, so we need to remove the other policies
 
 213                 // and point to this one.
 
 215                 LOGGER.info("New policy has greater weight {}, replacing {}", policyWeight, firstEntry.getKey());
 
 216                 List<Pair<String, Map<String, Object>>> listPolicies = new LinkedList<>();
 
 217                 listPolicies.add(Pair.of(policyId, policyContent));
 
 219                 weightMap.put(policyWeight, listPolicies);
 
 223             // Create a new entry
 
 225             LOGGER.info("New entry {} weight {}", policyType, policyWeight);
 
 226             List<Pair<String, Map<String, Object>>> listPolicies = new LinkedList<>();
 
 227             listPolicies.add(Pair.of(policyId, policyContent));
 
 228             Map<Integer, List<Pair<String, Map<String, Object>>>> newWeightMap = new LinkedHashMap<>();
 
 229             newWeightMap.put(policyWeight, listPolicies);
 
 230             closestMatches.put(policyType, newWeightMap);
 
 235     public PolicyType convertPolicy(ToscaPolicy toscaPolicy) throws ToscaPolicyConversionException {
 
 237         // Get the TOSCA Policy Type for this policy
 
 239         Collection<ToscaPolicyType> toscaPolicyTypes = this.getPolicyTypes(toscaPolicy.getTypeIdentifier());
 
 241         // If we don't have any TOSCA policy types, then we cannot know
 
 242         // which properties are matchable.
 
 244         if (toscaPolicyTypes.isEmpty()) {
 
 245             throw new ToscaPolicyConversionException(
 
 246                     "Cannot retrieve Policy Type definition for policy " + toscaPolicy.getName());
 
 249         // Policy name should be at the root
 
 251         String policyName = toscaPolicy.getMetadata().get(POLICY_ID);
 
 253         // Set it as the policy ID
 
 255         PolicyType newPolicyType = new PolicyType();
 
 256         newPolicyType.setPolicyId(policyName);
 
 258         // Optional description
 
 260         newPolicyType.setDescription(toscaPolicy.getDescription());
 
 262         // There should be a metadata section
 
 264         fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
 
 266         // Set the combining rule
 
 268         newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue());
 
 270         // Generate the TargetType - the policy should not be evaluated
 
 271         // unless all the matchable properties it cares about are matched.
 
 273         Pair<TargetType, Integer> pairGenerated = generateTargetType(toscaPolicy.getProperties(), toscaPolicyTypes);
 
 274         newPolicyType.setTarget(pairGenerated.getLeft());
 
 276         // Now represent the policy as Json
 
 278         StandardCoder coder = new StandardCoder();
 
 281             jsonPolicy = coder.encode(toscaPolicy);
 
 282         } catch (CoderException e) {
 
 283             throw new ToscaPolicyConversionException("Failed to encode policy to json", e);
 
 286         // Add it as an obligation
 
 288         addObligation(newPolicyType, policyName, jsonPolicy, pairGenerated.getRight(), toscaPolicy.getType());
 
 290         // Now create the Permit Rule.
 
 292         RuleType rule = new RuleType();
 
 293         rule.setDescription("Default is to PERMIT if the policy matches.");
 
 294         rule.setRuleId(policyName + ":rule");
 
 295         rule.setEffect(EffectType.PERMIT);
 
 296         rule.setTarget(new TargetType());
 
 298         // The rule contains the Condition which adds logic for
 
 299         // optional policy-type filtering.
 
 301         rule.setCondition(generateConditionForPolicyType(toscaPolicy.getType()));
 
 303         // Add the rule to the policy
 
 305         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
 
 307         // Log output of the policy
 
 309         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
 
 310             XACMLPolicyWriter.writePolicyFile(os, newPolicyType);
 
 311             LOGGER.info("{}", os);
 
 312         } catch (IOException e) {
 
 313             LOGGER.error("Failed to create byte array stream", e);
 
 318         return newPolicyType;
 
 322      * For generating target type, we scan for matchable properties
 
 323      * and use those to build the policy.
 
 325      * @param properties Properties section of policy
 
 326      * @param policyTypes Collection of policy Type to find matchable metadata
 
 327      * @return {@code Pair<TargetType, Integer>} Returns a TargetType and a Total Weight of matchables.
 
 329     protected Pair<TargetType, Integer> generateTargetType(Map<String, Object> properties,
 
 330             Collection<ToscaPolicyType> policyTypes) {
 
 331         TargetType targetType = new TargetType();
 
 333         // Iterate the properties
 
 335         int totalWeight = findMatchableFromMap(properties, policyTypes, targetType);
 
 336         LOGGER.info("Total weight is {}", totalWeight);
 
 337         return Pair.of(targetType, totalWeight);
 
 340     @SuppressWarnings("unchecked")
 
 341     protected int findMatchableFromList(List<Object> listProperties, Collection<ToscaPolicyType> policyTypes,
 
 342             TargetType targetType) {
 
 343         LOGGER.info("findMatchableFromList {}", listProperties);
 
 345         for (Object property : listProperties) {
 
 346             if (property instanceof List) {
 
 347                 totalWeight += findMatchableFromList((List<Object>) property, policyTypes, targetType);
 
 348             } else if (property instanceof Map) {
 
 349                 totalWeight += findMatchableFromMap((Map<String, Object>) property, policyTypes, targetType);
 
 355     protected int findMatchableFromMap(Map<String, Object> properties, Collection<ToscaPolicyType> policyTypes,
 
 356             TargetType targetType) {
 
 357         LOGGER.info("findMatchableFromMap {}", properties);
 
 359         for (Entry<String, Object> entrySet : properties.entrySet()) {
 
 361             // Is this a matchable property?
 
 363             if (isMatchable(entrySet.getKey(), policyTypes)) {
 
 364                 LOGGER.info("Found matchable property {}", entrySet.getKey());
 
 365                 int weight = generateMatchable(targetType, entrySet.getKey(), entrySet.getValue());
 
 366                 LOGGER.info("Weight is {}", weight);
 
 367                 totalWeight += weight;
 
 370                 // Check if we need to search deeper
 
 372                 totalWeight += checkDeeperForMatchable(entrySet.getValue(), policyTypes, targetType);
 
 378     @SuppressWarnings("unchecked")
 
 379     protected int checkDeeperForMatchable(Object property, Collection<ToscaPolicyType> policyTypes,
 
 380             TargetType targetType) {
 
 381         if (property instanceof List) {
 
 382             return findMatchableFromList((List<Object>) property, policyTypes, targetType);
 
 383         } else if (property instanceof Map) {
 
 384             return findMatchableFromMap((Map<String, Object>) property, policyTypes,
 
 387         LOGGER.info("checkDeeperForMatchable not necessary for {}", property);
 
 392      * isMatchable - Iterates through available TOSCA Policy Types to determine if a property
 
 393      * should be treated as matchable.
 
 395      * @param propertyName Name of property
 
 396      * @param policyTypes Collection of TOSCA Policy Types to scan
 
 397      * @return true if matchable
 
 399     protected boolean isMatchable(String propertyName, Collection<ToscaPolicyType> policyTypes) {
 
 400         for (ToscaPolicyType policyType : policyTypes) {
 
 401             for (Entry<String, ToscaProperty> propertiesEntry : policyType.getProperties().entrySet()) {
 
 402                 if (checkIsMatchableProperty(propertyName, propertiesEntry)) {
 
 406                 // Check if its a list or map
 
 408                 if (isListOrMap(propertiesEntry.getValue().getType())
 
 409                         && ! isYamlType(propertiesEntry.getValue().getEntrySchema().getType())) {
 
 410                     LOGGER.info("need to search list or map");
 
 414         LOGGER.info("isMatchable false for {}", propertyName);
 
 418     private boolean isListOrMap(String type) {
 
 419         return "list".equalsIgnoreCase(type) || "map".equalsIgnoreCase(type);
 
 422     private boolean isYamlType(String type) {
 
 423         return "string".equalsIgnoreCase(type) || "integer".equalsIgnoreCase(type) || "float".equalsIgnoreCase(type)
 
 424                 || "boolean".equalsIgnoreCase(type) || "timestamp".equalsIgnoreCase(type);
 
 428      * checkIsMatchableProperty - checks the policy contents for matchable field. If the metadata doesn't exist,
 
 429      * then definitely not. If the property doesn't exist, then definitely not. Otherwise need to have a metadata
 
 430      * section with the matchable property set to true.
 
 432      * @param propertyName String value of property
 
 433      * @param propertiesEntry Section of the TOSCA Policy Type where properties and metadata sections are held
 
 434      * @return true if matchable
 
 436     protected boolean checkIsMatchableProperty(String propertyName, Entry<String, ToscaProperty> propertiesEntry) {
 
 437         if (! propertiesEntry.getKey().equals(propertyName)
 
 438                 || propertiesEntry.getValue().getMetadata() == null) {
 
 441         for (Entry<String, String> entrySet : propertiesEntry.getValue().getMetadata().entrySet()) {
 
 442             if ("matchable".equals(entrySet.getKey()) && "true".equals(entrySet.getValue())) {
 
 450      * generateMatchable - Given the object, generates list of MatchType objects and add them
 
 451      * to the TargetType object. Returns a weight which is the number of AnyOf's generated. The
 
 452      * weight can be used to further filter the results for "closest match".
 
 454      * @param targetType TargetType object to add matches to
 
 455      * @param key Property key
 
 456      * @param value Object is the value - which can be a Collection or single Object
 
 457      * @return int Weight of the match.
 
 459     @SuppressWarnings("unchecked")
 
 460     protected int generateMatchable(TargetType targetType, String key, Object value) {
 
 462         if (value instanceof Collection) {
 
 463             AnyOfType anyOf = generateMatches((Collection<Object>) value,
 
 464                     new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key));
 
 465             if (! anyOf.getAllOf().isEmpty()) {
 
 466                 targetType.getAnyOf().add(anyOf);
 
 470             AnyOfType anyOf = generateMatches(Arrays.asList(value),
 
 471                     new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key));
 
 472             if (! anyOf.getAllOf().isEmpty()) {
 
 473                 targetType.getAnyOf().add(anyOf);
 
 481      * generateMatches - Goes through the collection of objects, creates a MatchType object
 
 482      * for each object and associates it with the given attribute Id. Returns the AnyOfType
 
 483      * object that contains all the generated MatchType objects.
 
 485      * @param matchables Collection of object to generate MatchType from
 
 486      * @param attributeId Given attribute Id for each MatchType
 
 487      * @return AnyOfType object
 
 489     protected AnyOfType generateMatches(Collection<Object> matchables, Identifier attributeId) {
 
 491         // This is our outer AnyOf - which is an OR
 
 493         AnyOfType anyOf = new AnyOfType();
 
 494         for (Object matchable : matchables) {
 
 498             Identifier idFunction = XACML3.ID_FUNCTION_STRING_EQUAL;
 
 499             Identifier idDatatype = XACML3.ID_DATATYPE_STRING;
 
 501             // See if we are another datatype
 
 503             // We should add datetime support. But to do that we need
 
 504             // probably more metadata to describe how that would be translated.
 
 506             if (matchable instanceof Integer) {
 
 507                 idFunction = XACML3.ID_FUNCTION_INTEGER_EQUAL;
 
 508                 idDatatype = XACML3.ID_DATATYPE_INTEGER;
 
 509             } else if (matchable instanceof Double) {
 
 510                 idFunction = XACML3.ID_FUNCTION_DOUBLE_EQUAL;
 
 511                 idDatatype = XACML3.ID_DATATYPE_DOUBLE;
 
 512             } else if (matchable instanceof Boolean) {
 
 513                 idFunction = XACML3.ID_FUNCTION_BOOLEAN_EQUAL;
 
 514                 idDatatype = XACML3.ID_DATATYPE_BOOLEAN;
 
 517             // Create a match for this
 
 519             MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
 
 521                     matchable.toString(),
 
 524                     XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
 
 526             // Now create an anyOf (OR)
 
 528             anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
 
 534      * Get Policy Type definitions. This could be previously loaded, or could be
 
 535      * stored in application path, or may need to be pulled from the API.
 
 538      * @param policyTypeId Policy Type Id
 
 539      * @return A list of PolicyTypes
 
 541     private List<ToscaPolicyType> getPolicyTypes(ToscaPolicyTypeIdentifier policyTypeId) {
 
 543         // Create identifier from the policy
 
 545         ToscaPolicyTypeIdentifier typeId = new ToscaPolicyTypeIdentifier(policyTypeId);
 
 547         // Find the Policy Type
 
 549         ToscaPolicyType policyType = findPolicyType(typeId);
 
 550         if (policyType == null)  {
 
 551             return Collections.emptyList();
 
 554         // Create our return object
 
 556         List<ToscaPolicyType> listTypes = new ArrayList<>();
 
 557         listTypes.add(policyType);
 
 559         // Look for parent policy types that could also contain matchable properties
 
 561         ToscaPolicyType childPolicyType = policyType;
 
 562         while (! childPolicyType.getDerivedFrom().startsWith("tosca.policies.Root")) {
 
 564             // Create parent policy type id.
 
 566             // We will have to assume the same version between child and the
 
 567             // parent policy type it derives from.
 
 569             // Or do we assume 1.0.0?
 
 571             ToscaPolicyTypeIdentifier parentId = new ToscaPolicyTypeIdentifier(childPolicyType.getDerivedFrom(),
 
 574             // Find the policy type
 
 576             ToscaPolicyType parentPolicyType = findPolicyType(parentId);
 
 577             if (parentPolicyType == null) {
 
 579                 // Probably would be best to throw an exception and
 
 580                 // return nothing back.
 
 582                 // But instead we will log a warning
 
 584                 LOGGER.warn("Missing parent policy type - proceeding anyway {}", parentId);
 
 593             listTypes.add(parentPolicyType);
 
 595             // Move to the next parent
 
 597             childPolicyType = parentPolicyType;
 
 603      * findPolicyType - given the ToscaPolicyTypeIdentifier, finds it in memory, or
 
 604      * then tries to find it either locally on disk or pull it from the Policy
 
 605      * Lifecycle API the given TOSCA Policy Type.
 
 607      * @param policyTypeId ToscaPolicyTypeIdentifier to find
 
 608      * @return ToscaPolicyType object. Can be null if failure.
 
 610     private ToscaPolicyType findPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
 
 612         // Is it loaded in memory?
 
 614         ToscaPolicyType policyType = this.matchablePolicyTypes.get(policyTypeId);
 
 615         if (policyType == null)  {
 
 619             policyType = this.loadPolicyType(policyTypeId);
 
 628      * loadPolicyType - Tries to load the given ToscaPolicyTypeIdentifier from local
 
 629      * storage. If it does not exist, will then attempt to pull from Policy Lifecycle
 
 632      * @param policyTypeId ToscaPolicyTypeIdentifier input
 
 633      * @return ToscaPolicyType object. Null if failure.
 
 635     private ToscaPolicyType loadPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
 
 637         // Construct what the file name should be
 
 639         Path policyTypePath = this.constructLocalFilePath(policyTypeId);
 
 646             // If it exists locally, read the bytes in
 
 648             bytes = Files.readAllBytes(policyTypePath);
 
 649         } catch (IOException e) {
 
 651             // Does not exist locally, so let's GET it from the policy api
 
 653             LOGGER.error("PolicyType not found in data area yet {}", policyTypePath, e);
 
 655             // So let's pull it from API REST call and save it locally
 
 657             return this.pullPolicyType(policyTypeId, policyTypePath);
 
 660         // Success - we have read locally the policy type. Now bring it into our
 
 663         LOGGER.info("Read in local policy type {}", policyTypePath.toAbsolutePath());
 
 665             ToscaServiceTemplate serviceTemplate = standardYamlCoder.decode(new String(bytes, StandardCharsets.UTF_8),
 
 666                     ToscaServiceTemplate.class);
 
 667             JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
 
 668             jtst.fromAuthorative(serviceTemplate);
 
 669             ToscaServiceTemplate completedJtst = jtst.toAuthorative();
 
 671             // Search for our Policy Type, there really only should be one but
 
 672             // this is returned as a map.
 
 674             for ( Entry<String, ToscaPolicyType> entrySet : completedJtst.getPolicyTypes().entrySet()) {
 
 675                 ToscaPolicyType entryPolicyType = entrySet.getValue();
 
 676                 if (policyTypeId.getName().equals(entryPolicyType.getName())
 
 677                         && policyTypeId.getVersion().equals(entryPolicyType.getVersion())) {
 
 678                     LOGGER.info("Found existing local policy type {} {}", entryPolicyType.getName(),
 
 679                             entryPolicyType.getVersion());
 
 681                     // Just simply return the policy type right here
 
 683                     return entryPolicyType;
 
 685                     LOGGER.warn("local policy type contains different name version {} {}", entryPolicyType.getName(),
 
 686                             entryPolicyType.getVersion());
 
 690             // This would be an error, if the file stored does not match what its supposed to be
 
 692             LOGGER.error("Existing policy type file does not contain right name and version");
 
 693         } catch (CoderException e) {
 
 694             LOGGER.error("Failed to decode tosca template for {}", policyTypePath, e);
 
 697         // Hopefully we never get here
 
 699         LOGGER.error("Failed to find/load policy type {}", policyTypeId);
 
 704      * pullPolicyType - pulls the given ToscaPolicyTypeIdentifier from the Policy Lifecycle API.
 
 705      * If successful, will store it locally given the policyTypePath.
 
 707      * @param policyTypeId ToscaPolicyTypeIdentifier
 
 708      * @param policyTypePath Path object to store locally
 
 709      * @return ToscaPolicyType object. Null if failure.
 
 711     private synchronized ToscaPolicyType pullPolicyType(ToscaPolicyTypeIdentifier policyTypeId, Path policyTypePath) {
 
 713         // This is what we return
 
 715         ToscaPolicyType policyType = null;
 
 717             PolicyApiCaller api = new PolicyApiCaller(this.apiRestParameters);
 
 719             policyType = api.getPolicyType(policyTypeId);
 
 720         } catch (PolicyApiException e) {
 
 721             LOGGER.error("Failed to make API call", e);
 
 722             LOGGER.error("parameters: {} ", this.apiRestParameters);
 
 725         LOGGER.info("Successfully pulled {}", policyTypeId);
 
 730             standardYamlCoder.encode(policyTypePath.toFile(), policyType);
 
 731         } catch (CoderException e) {
 
 732             LOGGER.error("Failed to store {} locally to {}", policyTypeId, policyTypePath, e);
 
 735         // Done return the policy type
 
 741      * constructLocalFilePath - common method to ensure the name of the local file for the
 
 742      * policy type is the same.
 
 744      * @param policyTypeId ToscaPolicyTypeIdentifier
 
 745      * @return Path object
 
 747     private Path constructLocalFilePath(ToscaPolicyTypeIdentifier policyTypeId) {
 
 748         return Paths.get(this.pathForData.toAbsolutePath().toString(), policyTypeId.getName() + "-"
 
 749                 + policyTypeId.getVersion() + ".yaml");