Merge of new rebased code
[appc.git] / appc-asdc-listener / appc-yang-generator / src / main / java / org / openecomp / appc / yang / impl / YANGGeneratorImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.appc.yang.impl;
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.velocity.Template;
28 import org.apache.velocity.VelocityContext;
29 import org.apache.velocity.app.VelocityEngine;
30 import org.apache.velocity.exception.ParseErrorException;
31 import org.apache.velocity.exception.ResourceNotFoundException;
32 import org.apache.velocity.runtime.RuntimeConstants;
33 import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
34 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
35 import org.openecomp.appc.yang.YANGGenerator;
36 import org.openecomp.appc.yang.exception.YANGGenerationException;
37 import org.openecomp.appc.yang.objects.Leaf;
38 import org.openecomp.appc.yang.type.YangTypes;
39 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
40 import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
41 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
42 import org.openecomp.sdc.tosca.services.yamlutil.ToscaExtensionYamlUtil;
43
44 import java.io.*;
45 import java.util.HashMap;
46 import java.util.LinkedList;
47 import java.util.List;
48 import java.util.Map;
49
50 @SuppressWarnings("CheckStyle")
51 public class YANGGeneratorImpl implements YANGGenerator {
52
53         private static final EELFLogger Log = EELFManager.getInstance().getLogger(YANGGeneratorImpl.class);
54         private static final String MODULE_TYPE = "moduleType";
55         private static final String LEAVES = "leaves";
56
57
58         /* (non-Javadoc)
59          * @see org.openecomp.appc.yang.YANGGenerator#generateYANG(java.lang.String, java.lang.String, java.io.OutputStream)
60          */
61         @Override
62         public void generateYANG(String uniqueID, String tosca, OutputStream stream)
63                         throws  YANGGenerationException {
64                 Log.info("Entered into generateYANG.");
65                 Log.debug("Received Tosca:\n" + tosca +"\n Received uniqueID:  "+uniqueID);
66
67                 validateInput(uniqueID, tosca, stream);
68                 Map<String,Object> parsedToscaMap = parseTosca(tosca);
69                 String moduleType =parsedToscaMap.get(MODULE_TYPE).toString();
70                 List<Leaf> leaves = (List<Leaf>) parsedToscaMap.get(LEAVES);
71                 VelocityEngine ve = new VelocityEngine();
72                 ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
73                 ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
74                 ve.init();
75                 Template template;
76
77                 try {
78                         template = ve.getTemplate("templates/YangTemplate.vm");
79                 } catch ( ResourceNotFoundException | ParseErrorException ex) {
80                         Log.error("Error while retrieving YANG Template", ex);
81                         throw new YANGGenerationException("Error while retrieving YANG Template",ex);
82                 }
83
84                 VelocityContext vc = new VelocityContext();
85
86                 vc.put("moduleName", uniqueID);
87                 vc.put(MODULE_TYPE, moduleType);
88                 vc.put(LEAVES, leaves);
89
90                 StringWriter sw = new StringWriter();
91                 template.merge(vc,sw);
92                 Log.debug("generated YANG \n "+sw.toString());
93                 try {
94                         String yang = sw.toString();
95                         validateYang(yang);
96                         stream.write(yang.getBytes());
97                         stream.flush();
98                 } catch (IOException e) {
99                         Log.error("Error while writing to outputstream", e);
100                         throw new YANGGenerationException("Error writing to outputstream",e);
101                 } finally {
102                         try {
103                                 stream.close();
104                         } catch (IOException e) {
105                                 Log.error("Error while closing outputstream", e);
106                         }
107                 }
108                 Log.info("exiting generateYANG method.");
109         }
110
111         private void validateYang(String yang) throws YANGGenerationException {
112
113                 try(InputStream inputYangStream = new ByteArrayInputStream(yang.getBytes())){
114                         YangStatementSourceImpl statementSource = new YangStatementSourceImpl(inputYangStream);
115                         if(statementSource.getYangAST()==null){
116                                 throw new YANGGenerationException("Syntax Error in Generated YANG = " + yang);
117                         }
118                 }
119                 catch(IOException e){
120                         Log.error("Error validating yang file "+ yang,e);
121                         throw new YANGGenerationException("Invalid YANG generated",e);
122                 }
123         }
124
125         private Map<String,Object> parseTosca(String tosca) throws YANGGenerationException {
126                 Log.info("Entered into parseTosca.");
127                 ServiceTemplate serviceTemplate = new ToscaExtensionYamlUtil().yamlToObject(tosca, ServiceTemplate.class);
128                 Map<String, NodeType> nodeTypeMap = serviceTemplate.getNode_types();
129                 String kind = nodeTypeMap.keySet().toArray(new String[0])[0];
130                 NodeType nodeType = nodeTypeMap.get(kind);
131                 Map<String,Object> returnMap= new HashMap<>();
132                 Map<String, PropertyDefinition> propertyDefinitionFromTOSCA = nodeType.getProperties();
133                 returnMap.put(MODULE_TYPE, kind);
134                 List<Leaf> leaves =  new LinkedList<>();
135
136                 for(Map.Entry<String, PropertyDefinition> entry: propertyDefinitionFromTOSCA.entrySet()){
137                         Leaf leaf = new Leaf();
138                         leaf.setName(entry.getKey());
139                         PropertyDefinition pd = entry.getValue();
140                         Map<String,String> typeMap=YangTypes.getYangTypeMap();
141                         if (typeMap.containsKey(pd.getType())) {
142                                 String paramType = typeMap.get(pd.getType());
143                                 leaf.setType(paramType);
144                                 leaf.setDescription(!StringUtils.isEmpty(pd.getDescription()) ? pd.getDescription() : "");
145                                 leaf.setMandatory((pd.getRequired() != null) ? Boolean.toString(pd.getRequired()) : Boolean.toString(false));
146                                 leaf.setDefaultValue((pd.get_default() != null) ? pd.get_default().toString(): "");
147                                 leaves.add(leaf);
148                         } else {
149                                 YANGGenerationException yangGenerationException = new YANGGenerationException(pd.getType() + " Type is not supported ", null);
150                                 Log.error(pd.getType() + " Type is not supported ", yangGenerationException);
151                                 throw yangGenerationException;
152                         }
153                 }
154                 returnMap.put(LEAVES, leaves);
155                 Log.info("exiting parseTosca method with return MAP "+returnMap);
156                 return returnMap;
157         }
158
159         private void validateInput(String uniqueID, String tosca, OutputStream stream) throws YANGGenerationException {
160                 Log.info("Entered into validateInput.");
161                 if(StringUtils.isEmpty(uniqueID)) {
162                         throw new YANGGenerationException("uniqueID is mandatory, cannot be null or empty.",null);
163                 }
164                 if(StringUtils.isEmpty(tosca)) {
165                         throw new YANGGenerationException("tosca is mandatory, cannot be null or empty.",null);
166                 }
167                 if(stream == null){
168                         throw new YANGGenerationException("stream is mandatory, cannot be null.",null);
169                 }
170                 Log.info("exiting validateInput method.");
171         }
172
173 }