Remove java.desktop dependency
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / DatastoreContextIntrospector.java
index c0ed1294e4851c8119e4c72623db91b08b871e4e..c94f86989f4c080b700d21f4a6a630085cff0665 100644 (file)
@@ -7,39 +7,34 @@
  */
 package org.opendaylight.controller.cluster.datastore;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.primitives.Primitives;
-import java.beans.BeanInfo;
-import java.beans.ConstructorProperties;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.MethodDescriptor;
-import java.beans.PropertyDescriptor;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import javax.annotation.concurrent.GuardedBy;
+import java.util.function.Function;
+import javax.management.ConstructorParameters;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.text.WordUtils;
+import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.opendaylight.controller.cluster.datastore.DatastoreContext.Builder;
-import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.distributed.datastore.provider.rev140612.DataStoreProperties;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.distributed.datastore.provider.rev140612.DataStorePropertiesContainer;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.opendaylight.yangtools.yang.common.Uint8;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,12 +54,20 @@ public class DatastoreContextIntrospector {
 
     private static final Map<String, Method> BUILDER_SETTERS = new HashMap<>();
 
+    private static final ImmutableMap<Class<?>, Function<String, Object>> UINT_FACTORIES =
+            ImmutableMap.<Class<?>, Function<String, Object>>builder()
+            .put(Uint8.class, Uint8::valueOf)
+            .put(Uint16.class, Uint16::valueOf)
+            .put(Uint32.class, Uint32::valueOf)
+            .put(Uint64.class, Uint64::valueOf)
+            .build();
+
     static {
         try {
             introspectDatastoreContextBuilder();
             introspectDataStoreProperties();
             introspectPrimitiveTypes();
-        } catch (final IntrospectionException e) {
+        } catch (final IllegalArgumentException e) {
             LOG.error("Error initializing DatastoreContextIntrospector", e);
         }
     }
@@ -84,7 +87,7 @@ public class DatastoreContextIntrospector {
                 processPropertyType(primitive);
             } catch (final NoSuchMethodException e) {
                 // Ignore primitives that can't be constructed from a String, eg Character and Void.
-            } catch (SecurityException | IntrospectionException e) {
+            } catch (SecurityException | IllegalArgumentException e) {
                 LOG.error("Error introspect primitive type {}", primitive, e);
             }
         }
