Fix FinalModifierException due to BindingToNormalizedNodeCodec final 74/44274/2
authorTom Pantelis <tpanteli@brocade.com>
Thu, 18 Aug 2016 14:31:00 +0000 (10:31 -0400)
committerTom Pantelis <tpanteli@brocade.com>
Thu, 18 Aug 2016 19:22:07 +0000 (19:22 +0000)
The BindingToNormalizedNodeCodec class is final which prevents blueprint from
being able to create a proxy instance when advertising as a service. This is
is OK as it will use the actual instance but it logs an exception:

2016-08-11 23:03:18,215 | INFO  | rint Extender: 2 | ServiceRecipe
| 15 - org.apache.aries.blueprint.core - 1.6.1 | Unable to create a
proxy object for the service .component-2 defined in bundle
org.opendaylight.controller.sal-binding-broker-impl/1.5.0.SNAPSHOT with
id. Returning the original object instead.
org.apache.aries.proxy.FinalModifierException: The class
org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec
is final.
at
org.apache.aries.proxy.impl.gen.ProxySubclassGenerator.scanForFinalModifiers(ProxySubclassGenerator.java:330)[12:org.apache.aries.proxy.impl:1.0.5]

Although it's logged at INFO level we should avoid it.

Changing BindingToNormalizedNodeCodec to non-final fixes the exception however it causes
an error when it tries to create the proxy b/c some methods are final. To avoid this, weneed to avoid the proxy creation altogether so I added a method to
BindingToNormalizedNodeCodecFactory to advertise the OSGi service instead of using
the blueprint <service> element.

Note: it's not good practice to advertise a service with the actual class but it's
needed with BindingToNormalizedNodeCodec for backwards compatibility with CSS modules
that inject the BindingToNormalizedNodeCodec instance and not its interfaces. The
BindingToNormalizedNodeCodec CSS service identity is deprecated and will/should go away in the future.

Change-Id: I96b6cb8b030de39808de17142d79f8bbd09bf735
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodecFactory.java
opendaylight/md-sal/sal-binding-broker/src/main/resources/org/opendaylight/blueprint/binding-broker.xml

index bb123a1..f1ae5cb 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
@@ -14,6 +16,8 @@ import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeC
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
 
 /**
  * Factory class for creating and initializing the BindingToNormalizedNodeCodec instances.
@@ -62,4 +66,27 @@ public class BindingToNormalizedNodeCodecFactory {
             SchemaService schemaService) {
         return schemaService.registerSchemaContextListener(instance);
     }
+
+    /**
+     * This method is called via blueprint to register a BindingToNormalizedNodeCodec instance with the OSGI
+     * service registry. This is done in code instead of directly via blueprint because the BindingToNormalizedNodeCodec
+     * instance must be advertised with the actual class for backwards compatibility with CSS modules and blueprint
+     * will try to create a proxy wrapper which is problematic with BindingToNormalizedNodeCodec because it's final
+     * and has final methods which can't be proxied.
+     *
+     * @param instance the BindingToNormalizedNodeCodec instance
+     * @param bundleContext the BundleContext
+     * @return ServiceRegistration instance
+     */
+    public static ServiceRegistration<BindingToNormalizedNodeCodec> registerOSGiService(BindingToNormalizedNodeCodec instance,
+            BundleContext bundleContext) {
+        Dictionary<String, String> props = new Hashtable<>();
+
+        // Set the appropriate service properties so the corresponding CSS module is restarted if this
+        // blueprint container is restarted
+        props.put("config-module-namespace", "urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl");
+        props.put("config-module-name", "runtime-generated-mapping");
+        props.put("config-instance-name", "runtime-mapping-singleton");
+        return bundleContext.registerService(BindingToNormalizedNodeCodec.class, instance, props );
+    }
 }
index 79d0868..f1438c6 100644 (file)
@@ -13,7 +13,7 @@
   </bean>
 
   <!-- Register the BindingToNormalizedNodeCodec with the SchemaService as a SchemaContextListener -->
-  <bean id="mappingCodecReg" class="org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodecFactory"
+  <bean id="mappingCodecListenerReg" class="org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodecFactory"
          factory-method="registerInstance" destroy-method="close">
     <argument ref="mappingCodec"/>
     <argument ref="schemaService"/>
 
   <!-- We also register the BindingToNormalizedNodeCodec with its actual class name for
        backwards compatibility for CSS users that inject the binding-dom-mapping-service -->
-  <service ref="mappingCodec" interface="org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec"
-        odl:type="default">
-    <!-- Set the appropriate service properties so the corresponding CSS module is restarted if this
-         blueprint container is restarted -->
-    <service-properties>
-      <entry key="config-module-namespace" value="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl"/>
-      <entry key="config-module-name" value="runtime-generated-mapping"/>
-      <entry key="config-instance-name" value="runtime-mapping-singleton"/>
-    </service-properties>
-  </service>
+  <bean id="mappingCodecServiceReg" class="org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodecFactory"
+         factory-method="registerOSGiService" destroy-method="unregister">
+    <argument ref="mappingCodec"/>
+    <argument ref="blueprintBundleContext"/>
+  </bean>
 
   <!-- Binding RPC Registry Service -->
 

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.