cd19ff9ec0881a7d2470e22c9a814adc8cc07fd4
[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 org.yaml.snakeyaml.DumperOptions;
20 import org.yaml.snakeyaml.TypeDescription;
21 import org.yaml.snakeyaml.Yaml;
22 import org.yaml.snakeyaml.constructor.Constructor;
23 import org.yaml.snakeyaml.introspector.BeanAccess;
24 import org.yaml.snakeyaml.introspector.Property;
25 import org.yaml.snakeyaml.introspector.PropertyUtils;
26 import org.yaml.snakeyaml.nodes.MappingNode;
27 import org.yaml.snakeyaml.nodes.NodeTuple;
28 import org.yaml.snakeyaml.nodes.Tag;
29 import org.yaml.snakeyaml.parser.ParserException;
30 import org.yaml.snakeyaml.representer.Representer;
31
32 import java.beans.IntrospectionException;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.util.*;
36
37 /**
38  * The type Yaml util.
39  */
40 @SuppressWarnings("unchecked")
41 public class YamlUtil {
42
43   private static final String DEFAULT = "default";
44   private static final String DEFAULT_STR = "_default";
45
46   /**
47    * Yaml to object t.
48    *
49    * @param <T>         the type parameter
50    * @param yamlContent the yaml content
51    * @param typClass    the t class
52    * @return the t
53    */
54   public <T> T yamlToObject(String yamlContent, Class<T> typClass) {
55     Constructor constructor = getConstructor(typClass);
56     constructor.setPropertyUtils(getPropertyUtils());
57     TypeDescription yamlFileDescription = new TypeDescription(typClass);
58     constructor.addTypeDescription(yamlFileDescription);
59     Yaml yaml = new Yaml(constructor);
60     T yamlObj = (T) yaml.load(yamlContent);
61     //noinspection ResultOfMethodCallIgnored
62     yamlObj.toString();
63     return yamlObj;
64   }
65
66   public InputStream loadYamlFileIs(String yamlFullFileName) {
67     return YamlUtil.class.getResourceAsStream(yamlFullFileName);
68   }
69
70   /**
71    * Yaml to object t.
72    *
73    * @param <T>         the type parameter
74    * @param yamlContent the yaml content
75    * @param typClass    the t class
76    * @return the t
77    */
78   public <T> T yamlToObject(InputStream yamlContent, Class<T> typClass) {
79     try {
80       Constructor constructor = getConstructor(typClass);
81       constructor.setPropertyUtils(getPropertyUtils());
82       TypeDescription yamlFileDescription = new TypeDescription(typClass);
83       constructor.addTypeDescription(yamlFileDescription);
84       Yaml yaml = new Yaml(constructor);
85       T yamlObj = (T) yaml.load(yamlContent);
86       if (yamlObj != null) {
87         //noinspection ResultOfMethodCallIgnored
88         yamlObj.toString();
89         return yamlObj;
90       } else {
91         throw new RuntimeException();
92       }
93     } catch (Exception exception) {
94       throw new RuntimeException(exception);
95     } finally {
96       try {
97         if (yamlContent != null) {
98           yamlContent.close();
99         }
100       } catch (IOException ignore) {
101         //do nothing
102       }
103     }
104   }
105
106
107   /**
108    * Gets constructor.
109    *
110    * @param <T>      the type parameter
111    * @param typClass the t class
112    * @return the constructor
113    */
114   public <T> Constructor getConstructor(Class<T> typClass) {
115     return new StrictMapAppenderConstructor(typClass);
116   }
117
118   /**
119    * Gets property utils.
120    *
121    * @return the property utils
122    */
123   protected PropertyUtils getPropertyUtils() {
124     return new MyPropertyUtils();
125   }
126
127
128   /**
129    * Yaml to map map.
130    *
131    * @param yamlContent the yaml content
132    * @return the map
133    */
134   public Map<String, LinkedHashMap<String, Object>> yamlToMap(InputStream yamlContent) {
135     Yaml yaml = new Yaml();
136     return (Map<String, LinkedHashMap<String, Object>>) yaml.load(yamlContent);
137   }
138
139   /**
140    * Object to yaml string.
141    * @param obj the obj
142    * @return the string
143    */
144   public String objectToYaml(Object obj) {
145     DumperOptions options = new DumperOptions();
146     options.setPrettyFlow(true);
147     options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
148     Representer representer = new CustomRepresenter();
149     representer.addClassTag(obj.getClass(), Tag.MAP);
150     representer.setPropertyUtils(new MyPropertyUtils());
151
152     Yaml yaml = new Yaml(representer, options);
153     return yaml.dump(obj);
154   }
155
156   /**
157    * Is yaml file content valid boolean.
158    *
159    * @param yamlFullFileName the yaml full file name
160    * @return the boolean
161    */
162   public boolean isYamlFileContentValid(String yamlFullFileName) {
163     Yaml yaml = new Yaml();
164     try {
165       Object loadResult = yaml.load(yamlFullFileName);
166       return loadResult != null;
167     } catch (Exception exception) {
168       return false;
169     }
170   }
171
172
173   private class CustomRepresenter extends Representer {
174     @Override
175     protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
176       //remove the bean type from the output yaml (!! ...)
177       if (!classTags.containsKey(javaBean.getClass())) {
178         addClassTag(javaBean.getClass(), Tag.MAP);
179       }
180
181       return super.representJavaBean(properties, javaBean);
182     }
183
184     @Override
185     protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
186                                                   Object propertyValue, Tag customTag) {
187       if (propertyValue == null) {
188         return null;
189       } else {
190         NodeTuple defaultNode =
191             super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
192
193         return DEFAULT_STR.equals(property.getName())
194             ? new NodeTuple(representData(DEFAULT), defaultNode.getValueNode())
195             : defaultNode;
196       }
197     }
198   }
199
200
201   /**
202    * The type My property utils.
203    */
204   public class MyPropertyUtils extends PropertyUtils {
205     //Unsorted properties
206     @Override
207     protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bnAccess)
208         throws IntrospectionException {
209       return new LinkedHashSet<>(getPropertiesMap(type,
210           BeanAccess.FIELD).values());
211     }
212
213     @Override
214     public Property getProperty(Class<?> type, String name) throws IntrospectionException {
215       String updatedName = name;
216       if (DEFAULT.equals(updatedName)) {
217         updatedName = DEFAULT_STR;
218       }
219       return super.getProperty(type, updatedName);
220     }
221
222   }
223
224   /**
225    * The type Strict map appender constructor.
226    */
227   protected class StrictMapAppenderConstructor extends Constructor {
228
229     /**
230      * Instantiates a new Strict map appender constructor.
231      *
232      * @param theRoot the the root
233      */
234     public StrictMapAppenderConstructor(Class<?> theRoot) {
235       super(theRoot);
236     }
237
238     @Override
239     protected Map<Object, Object> createDefaultMap() {
240       final Map<Object, Object> delegate = super.createDefaultMap();
241       return new AbstractMap<Object, Object>() {
242         @Override
243         public Object put(Object key, Object value) {
244           if (delegate.containsKey(key)) {
245             throw new IllegalStateException("duplicate key: " + key);
246           }
247           return delegate.put(key, value);
248         }
249
250         @Override
251         public Set<Entry<Object, Object>> entrySet() {
252           return delegate.entrySet();
253         }
254       };
255     }
256
257     @Override
258     protected Map<Object, Object> constructMapping(MappingNode node) {
259       try {
260         return super.constructMapping(node);
261       } catch (IllegalStateException exception) {
262         throw new ParserException("while parsing MappingNode",
263             node.getStartMark(), exception.getMessage(),
264             node.getEndMark());
265       }
266     }
267   }
268 }