@@ -109,34 +112,37 @@ public class DatastoreContextIntrospector {
      * yang grouping. We use the bean Introspector to find the types of all the properties defined
      * in the interface (this is the type returned from the getter method). For each type, we find
      * the appropriate constructor that we will use.
+     *
+     * @throws IllegalArgumentException if failed to process yang-defined property
      */
-    private static void introspectDataStoreProperties() throws IntrospectionException {
-        final BeanInfo beanInfo = Introspector.getBeanInfo(DataStoreProperties.class);
-        for (final PropertyDescriptor desc: beanInfo.getPropertyDescriptors()) {
-            processDataStoreProperty(desc.getName(), desc.getPropertyType(), desc.getReadMethod());
+    private static void introspectDataStoreProperties() {
+        for (final Method method : DataStoreProperties.class.getDeclaredMethods()) {
+            final String propertyName = getPropertyName(method);
+            if (propertyName != null) {
+                processDataStoreProperty(propertyName, method.getReturnType(), method);
+            }
         }
+    }
 
-        // Getter methods that return Boolean and start with "is" instead of "get" aren't recognized as
-        // properties and thus aren't returned from getPropertyDescriptors. A getter starting with
-        // "is" is only supported if it returns primitive boolean. So we'll check for these via
-        // getMethodDescriptors.
-        for (final MethodDescriptor desc: beanInfo.getMethodDescriptors()) {
-            final String methodName = desc.getName();
-            if (Boolean.class.equals(desc.getMethod().getReturnType()) && methodName.startsWith("is")) {
-                final String propertyName = WordUtils.uncapitalize(methodName.substring(2));
-                processDataStoreProperty(propertyName, Boolean.class, desc.getMethod());
-            }
+    private static String getPropertyName(final Method method) {
+        final String methodName = method.getName();
+        if (Boolean.class.equals(method.getReturnType()) && methodName.startsWith("is")) {
+            return WordUtils.uncapitalize(methodName.substring(2));
+        } else if (methodName.startsWith("get")) {
+            return WordUtils.uncapitalize(methodName.substring(3));
         }
+        return null;
     }
 
     /**
      * Processes a property defined on the DataStoreProperties interface.
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private static void processDataStoreProperty(final String name, final Class<?> propertyType, Method readMethod) {
-        Preconditions.checkArgument(BUILDER_SETTERS.containsKey(name), String.format(
+    private static void processDataStoreProperty(final String name, final Class<?> propertyType,
+            final Method readMethod) {
+        checkArgument(BUILDER_SETTERS.containsKey(name),
                 "DataStoreProperties property \"%s\" does not have corresponding setter in DatastoreContext.Builder",
-                name));
+                name);
         try {
             processPropertyType(propertyType);
             DATA_STORE_PROP_INFO.put(name, new SimpleImmutableEntry<>(propertyType, readMethod));
@@ -148,9 +154,11 @@ public class DatastoreContextIntrospector {
     /**
      * Finds the appropriate constructor for the specified type that we will use to construct
      * instances.
+     *
+     * @throws IllegalArgumentException if yang-defined type has no property, annotated by ConstructorParameters
      */
     private static void processPropertyType(final Class<?> propertyType)
-            throws NoSuchMethodException, SecurityException, IntrospectionException {
+            throws NoSuchMethodException, SecurityException {
         final Class<?> wrappedType = Primitives.wrap(propertyType);
         if (CONSTRUCTORS.containsKey(wrappedType)) {
             return;
@@ -167,9 +175,9 @@ public class DatastoreContextIntrospector {
             // validation (eg range checking). The yang-generated types have a couple single-argument
             // constructors but the one we want has the bean ConstructorProperties annotation.
             for (final Constructor<?> ctor: propertyType.getConstructors()) {
-                final ConstructorProperties ctorPropsAnnotation = ctor.getAnnotation(ConstructorProperties.class);
-                if (ctor.getParameterTypes().length == 1 && ctorPropsAnnotation != null) {
-                    findYangTypeGetter(propertyType, ctorPropsAnnotation.value()[0]);
+                final ConstructorParameters ctorParAnnotation = ctor.getAnnotation(ConstructorParameters.class);
+                if (ctor.getParameterCount() == 1 && ctorParAnnotation != null) {
+                    findYangTypeGetter(propertyType, ctorParAnnotation.value()[0]);
                     CONSTRUCTORS.put(propertyType, ctor);
                     break;
                 }
@@ -179,17 +187,19 @@ public class DatastoreContextIntrospector {
 
     /**
      * Finds the getter method on a yang-generated type for the specified property name.
+     *
+     * @throws IllegalArgumentException if passed type has no passed property
      */
-    private static void findYangTypeGetter(final Class<?> type, final String propertyName)
-            throws IntrospectionException {
-        for (final PropertyDescriptor desc: Introspector.getBeanInfo(type).getPropertyDescriptors()) {
-            if (desc.getName().equals(propertyName)) {
-                YANG_TYPE_GETTERS.put(type, desc.getReadMethod());
+    private static void findYangTypeGetter(final Class<?> type, final String propertyName) {
+        for (Method method : type.getDeclaredMethods()) {
+            final String property = getPropertyName(method);
+            if (property != null && property.equals(propertyName)) {
+                YANG_TYPE_GETTERS.put(type, method);
                 return;
             }
         }
 
-        throw new IntrospectionException(String.format(
+        throw new IllegalArgumentException(String.format(
                 "Getter method for constructor property %s not found for YANG type %s",
                 propertyName, type));
     }
@@ -200,12 +210,7 @@ public class DatastoreContextIntrospector {
     private Map<String, Object> currentProperties;
 
     public DatastoreContextIntrospector(final DatastoreContext context,
-            final BindingNormalizedNodeSerializer bindingSerializer) {
-        final QName qname = BindingReflections.findQName(DataStorePropertiesContainer.class);
-        final DataStorePropertiesContainer defaultPropsContainer = (DataStorePropertiesContainer)
-                bindingSerializer.fromNormalizedNode(bindingSerializer.toYangInstanceIdentifier(
-                        InstanceIdentifier.builder(DataStorePropertiesContainer.class).build()),
-                ImmutableNodes.containerNode(qname)).getValue();
+            final DataStorePropertiesContainer defaultPropsContainer) {
 
         final Builder builder = DatastoreContext.newBuilderFrom(context);
         for (Entry<String, Entry<Class<?>, Method>> entry: DATA_STORE_PROP_INFO.entrySet()) {
@@ -311,8 +316,8 @@ public class DatastoreContextIntrospector {
         // Sort the property keys by putting the names prefixed with the data store type last. This
         // is done so data store specific settings are applied after global settings.
         final ArrayList<String> keys = new ArrayList<>(inKeys);
-        Collections.sort(keys, (key1, key2) -> key1.startsWith(dataStoreTypePrefix) ? 1 :
-                   key2.startsWith(dataStoreTypePrefix) ? -1 : key1.compareTo(key2));
+        keys.sort((key1, key2) -> key1.startsWith(dataStoreTypePrefix) ? 1 :
+            key2.startsWith(dataStoreTypePrefix) ? -1 : key1.compareTo(key2));
         return keys;
     }
 
@@ -392,13 +397,18 @@ public class DatastoreContextIntrospector {
         }
 
         final Constructor<?> ctor = CONSTRUCTORS.get(toType);
-
-        LOG.trace("Found {}", ctor);
-
         if (ctor == null) {
+            if (fromValue instanceof String) {
+                final Function<String, Object> factory = UINT_FACTORIES.get(toType);
+                if (factory != null) {
+                    return factory.apply((String) fromValue);
+                }
+            }
+
             throw new IllegalArgumentException(String.format("Constructor not found for type %s", toType));
         }
 
+        LOG.trace("Found {}", ctor);
         Object value = fromValue;
 
         // Once we find a constructor that takes the original type as an argument, we're done recursing.