Merge "Reformat sdnr devicemanager to ONAP code style"
[ccsdk/features.git] / sdnr / wt / data-provider / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / dataprovider / yangtools / YangToolsMapper.java
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.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
51
52 /**
53  * YangToolsMapper is a specific Jackson mapper configuration for opendaylight yangtools serialization or
54  * deserialization of DataObject to/from JSON TODO ChoiceIn and Credentials deserialization only for
55  * LoginPasswordBuilder
56  */
57 public class YangToolsMapper extends ObjectMapper {
58
59     private final Logger LOG = LoggerFactory.getLogger(YangToolsMapper.class);
60     private static final long serialVersionUID = 1L;
61     private static BundleContext context;
62
63     public YangToolsMapper() {
64         super();
65         configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
66         setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
67         setSerializationInclusion(Include.NON_NULL);
68         setAnnotationIntrospector(new YangToolsBuilderAnnotationIntrospector());
69         SimpleModule dateAndTimeSerializerModule = new SimpleModule();
70         dateAndTimeSerializerModule.addSerializer(DateAndTime.class, new CustomDateAndTimeSerializer());
71         registerModule(dateAndTimeSerializerModule);
72         Bundle bundle = FrameworkUtil.getBundle(YangToolsMapper.class);
73         context = bundle != null ? bundle.getBundleContext() : null;
74     }
75
76     @Override
77     public String writeValueAsString(Object value) throws JsonProcessingException {
78         // TODO Auto-generated method stub
79         return super.writeValueAsString(value);
80     }
81
82     /**
83      * Get Builder object for yang tools interface.
84      * 
85      * @param <T> yang-tools base datatype
86      * @param clazz class with interface.
87      * @return builder for interface or null if not existing
88      */
89     @SuppressWarnings("unchecked")
90     public @Nullable <T extends DataObject> Builder<T> getBuilder(Class<T> clazz) {
91         String builder = clazz.getName() + "Builder";
92         try {
93             Class<?> clazzBuilder = findClass(builder);
94             return (Builder<T>) clazzBuilder.newInstance();
95         } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
96             LOG.debug("Problem ", e);
97             return null;
98         }
99     }
100
101     /**
102      * Callback for handling mapping failures.
103      * 
104      * @return
105      */
106     public int getMappingFailures() {
107         return 0;
108     }
109
110     /**
111      * Provide mapping of string to attribute names, generated by yang-tools. "netconf-id" converted to "_netconfId"
112      * 
113      * @param name with attribute name, not null or empty
114      * @return converted string or null if name was empty or null
115      */
116     public @Nullable static String toCamelCaseAttributeName(final String name) {
117         if (name == null || name.isEmpty())
118             return null;
119
120         final StringBuilder ret = new StringBuilder(name.length());
121         if (!name.startsWith("_"))
122             ret.append('_');
123         int start = 0;
124         for (final String word : name.split("-")) {
125             if (!word.isEmpty()) {
126                 if (start++ == 0) {
127                     ret.append(Character.toLowerCase(word.charAt(0)));
128                 } else {
129                     ret.append(Character.toUpperCase(word.charAt(0)));
130                 }
131                 ret.append(word.substring(1));
132             }
133         }
134         return ret.toString();
135     }
136
137     /**
138      * Adapted Builder callbacks
139      */
140     private static class YangToolsBuilderAnnotationIntrospector extends JacksonAnnotationIntrospector {
141         private static final long serialVersionUID = 1L;
142
143         @Override
144         public Class<?> findPOJOBuilder(AnnotatedClass ac) {
145             try {
146                 String builder = null;
147                 if (ac.getRawType().equals(Credentials.class)) {
148                     builder =
149                             "org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder";
150                     //System.out.println(DataContainer.class.isAssignableFrom(ac.getRawType()));
151                     //System.out.println(ChoiceIn.class.isAssignableFrom(ac.getRawType()));
152
153                 } else if (ac.getRawType().equals(DateAndTime.class)) {
154                     builder = DateAndTimeBuilder.class.getName();
155                 }
156
157                 else {
158                     if (ac.getRawType().isInterface()) {
159                         builder = ac.getName() + "Builder";
160                     }
161                 }
162                 if (builder != null) {
163                     //System.out.println("XX1: "+ac.getRawType());
164                     //System.out.println("XX2: "+builder);
165                     //Class<?> innerBuilder = Class.forName(builder);
166                     Class<?> innerBuilder = findClass(builder);
167                     //System.out.println("Builder found: "+ innerBuilder);
168                     return innerBuilder;
169                 }
170             } catch (ClassNotFoundException e) {
171                 // No problem .. try next
172             }
173             return super.findPOJOBuilder(ac);
174         }
175
176         @Override
177         public Value findPOJOBuilderConfig(AnnotatedClass ac) {
178             if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
179                 return super.findPOJOBuilderConfig(ac);
180             }
181             return new JsonPOJOBuilder.Value("build", "set");
182         }
183     }
184
185     private static Class<?> findClass(String name) throws ClassNotFoundException {
186         // Try to find in other bundles
187         if (context != null) {
188             //OSGi environment
189             for (Bundle b : context.getBundles()) {
190                 try {
191                     return b.loadClass(name);
192                 } catch (ClassNotFoundException e) {
193                     // No problem, this bundle doesn't have the class
194                 }
195             }
196             throw new ClassNotFoundException("Can not find Class in OSGi context.");
197         } else {
198             return Class.forName(name);
199         }
200         // not found in any bundle
201     }
202
203     public static class DateAndTimeBuilder {
204
205         private final String _value;
206
207         public DateAndTimeBuilder(String v) {
208             this._value = v;
209         }
210
211         public DateAndTime build() {
212             return new DateAndTime(_value);
213         }
214
215     }
216     public static class CustomDateAndTimeSerializer extends StdSerializer<DateAndTime> {
217
218         /**
219          * 
220          */
221         private static final long serialVersionUID = 1L;
222
223         public CustomDateAndTimeSerializer() {
224             this(null);
225         }
226
227         protected CustomDateAndTimeSerializer(Class<DateAndTime> t) {
228             super(t);
229         }
230
231         @Override
232         public void serialize(DateAndTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
233             gen.writeString(value.getValue());
234         }
235
236     }
237 }