5539617b0f0e6976ced07648c9b5bb1c104a5946
[policy/gui.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.onap.policy.gui.editors.apex.rest.handling.converter.tosca;
21
22 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.PolicyToscaConverter.ToscaKey.POLICIES;
23 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.PolicyToscaConverter.ToscaKey.PROPERTIES;
24 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.PolicyToscaConverter.ToscaKey.TOPOLOGY_TEMPLATE;
25 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.PolicyToscaConverter.ToscaKey.TOSCA_DEFINITIONS_VERSION;
26 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.INVALID_ENTRY;
27 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.INVALID_POLICY;
28 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.INVALID_TOSCA_TEMPLATE;
29 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.MISSING_ENTRY;
30 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.MISSING_POLICY;
31 import static org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.ToscaTemplateProcessor.ErrorMessage.ONLY_ONE_POLICY_ALLOWED;
32
33 import com.google.gson.JsonArray;
34 import com.google.gson.JsonObject;
35 import com.google.gson.JsonPrimitive;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.nio.charset.StandardCharsets;
39 import java.util.HashSet;
40 import java.util.Optional;
41 import java.util.Set;
42 import java.util.function.Function;
43 import lombok.AllArgsConstructor;
44 import org.apache.commons.io.IOUtils;
45 import org.onap.policy.common.utils.coder.CoderException;
46 import org.onap.policy.common.utils.coder.StandardCoder;
47 import org.onap.policy.gui.editors.apex.rest.handling.converter.tosca.PolicyToscaConverter.ToscaKey;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 /**
52  * Process the TOSCA JSON template file, base for the Policy Model TOSCA conversion.
53  */
54 public class ToscaTemplateProcessor {
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(ToscaTemplateProcessor.class);
57
58     private final StandardCoder jsonCoder;
59
60     public ToscaTemplateProcessor(final StandardCoder jsonCoder) {
61         this.jsonCoder = jsonCoder;
62     }
63
64     /**
65      * Process the TOSCA JSON template file.
66      *
67      * @param toscaTemplateInputStream the input stream for the TOSCA JSON template file
68      * @return the result of the processing with the read JSON and its errors.
69      */
70     public ProcessedTemplate process(final InputStream toscaTemplateInputStream) throws IOException {
71         final ProcessedTemplate processedTemplate = new ProcessedTemplate();
72
73         final String templateAsString;
74         try (final InputStream inputStream = toscaTemplateInputStream) {
75             templateAsString = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
76         }
77
78         final Set<String> errorSet = validate(templateAsString);
79         processedTemplate.setContent(templateAsString);
80         processedTemplate.addToErrors(errorSet);
81
82         return processedTemplate;
83     }
84
85     private Set<String> validate(final String toscaTemplate) {
86         final Set<String> errorSet = new HashSet<>();
87         final JsonObject toscaTemplateJson;
88         try {
89             toscaTemplateJson = jsonCoder.decode(toscaTemplate, JsonObject.class);
90         } catch (final CoderException e) {
91             LOGGER.debug(INVALID_TOSCA_TEMPLATE.getMessage(), e);
92             errorSet.add(INVALID_TOSCA_TEMPLATE.getMessage());
93             return errorSet;
94         }
95
96         final Optional<JsonPrimitive> toscaDefinitionVersionOpt =
97             readJsonEntry(TOSCA_DEFINITIONS_VERSION, toscaTemplateJson::getAsJsonPrimitive, errorSet);
98         if (toscaDefinitionVersionOpt.isEmpty()) {
99             return errorSet;
100         }
101
102         final Optional<JsonObject> topologyTemplate =
103             readJsonEntry(TOPOLOGY_TEMPLATE, toscaTemplateJson::getAsJsonObject, errorSet);
104         if (topologyTemplate.isEmpty()) {
105             return errorSet;
106         }
107
108         final Optional<JsonArray> policiesOpt =
109             readJsonEntry(POLICIES, topologyTemplate.get()::getAsJsonArray, errorSet);
110         if (policiesOpt.isEmpty()) {
111             return errorSet;
112         }
113         final JsonArray policies = policiesOpt.get();
114
115         if (policies.size() == 0) {
116             errorSet.add(MISSING_POLICY.getMessage());
117             return errorSet;
118         }
119
120         if (policies.size() > 1) {
121             errorSet.add(ONLY_ONE_POLICY_ALLOWED.getMessage());
122             return errorSet;
123         }
124
125         final JsonObject firstPolicy;
126         try {
127             final JsonObject firstPolicyObj = policies.get(0).getAsJsonObject();
128             firstPolicy = firstPolicyObj.entrySet().iterator().next().getValue().getAsJsonObject();
129         } catch (final Exception e) {
130             final String errorMsg = INVALID_POLICY.getMessage();
131             LOGGER.debug(errorMsg, e);
132             errorSet.add(errorMsg);
133             return errorSet;
134         }
135
136         readJsonEntry(PROPERTIES, firstPolicy::getAsJsonObject, errorSet);
137
138         return errorSet;
139     }
140
141     private <T> Optional<T> readJsonEntry(final ToscaKey toscaKey,
142                                           final Function<String, T> jsonFunction, final Set<String> errorSet) {
143         try {
144             final T json = jsonFunction.apply(toscaKey.getKey());
145             if (json == null) {
146                 errorSet.add(MISSING_ENTRY.getMessage(toscaKey.getKey()));
147             }
148             return Optional.ofNullable(json);
149         } catch (final Exception e) {
150             final String errorMsg = INVALID_ENTRY.getMessage(toscaKey.getKey());
151             LOGGER.debug(errorMsg, e);
152             errorSet.add(errorMsg);
153             return Optional.empty();
154         }
155
156     }
157
158     /**
159      * Stores the possible error messages for the Tosca template validation process.
160      */
161     @AllArgsConstructor
162     public enum ErrorMessage {
163         MISSING_ENTRY("Missing '%s' entry"),
164         MISSING_POLICY("No policy was provided in the 'policies' list"),
165         INVALID_POLICY("Invalid policy was provided in the 'policies' list"),
166         ONLY_ONE_POLICY_ALLOWED("Only one policy entry is allowed in the 'policies' list"),
167         INVALID_TOSCA_TEMPLATE("Invalid tosca template provided"),
168         INVALID_ENTRY("Invalid entry '%s' provided"),
169         MISSING_PROPERTIES_ENTRY("Missing properties entry in '%s'");
170
171         private final String messageFormat;
172
173         public String getMessage(final String... params) {
174             return String.format(this.messageFormat, params);
175         }
176     }
177
178
179 }