Fix a ClassNotFoundException raised during demarshalling 45/1145/1
authorGiovanni Meo <gmeo@cisco.com>
Tue, 10 Sep 2013 10:05:56 +0000 (12:05 +0200)
committerGiovanni Meo <gmeo@cisco.com>
Tue, 10 Sep 2013 11:05:25 +0000 (13:05 +0200)
Under certain conditions an error like:

Caused by: java.lang.ClassNotFoundException: org.opendaylight.controller.sal.reader.FlowOnNode
at org.eclipse.gemini.web.tomcat.internal.loading.BundleWebappClassLoader.loadClass(BundleWebappClassLoader.java:312) ~[na:na]
at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ~[na:1.7.0_09]
at java.lang.Class.forName0(Native Method) ~[na:1.7.0_09]
at java.lang.Class.forName(Class.java:264) ~[na:1.7.0_09]
at org.jboss.marshalling.AbstractClassResolver.loadClass(AbstractClassResolver.java:135) ~[na:na]
at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:116) ~[na:na]
at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:893) ~[na:na]
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1205) ~[na:na]
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) ~[na:na]
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:209) ~[na:na]

this is due to the fact that by default the Jboss Marshaller used by
Infinispan uses the Thread Context Class Loader to retrieve the
classloader to be used in the demarshalling function. Equinox provides
a default one
(org.eclipse.core.runtime.internal.adaptor.ContextFinder) as TCCL,
however it heuristically try to find the classloader and in some cases
can fetch the wrong one. Now given that all the classes managed by
clustering services must go via OSGi it make sense to force the usage
of only the bundle class loader and we let OSGi framework to figure
out how to load the class.

Change-Id: I24a9056eda5f6ab7b8cf0ab2e476be56cb61f6c1
Signed-off-by: Giovanni Meo <gmeo@cisco.com>
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClassResolver.java [new file with mode: 0644]
opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClusterManager.java

diff --git a/opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClassResolver.java b/opendaylight/clustering/services_implementation/src/main/java/org/opendaylight/controller/clustering/services_implementation/internal/ClassResolver.java
new file mode 100644 (file)
index 0000000..521a773
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.clustering.services_implementation.internal;
+
+import java.lang.ref.WeakReference;
+
+import org.jboss.marshalling.ContextClassResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ClassResolver extends ContextClassResolver {
+    private WeakReference<ClassLoader> osgiClassLoader = null;
+    private static final Logger logger = LoggerFactory.getLogger(ClassResolver.class);
+
+    public ClassResolver() {
+        ClassLoader cl = this.getClass()
+                .getClassLoader();
+        if (cl != null) {
+            this.osgiClassLoader = new WeakReference<ClassLoader>(cl);
+            logger.trace("Acquired weak reference to OSGi classLoader {}", cl);
+        }
+    }
+
+    @Override
+    protected ClassLoader getClassLoader() {
+        ClassLoader ret = null;
+        if (this.osgiClassLoader != null) {
+            ret = this.osgiClassLoader.get();
+            if (ret != null) {
+                if (logger.isTraceEnabled()) {
+                    logger.trace("Returning OSGi class loader {}", ret);
+                }
+                return ret;
+            }
+        }
+
+        logger.warn("Could not resolve classloader!");
+        return ret;
+    }
+}
index f5c655a4eae8fb52afcefad92507177ff1cc479a..cd3a29579194c9a6a9831f4e44d7e67150b69f6d 100644 (file)
@@ -33,6 +33,9 @@ import javax.transaction.TransactionManager;
 
 import org.infinispan.Cache;
 import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
+import org.infinispan.configuration.parsing.ParserRegistry;
 import org.infinispan.manager.DefaultCacheManager;
 import org.infinispan.manager.EmbeddedCacheManager;
 import org.infinispan.notifications.Listener;
@@ -247,8 +250,14 @@ public class ClusterManager implements IClusterServices, IContainerAware {
         }
         logger.info("Starting the ClusterManager");
         try {
-            //FIXME keeps throwing FileNotFoundException
-            this.cm = new DefaultCacheManager("config/infinispan-config.xml");
+            ParserRegistry parser = new ParserRegistry(this.getClass()
+                    .getClassLoader());
+            ConfigurationBuilderHolder holder = parser.parseFile("config/infinispan-config.xml");
+            GlobalConfigurationBuilder globalBuilder = holder.getGlobalConfigurationBuilder();
+            globalBuilder.serialization()
+                    .classResolver(new ClassResolver())
+                    .build();
+            this.cm = new DefaultCacheManager(holder, false);
             logger.debug("Allocated ClusterManager");
             if (this.cm != null) {
                 this.cm.start();