Implement PNFD Model driven conversion
[sdc.git] / common / onap-tosca-datatype / src / main / java / org / onap / sdc / tosca / services / YamlUtil.java
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
17 package org.onap.sdc.tosca.services;
18
19 import java.util.List;
20 import java.util.Optional;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.yaml.snakeyaml.DumperOptions;
24 import org.yaml.snakeyaml.TypeDescription;
25 import org.yaml.snakeyaml.Yaml;
26 import org.yaml.snakeyaml.constructor.Constructor;
27 import org.yaml.snakeyaml.introspector.BeanAccess;
28 import org.yaml.snakeyaml.introspector.Property;
29 import org.yaml.snakeyaml.introspector.PropertyUtils;
30 import org.yaml.snakeyaml.nodes.MappingNode;
31 import org.yaml.snakeyaml.nodes.NodeTuple;
32 import org.yaml.snakeyaml.nodes.Tag;
33 import org.yaml.snakeyaml.parser.ParserException;
34 import org.yaml.snakeyaml.representer.Representer;
35
36
37 import java.beans.IntrospectionException;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.util.AbstractMap;
41 import java.util.LinkedHashMap;
42 import java.util.LinkedHashSet;
43 import java.util.Map;
44 import java.util.Set;
45
46 /**
47  * The type Yaml util.
48  */
49 @SuppressWarnings("unchecked")
50 public class YamlUtil {
51     private static final Logger LOGGER = LoggerFactory.getLogger(YamlUtil.class.getName());
52
53   private static final String DEFAULT = "default";
54   private static final String DEFAULT_STR = "_default";
55
56   /**
57    * Yaml to object t.
58    *
59    * @param <T>         the type parameter
60    * @param yamlContent the yaml content
61    * @param typClass    the t class
62    * @return the t
63    */
64   public <T> T yamlToObject(String yamlContent, Class<T> typClass) {
65     Constructor constructor = getConstructor(typClass);
66     constructor.setPropertyUtils(getPropertyUtils());
67     TypeDescription yamlFileDescription = new TypeDescription(typClass);
68     constructor.addTypeDescription(yamlFileDescription);
69     Yaml yaml = new Yaml(constructor);
70     T yamlObj = (T) yaml.load(yamlContent);
71     //noinspection ResultOfMethodCallIgnored
72     yamlObj.toString();
73     return yamlObj;
74   }
75
76   public InputStream loadYamlFileIs(String yamlFullFileName) {
77     return YamlUtil.class.getResourceAsStream(yamlFullFileName);
78   }
79
80   /**
81    * Yaml to object t.
82    *
83    * @param <T>         the type parameter
84    * @param yamlContent the yaml content
85    * @param typClass    the t class
86    * @return the t
87    */
88   public <T> T yamlToObject(InputStream yamlContent, Class<T> typClass) {
89     try {
90       Constructor constructor = getConstructor(typClass);
91       constructor.setPropertyUtils(getPropertyUtils());
92       TypeDescription yamlFileDescription = new TypeDescription(typClass);
93       constructor.addTypeDescription(yamlFileDescription);
94       Yaml yaml = new Yaml(constructor);
95       T yamlObj = (T) yaml.load(yamlContent);
96       if (yamlObj != null) {
97         //noinspection ResultOfMethodCallIgnored
98         yamlObj.toString();
99         return yamlObj;
100       } else {
101         throw new RuntimeException();
102       }
103     } catch (Exception exception) {
104       throw new RuntimeException(exception);
105     } finally {
106       try {
107         if (yamlContent != null) {
108           yamlContent.close();
109         }
110       } catch (IOException ignore) {
111         //do nothing
112       }
113     }
114   }
115
116
117   /**
118    * Gets constructor.
119    *
120    * @param <T>      the type parameter
121    * @param typClass the t class
122    * @return the constructor
123    */
124   public <T> Constructor getConstructor(Class<T> typClass) {
125     return new StrictMapAppenderConstructor(typClass);
126   }
127
128   /**
129    * Gets property utils.
130    *
131    * @return the property utils
132    */
133   protected PropertyUtils getPropertyUtils() {
134     return new MyPropertyUtils();
135   }
136
137
138   /**
139    * Yaml to map map.
140    *
141    * @param yamlContent the yaml content
142    * @return the map
143    */
144   public Map<String, LinkedHashMap<String, Object>> yamlToMap(InputStream yamlContent) {
145     Yaml yaml = new Yaml();
146     return (Map<String, LinkedHashMap<String, Object>>) yaml.load(yamlContent);
147   }
148
149
150     /**
151      * Parse a YAML file to List
152      *
153      * @param yamlFileInputStream the YAML file input stream
154      * @return The YAML casted as a list
155      */
156     public static Optional<List<Object>> yamlToList(final InputStream yamlFileInputStream) {
157         List<Object> yamlList = null;
158         try {
159             yamlList = (List<Object>) read(yamlFileInputStream);
160         } catch (final ClassCastException ex) {
161             if (LOGGER.isWarnEnabled()) {
162                 LOGGER.warn("Could not parse YAML to List.", ex);
163             }
164         }
165         return Optional.ofNullable(yamlList);
166     }
167
168     /**
169      * Parse a YAML file to Object
170      *
171      * @param yamlFileInputStream the YAML file input stream
172      * @return The YAML Object
173      */
174     public static Object read(final InputStream yamlFileInputStream) {
175         final Yaml yaml = new Yaml();
176         return yaml.load(yamlFileInputStream);
177     }
178
179   /**
180    * Object to yaml string.
181    * @param obj the obj
182    * @return the string
183    */
184   public String objectToYaml(Object obj) {
185     DumperOptions options = new DumperOptions();
186     options.setPrettyFlow(true);
187     options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
188     Representer representer = new CustomRepresenter();
189     representer.addClassTag(obj.getClass(), Tag.MAP);
190     representer.setPropertyUtils(new MyPropertyUtils());
191
192     Yaml yaml = new Yaml(representer, options);
193     return yaml.dump(obj);
194   }
195
196   /**
197    * Is yaml file content valid boolean.
198    *
199    * @param yamlFullFileName the yaml full file name
200    * @return the boolean
201    */
202   public boolean isYamlFileContentValid(String yamlFullFileName) {
203     Yaml yaml = new Yaml();
204     try {
205       Object loadResult = yaml.load(yamlFullFileName);
206       return loadResult != null;
207     } catch (Exception exception) {
208       return false;
209     }
210   }
211
212
213   private class CustomRepresenter extends Representer {
214     @Override
215     protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
216       //remove the bean type from the output yaml (!! ...)
217       if (!classTags.containsKey(javaBean.getClass())) {
218         addClassTag(javaBean.getClass(), Tag.MAP);
219       }
220
221       return super.representJavaBean(properties, javaBean);
222     }
223
224     @Override
225     protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
226                                                   Object propertyValue, Tag customTag) {
227       if (propertyValue == null) {
228         return null;
229       } else {
230         NodeTuple defaultNode =
231             super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
232
233         return DEFAULT_STR.equals(property.getName())
234             ? new NodeTuple(representData(DEFAULT), defaultNode.getValueNode())
235             : defaultNode;
236       }
237     }
238   }
239
240
241   /**
242    * The type My property utils.
243    */
244   public class MyPropertyUtils extends PropertyUtils {
245     //Unsorted properties
246     @Override
247     protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bnAccess)
248         throws IntrospectionException {
249       return new LinkedHashSet<>(getPropertiesMap(type,
250           BeanAccess.FIELD).values());
251     }
252
253     @Override
254     public Property getProperty(Class<?> type, String name) throws IntrospectionException {
255       String updatedName = name;
256       if (DEFAULT.equals(updatedName)) {
257         updatedName = DEFAULT_STR;
258       }
259       return super.getProperty(type, updatedName);
260     }
261
262   }
263
264   /**
265    * The type Strict map appender constructor.
266    */
267   protected class StrictMapAppenderConstructor extends Constructor {
268
269     /**
270      * Instantiates a new Strict map appender constructor.
271      *
272      * @param theRoot the the root
273      */
274     public StrictMapAppenderConstructor(Class<?> theRoot) {
275       super(theRoot);
276     }
277
278     @Override
279     protected Map<Object, Object> createDefaultMap() {
280       final Map<Object, Object> delegate = super.createDefaultMap();
281       return new AbstractMap<Object, Object>() {
282         @Override
283         public Object put(Object key, Object value) {
284           if (delegate.containsKey(key)) {
285             throw new IllegalStateException("duplicate key: " + key);
286           }
287           return delegate.put(key, value);
288         }
289
290         @Override
291         public Set<Entry<Object, Object>> entrySet() {
292           return delegate.entrySet();
293         }
294       };
295     }
296
297     @Override
298     protected Map<Object, Object> constructMapping(MappingNode node) {
299       try {
300         return super.constructMapping(node);
301       } catch (IllegalStateException exception) {
302         throw new ParserException("while parsing MappingNode",
303             node.getStartMark(), exception.getMessage(),
304             node.getEndMark());
305       }
306     }
307   }
308 }