2 * ============LICENSE_START=======================================================
3 * ONAP : ccsdk features
4 * ================================================================================
5 * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools;
24 import com.fasterxml.jackson.databind.DeserializationContext;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.Optional;
32 import java.util.concurrent.ConcurrentHashMap;
33 import javax.annotation.Nullable;
34 import org.opendaylight.yangtools.concepts.Builder;
35 import org.osgi.framework.Bundle;
36 import org.osgi.framework.BundleContext;
37 import org.osgi.framework.FrameworkUtil;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 public class YangToolsMapperHelper {
43 private static final Logger LOG = LoggerFactory.getLogger(YangToolsMapperHelper.class);
44 private static final String TYPEOBJECT_INSTANCE_METHOD = "getDefaultInstance";
45 private static final String BUILDER = "Builder";
47 private static BundleContext context = getBundleContext();
48 private static ConcurrentHashMap<String, Class<?>> cache = new ConcurrentHashMap<>();
50 private YangToolsMapperHelper() {
54 public static Class<?> findClass(String name) throws ClassNotFoundException {
57 Class<?> res = cache.get(name);
61 //Try first in actual bundle
63 return loadClass(null, name);
64 } catch (ClassNotFoundException e) {
65 // No problem, this bundle doesn't have the class
67 // Try to find in other bundles
68 if (context != null) {
70 for (Bundle b : context.getBundles()) {
72 return loadClass(b, name);
73 } catch (ClassNotFoundException e) {
74 // No problem, this bundle doesn't have the class
78 // really not found in any bundle
79 throw new ClassNotFoundException("Can not find class '"+name+"'");
82 private static Class<?> loadClass(Bundle b, String name) throws ClassNotFoundException {
83 Class<?> res = b == null ? Class.forName(name) : b.loadClass(name);
89 * Verify if builder is available
91 * @throws ClassNotFoundException
93 public static Class<?> assertBuilderClass(Class<?> clazz) throws ClassNotFoundException {
94 return getBuilderClass(getBuilderClassName(clazz));
97 public static Class<?> getBuilderClass(String name) throws ClassNotFoundException {
98 return findClass(name);
101 public static Class<?> getBuilderClass(Class<?> clazz) throws ClassNotFoundException {
102 return findClass(getBuilderClassName(clazz));
106 * Create name of builder class
110 * @return builders class name
111 * @throws ClassNotFoundException
113 public static String getBuilderClassName(Class<?> clazz) {
114 return clazz.getName() + BUILDER;
117 @SuppressWarnings("unchecked")
118 public static <B extends Builder<?>> Class<B> findBuilderClass(DeserializationContext ctxt, Class<?> clazz) throws ClassNotFoundException {
119 return (Class<B>) findClass(getBuilderClassName(clazz));
122 public static <B extends Builder<?>> Optional<Class<B>> findBuilderClassOptional(DeserializationContext ctxt, Class<?> clazz) {
124 return Optional.of(findBuilderClass(ctxt, clazz));
125 } catch (ClassNotFoundException e) {
126 return Optional.empty();
130 public static boolean hasClassDeclaredMethod(Class<?> clazz, String name) {
131 Method[] methods = clazz.getDeclaredMethods();
132 for (Method m : methods) {
133 if (m.getName().equals(name)) {
140 @SuppressWarnings("unchecked")
141 public static <T> Optional<T> getInstanceByConstructor(Class<?> clazz, String arg) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
142 List<Class<?>> ctypes = getConstructorParameterTypes(clazz, String.class);
143 Optional<Object> oObj;
144 for (Class<?> ctype : ctypes) {
145 if (ctype.equals(String.class)) {
146 return Optional.of((T) clazz.getConstructor(ctype).newInstance(arg));
147 } else if ((oObj = getDefaultInstance(ctype, arg)).isPresent()) {
148 return Optional.of((T) clazz.getConstructor(ctype).newInstance(oObj.get()));
150 // TODO: recursive instantiation down to string constructor or
151 // getDefaultInstance method
152 LOG.debug("Not implemented arg:'{}' class:'{}'", arg, clazz);
155 return Optional.empty();
158 @SuppressWarnings("unchecked")
159 public static <T> Optional<T> getDefaultInstance(@Nullable Class<?> clazz, String arg)
160 throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
161 InvocationTargetException {
162 LOG.trace("arg:'{}' clazz '{}'", arg, clazz.getName());
164 Method[] methods = clazz.getDeclaredMethods();
165 for (Method m : methods) {
166 //TODO Verify argument type to avoid exception
167 if (m.getName().equals(TYPEOBJECT_INSTANCE_METHOD)) {
168 Method method = clazz.getDeclaredMethod(TYPEOBJECT_INSTANCE_METHOD, String.class);
169 LOG.trace("Invoke {} available {}",TYPEOBJECT_INSTANCE_METHOD, method != null);
170 return Optional.of((T) method.invoke(null, arg));
174 return Optional.empty();
177 public static <T> Optional<T> getDefaultInstance(Optional<Class<T>> optionalClazz, String arg)
178 throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
179 InvocationTargetException {
180 if (optionalClazz.isPresent()) {
181 return getDefaultInstance(optionalClazz.get(), arg);
183 return Optional.empty();
186 public static List<Class<?>> getConstructorParameterTypes(Class<?> clazz, Class<?> prefer) {
188 Constructor<?>[] constructors = clazz.getConstructors();
189 List<Class<?>> res = new ArrayList<>();
190 for (Constructor<?> c : constructors) {
191 Class<?>[] ptypes = c.getParameterTypes();
192 if (ptypes.length == 1) {
196 if (prefer != null && ptypes.length == 1 && ptypes[0].equals(prefer)) {
197 return Arrays.asList(prefer);
203 public static boolean implementsInterface(Class<?> clz, Class<?> ifToImplement) {
204 Class<?>[] ifs = clz.getInterfaces();
205 for (Class<?> iff : ifs) {
206 if (iff.equals(ifToImplement)) {
214 * Provide mapping of string to attribute names, generated by yang-tools. "netconf-id" converted to "_netconfId"
216 * @param name with attribute name, not null or empty
217 * @return converted string or null if name was empty or null
219 public @Nullable static String toCamelCaseAttributeName(final String name) {
220 if (name == null || name.isEmpty())
223 final StringBuilder ret = new StringBuilder(name.length());
224 if (!name.startsWith("_"))
227 for (final String word : name.split("-")) {
228 if (!word.isEmpty()) {
230 ret.append(Character.toLowerCase(word.charAt(0)));
232 ret.append(Character.toUpperCase(word.charAt(0)));
234 ret.append(word.substring(1));
237 return ret.toString();
240 private static BundleContext getBundleContext() {
241 Bundle bundle = FrameworkUtil.getBundle(YangToolsMapperHelper.class);
242 return bundle != null ? bundle.getBundleContext() : null;