ddb8ddb830a3cd44062283dbae08fa043d75dbea
[sdc/sdc-tosca.git] / jtosca / src / main / java / org / onap / sdc / toscaparser / api / ToscaTemplate.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (c) 2017 AT&T Intellectual Property.
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  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END=========================================================
17  * Modifications copyright (c) 2019 Fujitsu Limited.
18  * ================================================================================
19  */
20 package org.onap.sdc.toscaparser.api;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.nio.file.Files;
28 import java.nio.file.Paths;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.function.Predicate;
39
40 import org.onap.sdc.toscaparser.api.common.JToscaException;
41 import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue;
42 import org.onap.sdc.toscaparser.api.common.ValidationIssueCollector;
43 import org.onap.sdc.toscaparser.api.elements.EntityType;
44 import org.onap.sdc.toscaparser.api.elements.DataType;
45 import org.onap.sdc.toscaparser.api.elements.Metadata;
46 import org.onap.sdc.toscaparser.api.extensions.ExtTools;
47 import org.onap.sdc.toscaparser.api.parameters.Input;
48 import org.onap.sdc.toscaparser.api.parameters.Output;
49 import org.onap.sdc.toscaparser.api.prereq.CSAR;
50 import org.onap.sdc.toscaparser.api.utils.JToscaErrorCodes;
51 import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54 import org.yaml.snakeyaml.Yaml;
55
56 public class ToscaTemplate extends Object {
57
58     public static final int MAX_LEVELS = 20;
59     private static Logger log = LoggerFactory.getLogger(ToscaTemplate.class.getName());
60
61     // TOSCA template key names
62     private static final String DEFINITION_VERSION = "tosca_definitions_version";
63     private static final String DEFAULT_NAMESPACE = "tosca_default_namespace";
64     private static final String TEMPLATE_NAME = "template_name";
65     private static final String TOPOLOGY_TEMPLATE = "topology_template";
66     private static final String TEMPLATE_AUTHOR = "template_author";
67     private static final String TEMPLATE_VERSION = "template_version";
68     private static final String DESCRIPTION = "description";
69     private static final String IMPORTS = "imports";
70     private static final String DSL_DEFINITIONS = "dsl_definitions";
71     private static final String NODE_TYPES = "node_types";
72     private static final String RELATIONSHIP_TYPES = "relationship_types";
73     private static final String RELATIONSHIP_TEMPLATES = "relationship_templates";
74     private static final String CAPABILITY_TYPES = "capability_types";
75     private static final String ARTIFACT_TYPES = "artifact_types";
76     private static final String DATA_TYPES = "data_types";
77     private static final String INTERFACE_TYPES = "interface_types";
78     private static final String POLICY_TYPES = "policy_types";
79     private static final String GROUP_TYPES = "group_types";
80     private static final String REPOSITORIES = "repositories";
81
82     private static String SECTIONS[] = {
83             DEFINITION_VERSION, DEFAULT_NAMESPACE, TEMPLATE_NAME,
84             TOPOLOGY_TEMPLATE, TEMPLATE_AUTHOR, TEMPLATE_VERSION,
85             DESCRIPTION, IMPORTS, DSL_DEFINITIONS, NODE_TYPES,
86             RELATIONSHIP_TYPES, RELATIONSHIP_TEMPLATES,
87             CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES,
88             INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES, REPOSITORIES
89     };
90
91     // Sections that are specific to individual template definitions
92     private static final String METADATA = "metadata";
93     private static ArrayList<String> SPECIAL_SECTIONS;
94
95     private ExtTools exttools = new ExtTools();
96
97     private ArrayList<String> VALID_TEMPLATE_VERSIONS;
98     private LinkedHashMap<String, ArrayList<String>> ADDITIONAL_SECTIONS;
99
100     private boolean isFile;
101     private String path;
102     private String inputPath;
103     private String rootPath;
104     private LinkedHashMap<String, Object> parsedParams;
105     private boolean resolveGetInput;
106     private LinkedHashMap<String, Object> tpl;
107     private String version;
108     private ArrayList<Object> imports;
109     private LinkedHashMap<String, Object> relationshipTypes;
110     private Metadata metaData;
111     private String description;
112     private TopologyTemplate topologyTemplate;
113     private ArrayList<Repository> repositories;
114     private ArrayList<Input> inputs;
115     private ArrayList<RelationshipTemplate> relationshipTemplates;
116     private ArrayList<NodeTemplate> nodeTemplates;
117     private ArrayList<Output> outputs;
118     private ArrayList<Policy> policies;
119     private ArrayList<Group> groups;
120     private ConcurrentHashMap<String, Object> nestedToscaTplsWithTopology;
121     private ArrayList<TopologyTemplate> nestedToscaTemplatesWithTopology;
122     private ToscaGraph graph;
123     private String csarTempDir;
124     private int nestingLoopCounter;
125     private LinkedHashMap<String, LinkedHashMap<String, Object>> metaProperties;
126     private Set<String> processedImports;
127     private LinkedHashMap<String, Object> customDefsFinal = new LinkedHashMap<>();
128     private HashSet<DataType> dataTypes;
129
130     public ToscaTemplate(String _path,
131                          LinkedHashMap<String, Object> _parsedParams,
132                          boolean aFile,
133                          LinkedHashMap<String, Object> yamlDictTpl) throws JToscaException {
134         init(_path, _parsedParams, aFile, yamlDictTpl, true);
135     }
136
137     public ToscaTemplate(String _path,
138                          LinkedHashMap<String, Object> _parsedParams,
139                          boolean aFile,
140                          LinkedHashMap<String, Object> yamlDictTpl, boolean resolveGetInput) throws JToscaException {
141         init(_path, _parsedParams, aFile, yamlDictTpl, resolveGetInput);
142     }
143
144     @SuppressWarnings("unchecked")
145     private void init(String _path,
146                       LinkedHashMap<String, Object> _parsedParams,
147                       boolean aFile,
148                       LinkedHashMap<String, Object> yamlDictTpl, boolean _resolveGetInput) throws JToscaException {
149
150         ThreadLocalsHolder.setCollector(new ValidationIssueCollector());
151
152         VALID_TEMPLATE_VERSIONS = new ArrayList<>();
153         VALID_TEMPLATE_VERSIONS.add("tosca_simple_yaml_1_0");
154         VALID_TEMPLATE_VERSIONS.add("tosca_simple_yaml_1_1");
155         VALID_TEMPLATE_VERSIONS.addAll(exttools.getVersions());
156         ADDITIONAL_SECTIONS = new LinkedHashMap<>();
157         SPECIAL_SECTIONS = new ArrayList<>();
158         SPECIAL_SECTIONS.add(METADATA);
159         ADDITIONAL_SECTIONS.put("tosca_simple_yaml_1_0", SPECIAL_SECTIONS);
160         ADDITIONAL_SECTIONS.put("tosca_simple_yaml_1_1", SPECIAL_SECTIONS);
161         ADDITIONAL_SECTIONS.putAll(exttools.getSections());
162
163         //long startTime = System.nanoTime();
164
165
166         isFile = aFile;
167         inputPath = null;
168         path = null;
169         tpl = null;
170         csarTempDir = null;
171         nestedToscaTplsWithTopology = new ConcurrentHashMap<>();
172         nestedToscaTemplatesWithTopology = new ArrayList<TopologyTemplate>();
173         resolveGetInput = _resolveGetInput;
174         metaProperties = new LinkedHashMap<>();
175
176         if (_path != null && !_path.isEmpty()) {
177             // save the original input path
178             inputPath = _path;
179             // get the actual path (will change with CSAR)
180             path = _getPath(_path);
181             // load the YAML template
182             if (path != null && !path.isEmpty()) {
183                 try (InputStream input = new FileInputStream(new File(path));) {
184                     //System.out.println("Loading YAML file " + path);
185                     log.debug("ToscaTemplate Loading YAMEL file {}", path);
186                     Yaml yaml = new Yaml();
187                     Object data = yaml.load(input);
188                     this.tpl = (LinkedHashMap<String, Object>) data;
189                 } catch (FileNotFoundException e) {
190                     log.error("ToscaTemplate - Exception loading yaml: {}", e.getMessage());
191                     log.error("Exception", e);
192                     ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE275",
193                             "ToscaTemplate - Exception loading yaml: -> " + e.getMessage()));
194                     return;
195                 } catch (Exception e) {
196                     log.error("ToscaTemplate - Error loading yaml, aborting -> ", e.getMessage());
197                     log.error("Exception", e);
198                     ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE275",
199                             "ToscaTemplate - Error loading yaml, aborting -> " + e.getMessage()));
200                     return;
201                 }
202
203                 if (yamlDictTpl != null) {
204                     //msg = (_('Both path and yaml_dict_tpl arguments were '
205                     //         'provided. Using path and ignoring yaml_dict_tpl.'))
206                     //log.info(msg)
207                     log.debug("ToscaTemplate - Both path and yaml_dict_tpl arguments were provided. Using path and ignoring yaml_dict_tpl");
208                 }
209             } else {
210                 // no input to process...
211                 _abort();
212             }
213         } else {
214             if (yamlDictTpl != null) {
215                 tpl = yamlDictTpl;
216             } else {
217                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE244",
218                         "ValueError: No path or yaml_dict_tpl was provided. There is nothing to parse"));
219                 log.debug("ToscaTemplate ValueError: No path or yaml_dict_tpl was provided. There is nothing to parse");
220
221             }
222         }
223
224         if (tpl != null) {
225             parsedParams = _parsedParams;
226             _validateField();
227             this.rootPath = path;
228             this.processedImports = new HashSet<String>();
229             this.imports = _tplImports();
230             this.version = _tplVersion();
231             this.metaData = _tplMetaData();
232             this.relationshipTypes = _tplRelationshipTypes();
233             this.description = _tplDescription();
234             this.dataTypes = getTopologyDataTypes();
235             this.topologyTemplate = _topologyTemplate();
236             this.repositories = _tplRepositories();
237             if (topologyTemplate.getTpl() != null) {
238                 this.inputs = _inputs();
239                 this.relationshipTemplates = _relationshipTemplates();
240                 this.nodeTemplates = _nodeTemplates();
241                 this.outputs = _outputs();
242                 this.policies = _policies();
243                 this.groups = _groups();
244 //                _handleNestedToscaTemplatesWithTopology();
245                 _handleNestedToscaTemplatesWithTopology(topologyTemplate);
246                 graph = new ToscaGraph(nodeTemplates);
247             }
248         }
249
250         if (csarTempDir != null) {
251             CSAR.deleteDir(new File(csarTempDir));
252             csarTempDir = null;
253         }
254
255         verifyTemplate();
256
257     }
258
259     private void _abort() throws JToscaException {
260         // print out all exceptions caught
261         verifyTemplate();
262         throw new JToscaException("jtosca aborting", JToscaErrorCodes.PATH_NOT_VALID.getValue());
263     }
264
265     private TopologyTemplate _topologyTemplate() {
266         return new TopologyTemplate(
267                 _tplTopologyTemplate(),
268                 _getAllCustomDefs(imports),
269                 relationshipTypes,
270                 parsedParams,
271                 null,
272                 resolveGetInput);
273     }
274
275     private ArrayList<Input> _inputs() {
276         return topologyTemplate.getInputs();
277     }
278
279     private ArrayList<NodeTemplate> _nodeTemplates() {
280         return topologyTemplate.getNodeTemplates();
281     }
282
283     private ArrayList<RelationshipTemplate> _relationshipTemplates() {
284         return topologyTemplate.getRelationshipTemplates();
285     }
286
287     private ArrayList<Output> _outputs() {
288         return topologyTemplate.getOutputs();
289     }
290
291     private String _tplVersion() {
292         return (String) tpl.get(DEFINITION_VERSION);
293     }
294
295     @SuppressWarnings("unchecked")
296     private Metadata _tplMetaData() {
297         Object mdo = tpl.get(METADATA);
298         if (mdo instanceof LinkedHashMap) {
299             return new Metadata((Map<String, Object>) mdo);
300         } else {
301             return null;
302         }
303     }
304
305     private String _tplDescription() {
306         return (String) tpl.get(DESCRIPTION);
307     }
308
309     @SuppressWarnings("unchecked")
310     private ArrayList<Object> _tplImports() {
311         return (ArrayList<Object>) tpl.get(IMPORTS);
312     }
313
314     @SuppressWarnings("unchecked")
315     private ArrayList<Repository> _tplRepositories() {
316         LinkedHashMap<String, Object> repositories =
317                 (LinkedHashMap<String, Object>) tpl.get(REPOSITORIES);
318         ArrayList<Repository> reposit = new ArrayList<>();
319         if (repositories != null) {
320             for (Map.Entry<String, Object> me : repositories.entrySet()) {
321                 Repository reposits = new Repository(me.getKey(), me.getValue());
322                 reposit.add(reposits);
323             }
324         }
325         return reposit;
326     }
327
328     private LinkedHashMap<String, Object> _tplRelationshipTypes() {
329         return (LinkedHashMap<String, Object>) _getCustomTypes(RELATIONSHIP_TYPES, null);
330     }
331
332     @SuppressWarnings("unchecked")
333     private LinkedHashMap<String, Object> _tplTopologyTemplate() {
334         return (LinkedHashMap<String, Object>) tpl.get(TOPOLOGY_TEMPLATE);
335     }
336
337     private ArrayList<Policy> _policies() {
338         return topologyTemplate.getPolicies();
339     }
340
341     private ArrayList<Group> _groups() {
342         return topologyTemplate.getGroups();
343     }
344
345     /**
346      * Read datatypes field
347      *
348      * @return return list of datatypes.
349      */
350     @SuppressWarnings("unchecked")
351     private HashSet<DataType> getTopologyDataTypes() {
352         LinkedHashMap<String, Object> value =
353                 (LinkedHashMap<String, Object>) tpl.get(DATA_TYPES);
354         HashSet<DataType> datatypes = new HashSet<>();
355         if (value != null) {
356             customDefsFinal.putAll(value);
357             for (Map.Entry<String, Object> me : value.entrySet()) {
358                 DataType datatype = new DataType(me.getKey(), value);
359                 datatypes.add(datatype);
360             }
361         }
362
363
364         return datatypes;
365     }
366
367     /**
368      * This method is used to get consolidated custom definitions from all imports
369      * It is logically divided in two parts to handle imports; map and list formats.
370      * Before processing the imports; it sorts them to make sure the current directory imports are
371      * being processed first and then others. Once sorted; it processes each import one by one in
372      * recursive manner.
373      * To avoid cyclic dependency among imports; this method uses a set to keep track of all
374      * imports which are already processed and filters the imports which occurs more than once.
375      *
376      * @param alImports all imports which needs to be processed
377      * @return the linked hash map containing all import definitions
378      */
379
380     @SuppressWarnings("unchecked")
381     private LinkedHashMap<String, Object> _getAllCustomDefs(Object alImports) {
382
383
384         String types[] = {
385                 IMPORTS, NODE_TYPES, CAPABILITY_TYPES, RELATIONSHIP_TYPES,
386                 DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES
387         };
388
389         List<Map<String, Object>> imports = (List<Map<String, Object>>) alImports;
390         if (imports != null && !imports.isEmpty()) {
391             if (imports.get(0) instanceof LinkedHashMap) {
392                 imports = sortImports(imports);
393
394                 for (Map<String, Object> map : imports) {
395                     List<Map<String, Object>> singleImportList = new ArrayList<>();
396                     singleImportList.add(map);
397
398                     Map<String, String> importNameDetails = getValidFileNameForImportReference(singleImportList);
399                     singleImportList = filterImportsForRecursion(singleImportList, importNameDetails);
400
401                     if (!singleImportList.get(0).isEmpty()) {
402                         LinkedHashMap<String, Object> customDefs = _getCustomTypes(types, new ArrayList<>(singleImportList));
403                         processedImports.add(importNameDetails.get("importFileName"));
404
405                         if (customDefs != null) {
406                             customDefsFinal.putAll(customDefs);
407
408                             if (customDefs.get(IMPORTS) != null) {
409                                 resetPathForRecursiveImports(importNameDetails.get("importRelativeName"));
410                                 LinkedHashMap<String, Object> importDefs = _getAllCustomDefs(customDefs.get(IMPORTS));
411                                 customDefsFinal.putAll(importDefs);
412                             }
413                         }
414                     }
415                 }
416             } else {
417                 LinkedHashMap<String, Object> customDefs = _getCustomTypes(types, new ArrayList<>(imports));
418                 if (customDefs != null) {
419                     customDefsFinal.putAll(customDefs);
420
421                     if (customDefs.get(IMPORTS) != null) {
422                         LinkedHashMap<String, Object> importDefs = _getAllCustomDefs(customDefs.get(IMPORTS));
423                         customDefsFinal.putAll(importDefs);
424                     }
425                 }
426             }
427         }
428
429         // As imports are not custom_types, remove from the dict
430         customDefsFinal.remove(IMPORTS);
431
432         return customDefsFinal;
433     }
434
435     /**
436      * This method is used to sort the imports in order so that same directory
437      * imports will be processed first
438      *
439      * @param customImports the custom imports
440      * @return the sorted list of imports
441      */
442     private List<Map<String, Object>> sortImports(List<Map<String, Object>> customImports) {
443         List<Map<String, Object>> finalList1 = new ArrayList<>();
444         List<Map<String, Object>> finalList2 = new ArrayList<>();
445         Iterator<Map<String, Object>> itr = customImports.iterator();
446         while (itr.hasNext()) {
447             Map<String, Object> innerMap = itr.next();
448             if (innerMap.toString().contains("../")) {
449                 finalList2.add(innerMap);
450                 itr.remove();
451             } else if (innerMap.toString().contains("/")) {
452                 finalList1.add(innerMap);
453                 itr.remove();
454             }
455         }
456
457         customImports.addAll(finalList1);
458         customImports.addAll(finalList2);
459         return customImports;
460     }
461
462     /**
463      * This method is used to reset PATH variable after processing of current import file is done
464      * This is required because of relative path nature of imports present in files.
465      *
466      * @param currImportRelativeName the current import relative name
467      */
468     private void resetPathForRecursiveImports(String currImportRelativeName) {
469         path = getPath(path, currImportRelativeName);
470     }
471
472     /**
473      * This is a recursive method which starts from current import and then recursively finds a
474      * valid path relative to current import file name.
475      * By doing this it handles all nested hierarchy of imports defined in CSARs
476      *
477      * @param path           the path
478      * @param importFileName the import file name
479      * @return the string containing updated path value
480      */
481     private String getPath(String path, String importFileName) {
482         String tempFullPath = (Paths.get(path).toAbsolutePath().getParent()
483                 .toString() + File.separator + importFileName.replace("../", "")).replace('\\', '/');
484         String tempPartialPath = (Paths.get(path).toAbsolutePath().getParent().toString()).replace('\\', '/');
485         if (Files.exists(Paths.get(tempFullPath)))
486             return tempFullPath;
487         else
488             return getPath(tempPartialPath, importFileName);
489     }
490
491     /**
492      * This method is used to get full path name for the file which needs to be processed. It helps
493      * in situation where files are present in different directory and are references as relative
494      * paths.
495      *
496      * @param customImports the custom imports
497      * @return the map containing import file full and relative paths
498      */
499     private Map<String, String> getValidFileNameForImportReference(List<Map<String, Object>> customImports) {
500         String importFileName;
501         Map<String, String> retMap = new HashMap<>();
502         for (Map<String, Object> map1 : customImports) {
503             for (Map.Entry<String, Object> entry : map1.entrySet()) {
504                 Map innerMostMap = (Map) entry.getValue();
505                 Iterator<Map.Entry<String, String>> it = innerMostMap.entrySet().iterator();
506                 while (it.hasNext()) {
507                     Map.Entry<String, String> val = it.next();
508                     if (val.getValue().contains("/")) {
509                         importFileName = (Paths.get(rootPath).toAbsolutePath().getParent().toString() + File
510                                 .separator + val.getValue().replace("../", "")).replace('\\', '/');
511                     } else {
512                         importFileName = (Paths.get(path).toAbsolutePath().getParent().toString() + File
513                                 .separator + val.getValue().replace("../", "")).replace('\\', '/');
514                     }
515                     retMap.put("importFileName", importFileName);
516                     retMap.put("importRelativeName", val.getValue());
517                 }
518             }
519         }
520         return retMap;
521     }
522
523     /**
524      * This method is used to filter the imports which already gets processed in previous step.
525      * It handles the use case of cyclic dependency in imports which may cause Stack Overflow
526      * exception
527      *
528      * @param customImports     the custom imports
529      * @param importNameDetails the import name details
530      * @return the list containing filtered imports
531      */
532     private List<Map<String, Object>> filterImportsForRecursion(List<Map<String, Object>>
533                                                                         customImports, Map<String,
534             String> importNameDetails) {
535         for (Map<String, Object> map1 : customImports) {
536             for (Map.Entry<String, Object> entry : map1.entrySet()) {
537                 Map innerMostMap = (Map) entry.getValue();
538                 Iterator<Map.Entry<String, String>> it = innerMostMap.entrySet().iterator();
539                 while (it.hasNext()) {
540                     it.next();
541                     if (processedImports.contains(importNameDetails.get("importFileName"))) {
542                         it.remove();
543                     }
544                 }
545             }
546         }
547
548         // Remove Empty elements
549         Iterator<Map<String, Object>> itr = customImports.iterator();
550         while (itr.hasNext()) {
551             Map innerMap = itr.next();
552             Predicate<Map> predicate = p -> p.values().isEmpty();
553             innerMap.values().removeIf(predicate);
554         }
555
556         return customImports;
557     }
558
559     @SuppressWarnings("unchecked")
560     private LinkedHashMap<String, Object> _getCustomTypes(Object typeDefinitions, ArrayList<Object> alImports) {
561
562         // Handle custom types defined in imported template files
563         // This method loads the custom type definitions referenced in "imports"
564         // section of the TOSCA YAML template.
565
566         LinkedHashMap<String, Object> customDefs = new LinkedHashMap<String, Object>();
567         ArrayList<String> typeDefs = new ArrayList<String>();
568         if (typeDefinitions instanceof String[]) {
569             for (String s : (String[]) typeDefinitions) {
570                 typeDefs.add(s);
571             }
572         } else {
573             typeDefs.add((String) typeDefinitions);
574         }
575
576         if (alImports == null) {
577             alImports = _tplImports();
578         }
579
580         if (alImports != null) {
581             ImportsLoader customService = new ImportsLoader(alImports, path, typeDefs, tpl);
582             ArrayList<LinkedHashMap<String, Object>> nestedToscaTpls = customService.getNestedToscaTpls();
583             _updateNestedToscaTplsWithTopology(nestedToscaTpls);
584
585             customDefs = customService.getCustomDefs();
586             if (customDefs == null) {
587                 return null;
588             }
589         }
590
591         //Handle custom types defined in current template file
592         for (String td : typeDefs) {
593             if (!td.equals(IMPORTS)) {
594                 LinkedHashMap<String, Object> innerCustomTypes = (LinkedHashMap<String, Object>) tpl.get(td);
595                 if (innerCustomTypes != null) {
596                     customDefs.putAll(innerCustomTypes);
597                 }
598             }
599         }
600         return customDefs;
601     }
602
603     private void _updateNestedToscaTplsWithTopology(ArrayList<LinkedHashMap<String, Object>> nestedToscaTpls) {
604         for (LinkedHashMap<String, Object> ntpl : nestedToscaTpls) {
605             // there is just one key:value pair in ntpl
606             for (Map.Entry<String, Object> me : ntpl.entrySet()) {
607                 String fileName = me.getKey();
608                 @SuppressWarnings("unchecked")
609                 LinkedHashMap<String, Object> toscaTpl = (LinkedHashMap<String, Object>) me.getValue();
610                 if (toscaTpl.get(TOPOLOGY_TEMPLATE) != null) {
611                     if (nestedToscaTplsWithTopology.get(fileName) == null) {
612                         nestedToscaTplsWithTopology.putAll(ntpl);
613                     }
614                 }
615             }
616         }
617     }
618
619     // multi level nesting - RECURSIVE
620     @SuppressWarnings("unchecked")
621     private void _handleNestedToscaTemplatesWithTopology(TopologyTemplate tt) {
622         if (++nestingLoopCounter > MAX_LEVELS) {
623             log.error("ToscaTemplate - _handleNestedToscaTemplatesWithTopology - Nested Topologies Loop: too many levels, aborting");
624             return;
625         }
626         // Reset Processed Imports for nested templates
627         this.processedImports = new HashSet<>();
628         for (Map.Entry<String, Object> me : nestedToscaTplsWithTopology.entrySet()) {
629             LinkedHashMap<String, Object> toscaTpl =
630                     (LinkedHashMap<String, Object>) me.getValue();
631             for (NodeTemplate nt : tt.getNodeTemplates()) {
632                 if (_isSubMappedNode(nt, toscaTpl)) {
633                     parsedParams = _getParamsForNestedTemplate(nt);
634                     ArrayList<Object> alim = (ArrayList<Object>) toscaTpl.get(IMPORTS);
635                     LinkedHashMap<String, Object> topologyTpl =
636                             (LinkedHashMap<String, Object>) toscaTpl.get(TOPOLOGY_TEMPLATE);
637                     TopologyTemplate topologyWithSubMapping =
638                             new TopologyTemplate(topologyTpl,
639                                     _getAllCustomDefs(alim),
640                                     relationshipTypes,
641                                     parsedParams,
642                                     nt,
643                                     resolveGetInput);
644                     nt.setOriginComponentTemplate(topologyWithSubMapping);
645                     if (topologyWithSubMapping.getSubstitutionMappings() != null) {
646                         // Record nested topology templates in top level template
647                         //nestedToscaTemplatesWithTopology.add(topologyWithSubMapping);
648                         // Set substitution mapping object for mapped node
649                         nt.setSubMappingToscaTemplate(
650                                 topologyWithSubMapping.getSubstitutionMappings());
651                         _handleNestedToscaTemplatesWithTopology(topologyWithSubMapping);
652                     }
653                 }
654             }
655         }
656     }
657
658 //      private void _handleNestedToscaTemplatesWithTopology() {
659 //              for(Map.Entry<String,Object> me: nestedToscaTplsWithTopology.entrySet()) {
660 //                      String fname = me.getKey();
661 //                      LinkedHashMap<String,Object> toscaTpl =
662 //                                                      (LinkedHashMap<String,Object>)me.getValue();
663 //                      for(NodeTemplate nt: nodeTemplates) {
664 //                              if(_isSubMappedNode(nt,toscaTpl)) {
665 //                                      parsedParams = _getParamsForNestedTemplate(nt);
666 //                    ArrayList<Object> alim = (ArrayList<Object>)toscaTpl.get(IMPORTS);
667 //                                      LinkedHashMap<String,Object> topologyTpl =
668 //                                                      (LinkedHashMap<String,Object>)toscaTpl.get(TOPOLOGY_TEMPLATE);
669 //                                      TopologyTemplate topologyWithSubMapping =
670 //                                                      new TopologyTemplate(topologyTpl,
671 //                                                                                              //_getAllCustomDefs(null),
672 //                                                                                              _getAllCustomDefs(alim),
673 //                                                                                              relationshipTypes,
674 //                                                                                              parsedParams,
675 //                                                                                              nt);
676 //                                      if(topologyWithSubMapping.getSubstitutionMappings() != null) {
677 //                        // Record nested topology templates in top level template
678 //                        nestedToscaTemplatesWithTopology.add(topologyWithSubMapping);
679 //                        // Set substitution mapping object for mapped node
680 //                        nt.setSubMappingToscaTemplate(
681 //                                      topologyWithSubMapping.getSubstitutionMappings());
682 //                                      }
683 //                              }
684 //                      }
685 //              }
686 //      }
687
688     private void _validateField() {
689         String sVersion = _tplVersion();
690         if (sVersion == null) {
691             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE245", String.format(
692                     "MissingRequiredField: Template is missing required field \"%s\"", DEFINITION_VERSION)));
693         } else {
694             _validateVersion(sVersion);
695             this.version = sVersion;
696         }
697
698         for (String sKey : tpl.keySet()) {
699             boolean bFound = false;
700             for (String sSection : SECTIONS) {
701                 if (sKey.equals(sSection)) {
702                     bFound = true;
703                     break;
704                 }
705             }
706             // check ADDITIONAL_SECTIONS
707             if (!bFound) {
708                 if (ADDITIONAL_SECTIONS.get(version) != null &&
709                         ADDITIONAL_SECTIONS.get(version).contains(sKey)) {
710                     bFound = true;
711                 }
712             }
713             if (!bFound) {
714                 ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE246", String.format(
715                         "UnknownFieldError: Template contains unknown field \"%s\"",
716                         sKey)));
717             }
718         }
719     }
720
721     private void _validateVersion(String sVersion) {
722         boolean bFound = false;
723         for (String vtv : VALID_TEMPLATE_VERSIONS) {
724             if (sVersion.equals(vtv)) {
725                 bFound = true;
726                 break;
727             }
728         }
729         if (!bFound) {
730             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE247", String.format(
731                     "InvalidTemplateVersion: \"%s\" is invalid. Valid versions are %s",
732                     sVersion, VALID_TEMPLATE_VERSIONS.toString())));
733         } else if ((!sVersion.equals("tosca_simple_yaml_1_0") && !sVersion.equals("tosca_simple_yaml_1_1"))) {
734             EntityType.updateDefinitions(sVersion);
735
736         }
737     }
738
739     private String _getPath(String _path) throws JToscaException {
740         if (_path.toLowerCase().endsWith(".yaml") || _path.toLowerCase().endsWith(".yml")) {
741             return _path;
742         } else if (_path.toLowerCase().endsWith(".zip") || _path.toLowerCase().endsWith(".csar")) {
743             // a CSAR archive
744             CSAR csar = new CSAR(_path, isFile);
745             if (csar.validate()) {
746                 try {
747                     csar.decompress();
748                     metaProperties = csar.getMetaProperties();
749                 } catch (IOException e) {
750                     log.error("ToscaTemplate - _getPath - IOException trying to decompress {}", _path);
751                     return null;
752                 }
753                 isFile = true; // the file has been decompressed locally
754                 csar.cleanup();
755                 csarTempDir = csar.getTempDir();
756                 return csar.getTempDir() + File.separator + csar.getMainTemplate();
757             }
758         } else {
759             ThreadLocalsHolder.getCollector().appendValidationIssue(new JToscaValidationIssue("JE248", "ValueError: " + _path + " is not a valid file"));
760             return null;
761         }
762         return null;
763     }
764
765     private void verifyTemplate() throws JToscaException {
766         //Criticals
767         int validationIssuesCaught = ThreadLocalsHolder.getCollector().validationIssuesCaught();
768         if (validationIssuesCaught > 0) {
769             List<String> validationIssueStrings = ThreadLocalsHolder.getCollector().getValidationIssueReport();
770             log.trace("####################################################################################################");
771             log.trace("ToscaTemplate - verifyTemplate - {} Parsing Critical{} occurred...", validationIssuesCaught, (validationIssuesCaught > 1 ? "s" : ""));
772             for (String s : validationIssueStrings) {
773                 log.trace("{}. CSAR name - {}", s, inputPath);
774             }
775             log.trace("####################################################################################################");
776         }
777
778     }
779
780     public String getPath() {
781         return path;
782     }
783
784     public String getVersion() {
785         return version;
786     }
787
788     public String getDescription() {
789         return description;
790     }
791
792     public TopologyTemplate getTopologyTemplate() {
793         return topologyTemplate;
794     }
795
796     public Metadata getMetaData() {
797         return metaData;
798     }
799
800     public ArrayList<Input> getInputs() {
801         if (inputs != null) {
802             inputs.stream().forEach(Input::resetAnnotaions);
803         }
804         return inputs;
805     }
806
807     public ArrayList<Output> getOutputs() {
808         return outputs;
809     }
810
811     public ArrayList<Policy> getPolicies() {
812         return policies;
813     }
814
815     public ArrayList<Group> getGroups() {
816         return groups;
817     }
818
819     public ArrayList<NodeTemplate> getNodeTemplates() {
820         return nodeTemplates;
821     }
822
823     public LinkedHashMap<String, Object> getMetaProperties(String propertiesFile) {
824         return metaProperties.get(propertiesFile);
825     }
826
827 //      private boolean _isSubMappedNode(NodeTemplate nt,LinkedHashMap<String,Object> toscaTpl) {
828 //              // Return True if the nodetemple is substituted
829 //              if(nt != null && nt.getSubMappingToscaTemplate() == null &&
830 //                              getSubMappingNodeType(toscaTpl).equals(nt.getType()) &&
831 //                              nt.getInterfaces().size() < 1) {
832 //                      return true;
833 //              }
834 //              return false;
835 //      }
836
837     private boolean _isSubMappedNode(NodeTemplate nt, LinkedHashMap<String, Object> toscaTpl) {
838         // Return True if the nodetemple is substituted
839         if (nt != null && nt.getSubMappingToscaTemplate() == null &&
840                 getSubMappingNodeType(toscaTpl).equals(nt.getType()) &&
841                 nt.getInterfaces().size() < 1) {
842             return true;
843         }
844         return false;
845     }
846
847     private LinkedHashMap<String, Object> _getParamsForNestedTemplate(NodeTemplate nt) {
848         // Return total params for nested_template
849         LinkedHashMap<String, Object> pparams;
850         if (parsedParams != null) {
851             pparams = parsedParams;
852         } else {
853             pparams = new LinkedHashMap<String, Object>();
854         }
855         if (nt != null) {
856             for (String pname : nt.getProperties().keySet()) {
857                 pparams.put(pname, nt.getPropertyValue(pname));
858             }
859         }
860         return pparams;
861     }
862
863     @SuppressWarnings("unchecked")
864     private String getSubMappingNodeType(LinkedHashMap<String, Object> toscaTpl) {
865         // Return substitution mappings node type
866         if (toscaTpl != null) {
867             return TopologyTemplate.getSubMappingNodeType(
868                     (LinkedHashMap<String, Object>) toscaTpl.get(TOPOLOGY_TEMPLATE));
869         }
870         return null;
871     }
872
873     public boolean hasNestedTemplates() {
874         // Return True if the tosca template has nested templates
875         return nestedToscaTemplatesWithTopology != null &&
876                 nestedToscaTemplatesWithTopology.size() >= 1;
877
878     }
879
880     public ArrayList<TopologyTemplate> getNestedTemplates() {
881         return nestedToscaTemplatesWithTopology;
882     }
883
884     public ConcurrentHashMap<String, Object> getNestedTopologyTemplates() {
885         return nestedToscaTplsWithTopology;
886     }
887
888     /**
889      * Get datatypes.
890      *
891      * @return return list of datatypes.
892      */
893     public HashSet<DataType> getDataTypes() {
894         return dataTypes;
895     }
896
897     @Override
898     public String toString() {
899         return "ToscaTemplate{" +
900                 "exttools=" + exttools +
901                 ", VALID_TEMPLATE_VERSIONS=" + VALID_TEMPLATE_VERSIONS +
902                 ", ADDITIONAL_SECTIONS=" + ADDITIONAL_SECTIONS +
903                 ", isFile=" + isFile +
904                 ", path='" + path + '\'' +
905                 ", inputPath='" + inputPath + '\'' +
906                 ", parsedParams=" + parsedParams +
907                 ", tpl=" + tpl +
908                 ", version='" + version + '\'' +
909                 ", imports=" + imports +
910                 ", relationshipTypes=" + relationshipTypes +
911                 ", metaData=" + metaData +
912                 ", description='" + description + '\'' +
913                 ", topologyTemplate=" + topologyTemplate +
914                 ", repositories=" + repositories +
915                 ", inputs=" + inputs +
916                 ", relationshipTemplates=" + relationshipTemplates +
917                 ", nodeTemplates=" + nodeTemplates +
918                 ", outputs=" + outputs +
919                 ", policies=" + policies +
920                 ", nestedToscaTplsWithTopology=" + nestedToscaTplsWithTopology +
921                 ", nestedToscaTemplatesWithTopology=" + nestedToscaTemplatesWithTopology +
922                 ", graph=" + graph +
923                 ", csarTempDir='" + csarTempDir + '\'' +
924                 ", nestingLoopCounter=" + nestingLoopCounter +
925                 ", dataTypes=" + dataTypes +
926                 '}';
927     }
928
929     public List<Input> getInputs(boolean annotationsRequired) {
930         if (inputs != null && annotationsRequired) {
931             inputs.stream().forEach(Input::parseAnnotations);
932             return inputs;
933         }
934         return getInputs();
935     }
936 }
937
938 /*python
939
940 import logging
941 import os
942
943 from copy import deepcopy
944 from toscaparser.common.exception import ValidationIssueCollector.collector
945 from toscaparser.common.exception import InvalidTemplateVersion
946 from toscaparser.common.exception import MissingRequiredFieldError
947 from toscaparser.common.exception import UnknownFieldError
948 from toscaparser.common.exception import ValidationError
949 from toscaparser.elements.entity_type import update_definitions
950 from toscaparser.extensions.exttools import ExtTools
951 import org.openecomp.sdc.toscaparser.api.imports
952 from toscaparser.prereq.csar import CSAR
953 from toscaparser.repositories import Repository
954 from toscaparser.topology_template import TopologyTemplate
955 from toscaparser.tpl_relationship_graph import ToscaGraph
956 from toscaparser.utils.gettextutils import _
957 import org.openecomp.sdc.toscaparser.api.utils.yamlparser
958
959
960 # TOSCA template key names
961 SECTIONS = (DEFINITION_VERSION, DEFAULT_NAMESPACE, TEMPLATE_NAME,
962             TOPOLOGY_TEMPLATE, TEMPLATE_AUTHOR, TEMPLATE_VERSION,
963             DESCRIPTION, IMPORTS, DSL_DEFINITIONS, NODE_TYPES,
964             RELATIONSHIP_TYPES, RELATIONSHIP_TEMPLATES,
965             CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, INTERFACE_TYPES,
966             POLICY_TYPES, GROUP_TYPES, REPOSITORIES) = \
967            ('tosca_definitions_version', 'tosca_default_namespace',
968             'template_name', 'topology_template', 'template_author',
969             'template_version', 'description', 'imports', 'dsl_definitions',
970             'node_types', 'relationship_types', 'relationship_templates',
971             'capability_types', 'artifact_types', 'data_types',
972             'interface_types', 'policy_types', 'group_types', 'repositories')
973 # Sections that are specific to individual template definitions
974 SPECIAL_SECTIONS = (METADATA) = ('metadata')
975
976 log = logging.getLogger("tosca.model")
977
978 YAML_LOADER = toscaparser.utils.yamlparser.load_yaml
979
980
981 class ToscaTemplate(object):
982     exttools = ExtTools()
983
984     VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
985
986     VALID_TEMPLATE_VERSIONS.extend(exttools.get_versions())
987
988     ADDITIONAL_SECTIONS = {'tosca_simple_yaml_1_0': SPECIAL_SECTIONS}
989
990     ADDITIONAL_SECTIONS.update(exttools.get_sections())
991
992     '''Load the template data.'''
993     def __init__(self, path=None, parsed_params=None, a_file=True,
994                  yaml_dict_tpl=None):
995
996         ValidationIssueCollector.collector.start()
997         self.a_file = a_file
998         self.input_path = None
999         self.path = None
1000         self.tpl = None
1001         self.nested_tosca_tpls_with_topology = {}
1002         self.nested_tosca_templates_with_topology = []
1003         if path:
1004             self.input_path = path
1005             self.path = self._get_path(path)
1006             if self.path:
1007                 self.tpl = YAML_LOADER(self.path, self.a_file)
1008             if yaml_dict_tpl:
1009                 msg = (_('Both path and yaml_dict_tpl arguments were '
1010                          'provided. Using path and ignoring yaml_dict_tpl.'))
1011                 log.info(msg)
1012                 print(msg)
1013         else:
1014             if yaml_dict_tpl:
1015                 self.tpl = yaml_dict_tpl
1016             else:
1017                 ValidationIssueCollector.collector.appendException(
1018                     ValueError(_('No path or yaml_dict_tpl was provided. '
1019                                  'There is nothing to parse.')))
1020
1021         if self.tpl:
1022             self.parsed_params = parsed_params
1023             self._validate_field()
1024             self.version = self._tpl_version()
1025             self.relationship_types = self._tpl_relationship_types()
1026             self.description = self._tpl_description()
1027             self.topology_template = self._topology_template()
1028             self.repositories = self._tpl_repositories()
1029             if self.topology_template.tpl:
1030                 self.inputs = self._inputs()
1031                 self.relationship_templates = self._relationship_templates()
1032                 self.nodetemplates = self._nodetemplates()
1033                 self.outputs = self._outputs()
1034                 self._handle_nested_tosca_templates_with_topology()
1035                 self.graph = ToscaGraph(self.nodetemplates)
1036
1037         ValidationIssueCollector.collector.stop()
1038         self.verify_template()
1039
1040     def _topology_template(self):
1041         return TopologyTemplate(self._tpl_topology_template(),
1042                                 self._get_all_custom_defs(),
1043                                 self.relationship_types,
1044                                 self.parsed_params,
1045                                 None)
1046
1047     def _inputs(self):
1048         return self.topology_template.inputs
1049
1050     def _nodetemplates(self):
1051         return self.topology_template.nodetemplates
1052
1053     def _relationship_templates(self):
1054         return self.topology_template.relationship_templates
1055
1056     def _outputs(self):
1057         return self.topology_template.outputs
1058
1059     def _tpl_version(self):
1060         return self.tpl.get(DEFINITION_VERSION)
1061
1062     def _tpl_description(self):
1063         desc = self.tpl.get(DESCRIPTION)
1064         if desc:
1065             return desc.rstrip()
1066
1067     def _tpl_imports(self):
1068         return self.tpl.get(IMPORTS)
1069
1070     def _tpl_repositories(self):
1071         repositories = self.tpl.get(REPOSITORIES)
1072         reposit = []
1073         if repositories:
1074             for name, val in repositories.items():
1075                 reposits = Repository(name, val)
1076                 reposit.append(reposits)
1077         return reposit
1078
1079     def _tpl_relationship_types(self):
1080         return self._get_custom_types(RELATIONSHIP_TYPES)
1081
1082     def _tpl_relationship_templates(self):
1083         topology_template = self._tpl_topology_template()
1084         return topology_template.get(RELATIONSHIP_TEMPLATES)
1085
1086     def _tpl_topology_template(self):
1087         return self.tpl.get(TOPOLOGY_TEMPLATE)
1088
1089     def _get_all_custom_defs(self, imports=None):
1090         types = [IMPORTS, NODE_TYPES, CAPABILITY_TYPES, RELATIONSHIP_TYPES,
1091                  DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES]
1092         custom_defs_final = {}
1093         custom_defs = self._get_custom_types(types, imports)
1094         if custom_defs:
1095             custom_defs_final.update(custom_defs)
1096             if custom_defs.get(IMPORTS):
1097                 import_defs = self._get_all_custom_defs(
1098                     custom_defs.get(IMPORTS))
1099                 custom_defs_final.update(import_defs)
1100
1101         # As imports are not custom_types, removing from the dict
1102         custom_defs_final.pop(IMPORTS, None)
1103         return custom_defs_final
1104
1105     def _get_custom_types(self, type_definitions, imports=None):
1106         """Handle custom types defined in imported template files
1107
1108         This method loads the custom type definitions referenced in "imports"
1109         section of the TOSCA YAML template.
1110         """
1111         custom_defs = {}
1112         type_defs = []
1113         if not isinstance(type_definitions, list):
1114             type_defs.append(type_definitions)
1115         else:
1116             type_defs = type_definitions
1117
1118         if not imports:
1119             imports = self._tpl_imports()
1120
1121         if imports:
1122             custom_service = toscaparser.imports.\
1123                 ImportsLoader(imports, self.path,
1124                               type_defs, self.tpl)
1125
1126             nested_tosca_tpls = custom_service.get_nested_tosca_tpls()
1127             self._update_nested_tosca_tpls_with_topology(nested_tosca_tpls)
1128
1129             custom_defs = custom_service.get_custom_defs()
1130             if not custom_defs:
1131                 return
1132
1133         # Handle custom types defined in current template file
1134         for type_def in type_defs:
1135             if type_def != IMPORTS:
1136                 inner_custom_types = self.tpl.get(type_def) or {}
1137                 if inner_custom_types:
1138                     custom_defs.update(inner_custom_types)
1139         return custom_defs
1140
1141     def _update_nested_tosca_tpls_with_topology(self, nested_tosca_tpls):
1142         for tpl in nested_tosca_tpls:
1143             filename, tosca_tpl = list(tpl.items())[0]
1144             if (tosca_tpl.get(TOPOLOGY_TEMPLATE) and
1145                 filename not in list(
1146                     self.nested_tosca_tpls_with_topology.keys())):
1147                 self.nested_tosca_tpls_with_topology.update(tpl)
1148
1149     def _handle_nested_tosca_templates_with_topology(self):
1150         for fname, tosca_tpl in self.nested_tosca_tpls_with_topology.items():
1151             for nodetemplate in self.nodetemplates:
1152                 if self._is_sub_mapped_node(nodetemplate, tosca_tpl):
1153                     parsed_params = self._get_params_for_nested_template(
1154                         nodetemplate)
1155                     topology_tpl = tosca_tpl.get(TOPOLOGY_TEMPLATE)
1156                     topology_with_sub_mapping = TopologyTemplate(
1157                         topology_tpl,
1158                         self._get_all_custom_defs(),
1159                         self.relationship_types,
1160                         parsed_params,
1161                         nodetemplate)
1162                     if topology_with_sub_mapping.substitution_mappings:
1163                         # Record nested topo templates in top level template
1164                         self.nested_tosca_templates_with_topology.\
1165                             append(topology_with_sub_mapping)
1166                         # Set substitution mapping object for mapped node
1167                         nodetemplate.sub_mapping_tosca_template = \
1168                             topology_with_sub_mapping.substitution_mappings
1169
1170     def _validate_field(self):
1171         version = self._tpl_version()
1172         if not version:
1173             ValidationIssueCollector.collector.appendException(
1174                 MissingRequiredFieldError(what='Template',
1175                                           required=DEFINITION_VERSION))
1176         else:
1177             self._validate_version(version)
1178             self.version = version
1179
1180         for name in self.tpl:
1181             if (name not in SECTIONS and
1182                name not in self.ADDITIONAL_SECTIONS.get(version, ())):
1183                 ValidationIssueCollector.collector.appendException(
1184                     UnknownFieldError(what='Template', field=name))
1185
1186     def _validate_version(self, version):
1187         if version not in self.VALID_TEMPLATE_VERSIONS:
1188             ValidationIssueCollector.collector.appendException(
1189                 InvalidTemplateVersion(
1190                     what=version,
1191                     valid_versions=', '. join(self.VALID_TEMPLATE_VERSIONS)))
1192         else:
1193             if version != 'tosca_simple_yaml_1_0':
1194                 update_definitions(version)
1195
1196     def _get_path(self, path):
1197         if path.lower().endswith(('.yaml','.yml')):
1198             return path
1199         elif path.lower().endswith(('.zip', '.csar')):
1200             # a CSAR archive
1201             csar = CSAR(path, self.a_file)
1202             if csar.validate():
1203                 csar.decompress()
1204                 self.a_file = True  # the file has been decompressed locally
1205                 return os.path.join(csar.temp_dir, csar.get_main_template())
1206         else:
1207             ValidationIssueCollector.collector.appendException(
1208                 ValueError(_('"%(path)s" is not a valid file.')
1209                            % {'path': path}))
1210
1211     def verify_template(self):
1212         if ValidationIssueCollector.collector.exceptionsCaught():
1213             if self.input_path:
1214                 raise ValidationError(
1215                     message=(_('\nThe input "%(path)s" failed validation with '
1216                                'the following error(s): \n\n\t')
1217                              % {'path': self.input_path}) +
1218                     '\n\t'.join(ValidationIssueCollector.collector.getExceptionsReport()))
1219             else:
1220                 raise ValidationError(
1221                     message=_('\nThe pre-parsed input failed validation with '
1222                               'the following error(s): \n\n\t') +
1223                     '\n\t'.join(ValidationIssueCollector.collector.getExceptionsReport()))
1224         else:
1225             if self.input_path:
1226                 msg = (_('The input "%(path)s" successfully passed '
1227                          'validation.') % {'path': self.input_path})
1228             else:
1229                 msg = _('The pre-parsed input successfully passed validation.')
1230
1231             log.info(msg)
1232
1233     def _is_sub_mapped_node(self, nodetemplate, tosca_tpl):
1234         """Return True if the nodetemple is substituted."""
1235         if (nodetemplate and not nodetemplate.sub_mapping_tosca_template and
1236                 self.get_sub_mapping_node_type(tosca_tpl) == nodetemplate.type
1237                 and len(nodetemplate.interfaces) < 1):
1238             return True
1239         else:
1240             return False
1241
1242     def _get_params_for_nested_template(self, nodetemplate):
1243         """Return total params for nested_template."""
1244         parsed_params = deepcopy(self.parsed_params) \
1245             if self.parsed_params else {}
1246         if nodetemplate:
1247             for pname in nodetemplate.get_properties():
1248                 parsed_params.update({pname:
1249                                       nodetemplate.get_property_value(pname)})
1250         return parsed_params
1251
1252     def get_sub_mapping_node_type(self, tosca_tpl):
1253         """Return substitution mappings node type."""
1254         if tosca_tpl:
1255             return TopologyTemplate.get_sub_mapping_node_type(
1256                 tosca_tpl.get(TOPOLOGY_TEMPLATE))
1257
1258     def _has_substitution_mappings(self):
1259         """Return True if the template has valid substitution mappings."""
1260         return self.topology_template is not None and \
1261             self.topology_template.substitution_mappings is not None
1262
1263     def has_nested_templates(self):
1264         """Return True if the tosca template has nested templates."""
1265         return self.nested_tosca_templates_with_topology is not None and \
1266             len(self.nested_tosca_templates_with_topology) >= 1
1267 */