ce67c39dd9d7b2c6496b02ffa46bbf9c2768129a
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk features
4  * ================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
6  * All rights 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.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools;
23
24 import java.io.IOException;
25 import javax.annotation.Nullable;
26
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
28 import org.opendaylight.yangtools.concepts.Builder;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.osgi.framework.Bundle;
31 import org.osgi.framework.BundleContext;
32 import org.osgi.framework.FrameworkUtil;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import com.fasterxml.jackson.annotation.JsonInclude.Include;
37 import com.fasterxml.jackson.core.JsonGenerator;
38 import com.fasterxml.jackson.core.JsonProcessingException;
39 import com.fasterxml.jackson.databind.DeserializationFeature;
40 import com.fasterxml.jackson.databind.ObjectMapper;
41 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
42 import com.fasterxml.jackson.databind.SerializerProvider;
43 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
44 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder.Value;
45 import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
46 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
47 import com.fasterxml.jackson.databind.module.SimpleModule;
48 import com.fasterxml.jackson.databind.ser.std.StdSerializer;
49
50 import org.eclipse.jdt.annotation.NonNull;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
52
53 /**
54  * YangToolsMapper is a specific Jackson mapper configuration for opendaylight yangtools serialization or
55  * deserialization of DataObject to/from JSON TODO ChoiceIn and Credentials deserialization only for
56  * LoginPasswordBuilder
57  */
58 public class YangToolsMapper2<T extends DataObject> extends ObjectMapper {
59
60     private final Logger LOG = LoggerFactory.getLogger(YangToolsMapper2.class);
61     private static final long serialVersionUID = 1L;
62     private static String ENTITY = "Entity";
63     private static String BUILDER = "Builder";
64
65     private @Nullable Class<T> clazz;
66     private @Nullable Class<? extends Builder<? extends T>> builderClazz;
67
68     private BundleContext context;
69
70     public <X extends T, B extends Builder<X>> YangToolsMapper2(Class<T> clazz, Class<B> builderClazz)
71             throws ClassNotFoundException {
72         super();
73         configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
74         setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
75         setSerializationInclusion(Include.NON_NULL);
76         setAnnotationIntrospector(new YangToolsBuilderAnnotationIntrospector());
77         SimpleModule dateAndTimeSerializerModule = new SimpleModule();
78         dateAndTimeSerializerModule.addSerializer(DateAndTime.class, new CustomDateAndTimeSerializer());
79         registerModule(dateAndTimeSerializerModule);
80         Bundle bundle = FrameworkUtil.getBundle(YangToolsMapper2.class);
81
82         this.clazz = clazz;
83         this.builderClazz = builderClazz != null ? builderClazz : getBuilderClass(getBuilderClassName(clazz));
84         context = bundle != null ? bundle.getBundleContext() : null;
85     }
86
87     public YangToolsMapper2() throws ClassNotFoundException {
88         this(null, null);
89     }
90
91
92     @Override
93     public String writeValueAsString(Object value) throws JsonProcessingException {
94         return super.writeValueAsString(value);
95     }
96
97     /**
98      * Get Builder object for yang tools interface.
99      * 
100      * @param <T> yang-tools base datatype
101      * @param clazz class with interface.
102      * @return builder for interface or null if not existing
103      */
104     @SuppressWarnings("unchecked")
105     public @Nullable <T extends DataObject> Builder<T> getBuilder(Class<T> clazz) {
106         try {
107             //Class<?> clazzBuilder = getBuilderClass(getBuilderClassName(clazz));
108             return (Builder<T>) builderClazz.newInstance();
109         } catch (InstantiationException | IllegalAccessException e) {
110             LOG.debug("Problem ", e);
111             return null;
112         }
113     }
114
115     /**
116      * Callback for handling mapping failures.
117      * 
118      * @return
119      */
120     public int getMappingFailures() {
121         return 0;
122     }
123
124     /**
125      * Provide mapping of string to attribute names, generated by yang-tools. "netconf-id" converted to "_netconfId"
126      * 
127      * @param name with attribute name, not null or empty
128      * @return converted string or null if name was empty or null
129      */
130     public @Nullable static String toCamelCaseAttributeName(final String name) {
131         if (name == null || name.isEmpty())
132             return null;
133
134         final StringBuilder ret = new StringBuilder(name.length());
135         if (!name.startsWith("_"))
136             ret.append('_');
137         int start = 0;
138         for (final String word : name.split("-")) {
139             if (!word.isEmpty()) {
140                 if (start++ == 0) {
141                     ret.append(Character.toLowerCase(word.charAt(0)));
142                 } else {
143                     ret.append(Character.toUpperCase(word.charAt(0)));
144                 }
145                 ret.append(word.substring(1));
146             }
147         }
148         return ret.toString();
149     }
150
151     /**
152      * Verify if builder is available
153      * 
154      * @throws ClassNotFoundException
155      **/
156     public Class<?> assertBuilderClass(Class<?> clazz) throws ClassNotFoundException {
157         return getBuilderClass(getBuilderClassName(clazz));
158     }
159
160     // --- Private functions
161
162     /**
163      * Create name of builder class
164      * 
165      * @param <T>
166      * @param clazz
167      * @return builders class name
168      * @throws ClassNotFoundException
169      */
170     private static String getBuilderClassName(Class<?> clazz) {
171         return clazz.getName() + BUILDER;
172         //              String clazzName = clazz.getName();
173         //              if (clazzName.endsWith(ENTITY)) {
174         //                      return clazzName.replace(ENTITY, BUILDER);
175         //              } else {
176         //                      return clazzName + BUILDER;
177         //              }
178     }
179
180     /**
181      * Search builder in context
182      * 
183      * @param name
184      * @return
185      * @throws ClassNotFoundException
186      */
187     @SuppressWarnings("unchecked")
188     private <X extends T, B extends Builder<X>> Class<B> getBuilderClass(String name) throws ClassNotFoundException {
189         // Try to find in other bundles
190         if (context != null) {
191             //OSGi environment
192             for (Bundle b : context.getBundles()) {
193                 try {
194                     return (Class<B>) b.loadClass(name);
195                 } catch (ClassNotFoundException e) {
196                     // No problem, this bundle doesn't have the class
197                 }
198             }
199             throw new ClassNotFoundException("Can not find Class in OSGi context.");
200         } else {
201             return (Class<B>) Class.forName(name);
202         }
203         // not found in any bundle
204     }
205
206     // --- Classes
207
208     /**
209      * Adapted Builder callbacks
210      */
211     private class YangToolsBuilderAnnotationIntrospector extends JacksonAnnotationIntrospector {
212         private static final long serialVersionUID = 1L;
213
214         @Override
215         public Class<?> findPOJOBuilder(AnnotatedClass ac) {
216
217             if (ac.getRawType().equals(Credentials.class)) {
218                 return org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder.class;
219
220             } else if (ac.getRawType().equals(DateAndTime.class)) {
221                 return DateAndTimeBuilder.class;
222
223             } else if (ac.getRawType().equals(clazz)) {
224                 return builderClazz;
225             }
226
227             if (ac.getRawType().isInterface()) {
228                 String builder = getBuilderClassName(ac.getRawType());
229                 try {
230                     Class<?> innerBuilder = getBuilderClass(builder);
231                     return innerBuilder;
232                 } catch (ClassNotFoundException e) {
233                     // No problem .. try next
234                 }
235             }
236             return super.findPOJOBuilder(ac);
237         }
238
239         @Override
240         public Value findPOJOBuilderConfig(AnnotatedClass ac) {
241             if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
242                 return super.findPOJOBuilderConfig(ac);
243             }
244             return new JsonPOJOBuilder.Value("build", "set");
245         }
246     }
247
248     public static class DateAndTimeBuilder {
249
250         private final String _value;
251
252         public DateAndTimeBuilder(String v) {
253             this._value = v;
254         }
255
256         public DateAndTime build() {
257             return new DateAndTime(_value);
258         }
259
260     }
261     public static class CustomDateAndTimeSerializer extends StdSerializer<@NonNull DateAndTime> {
262
263         private static final long serialVersionUID = 1L;
264
265         public CustomDateAndTimeSerializer() {
266             this(null);
267         }
268
269         protected CustomDateAndTimeSerializer(Class<DateAndTime> t) {
270             super(t);
271         }
272
273         @Override
274         public void serialize(DateAndTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
275             gen.writeString(value.getValue());
276         }
277
278     }
279 }