9 Replies Latest reply on Jan 8, 2015 2:34 PM by pferraro

    WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars

    hr.stoyanov

      Hello,

      I am getting java.lang.ClassCastException for the same classes which I store in Wildfly's Infinispan cache. This happens when I redeploy my WAR file in a running server and the only solution is to restart Wildfly itself. I suspect this is because Infinispan somehow retains the classloaders used when storing the objects. How can this be solved?

        • 1. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
          jaikiran

          Please post the entire exception stacktrace and also relevant code from your application where you use Infinispan.

          • 2. Re: Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
            hr.stoyanov

            Jaikiran Pai,

            Below is the class cast exception and the Java code that causes it - this type of class cast exceptions (for the same class) occur only when the same class is loaded from different classloaders. Somehow the Wildfly built-in Infinispan cache retains the classloader from previous deployments, so when the web app is redeployed, it is associated with a new classloader and  the exceptions occurs upon retrieving and casting the objects from the cache. The only solution I have so far is to restart the Wildfly server. Not pretty!

            ,,,

            static ScreenDTO getScreensForDisplay(Cache<String, Object> cache, EntityManager em, String userId) {

                    AtomicMap<String, Object> map = AtomicMapLookup.getAtomicMap(cache, userId);

                    String key = getTopScreenKey();

                    ScreenDTO topScreen = ScreenDTO.class.cast(map.get(key));

                    if (topScreen != null) {

                        return topScreen;

                    }

                    ...

            }

             

             

             

            Caused by: java.lang.ClassCastException: Cannot cast com.peruncs.s4g.web.gwt.client.shared.ScreenDTO to com.peruncs.s4g.web.gwt.client.shared.ScreenDTO

              at java.lang.Class.cast(Class.java:3361) [rt.jar:1.8.0_25]

              at com.peruncs.s4g.web.gwt.server.Screen.getScreensForDisplay(Screen.java:502) [classes:]

              at com.peruncs.s4g.web.gwt.server.ScreensManagerImpl.getUserScreens(ScreensManagerImpl.java:52) [classes:]

              at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_25]

              at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_25]

              at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_25]

              at java.lang.reflect.Method.invoke(Method.java:483) [rt.jar:1.8.0_25]

              at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)

              at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)

              at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)

              at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)

              at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:82) [wildfly-weld-8.2.0.Final.jar:8.2.0.Final]

              at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:93) [wildfly-weld-8.2.0.Final.jar:8.2.0.Final]

              at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)

              at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)

              at org.jboss.as.ee.component.interceptors.UserInterceptorFactory$1.processInvocation(UserInterceptorFactory.java:63)

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)

              at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]

              at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)

              at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47) [wildfly-jpa-8.2.0

             

             

            The Infinispan docs mention that one can configure:

            <store-as-binary />

            as a way to achieve classloader isolation. However, this configuration is not mentioned in the Wildfly Infinispan intergration document. I wonder if this can help me with my issue.

             

            Here is my cache configuration:

            ...

            <subsystem xmlns="urn:jboss:domain:infinispan:2.0">

                        <cache-container name="S4GCacheContainer" default-cache="S4GLocalCache">

                            <local-cache name="S4GLocalCache">

                                <transaction mode="NON_XA"/>

                                <eviction strategy="LRU" max-entries="5000"/>

                                <expiration lifespan="86400000"/>

                                <file-store passivation="true" purge="true"/>

                            </local-cache>

                        </cache-container>

                   ...

            </cache-container>

            • 3. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
              rs3vans

              In Java, every object retains a reference to its Class, and every Class retains a reference to its ClassLoader. If you store objects in a cache which is not part of the deployed WAR (and therefore, not destroyed when the WAR is undeployed), then those objects are not garbage collected, and their classes are not unloaded. When your newly deployed WAR starts to access the cache, it is getting instances of those objects which were part of the previous ClassLoader - they are not considered the same.

               

              I have run into the same thing before, and I was left with manually clearing the cache just after redeploying the WAR. There may be a way to serialize the objects going into the infinispan cache, but I'm not sure how to do that...

              • 4. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                wdfink

                One option to solve this might be to store the ScreenDTO class in  module and use a dependency from the war. In this case the class loader does not change if you redeploy the war.

                But why you need such objects if you redeploy?

                • 5. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                  hr.stoyanov

                  Wolf-Dieter Fink,

                  I do not need the ScreenDTO objests when I redeploy. In fact,  I configured

                  the cache to purge upon restart (see the module configuration I posted).

                  But the purge attribute does not help when redeployment wars into a running

                  wildfly container.

                   

                  I am exploring two options now:

                  1. Make Infinispan serialize to binaries.  This way there will be no

                  classloaders retained. This seems to be possible according to the

                  Infinispan docs and is explicitly said to guard against classloaders

                  issues, but seems to be unsupported by the wildfly module?

                   

                  2. Implement @WebListener in my war file to start/stop the cache upon

                  deploy /undeploy.  This way the war life cycle is synced up with

                  starting/stopping the cache.  But early tests yesterday did not work...

                  Will to more tonight y

                   

                  Any other ideas are welcome.  This should be much easier...

                   

                  /Hristo Stoyanov

                  • 6. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                    jaikiran

                    I can see why the purge attribute may not work in this case, since the cache has no link with the web application and hence no idea about the lifecycle management of the source of the cached objects. I don't know what the recommend way to deal with such cases is. Perhaps a application specific cache configured at application level instead of subsystem level? I'm just guessing though.

                     

                    pferraro would know more about this (It's a holiday season right now so you might see a delayed response).

                    • 7. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                      pferraro

                      I suspect that your cache is not properly scoped to your deployment.  The easiest way to properly handle cache lifecycle correctly is to let WildFly manage it (i.e. via @Resource(lookup) of the cache).  That way, when your application deploys, any injected caches will start automatically, and stop automatically on undeploy (provided no other deployment/service depends on them).  Stopping a cache that uses a file-store will force all cache contents to passivate.  When the cache contents are passivated, they are serialized using the module identifier of the deployment - and so are able to be recognized upon re-activation by the redeployed application.  However, if purge is enabled, the cache contents are discarded on stop - so each deployment *should* start with an empty cache.

                      It sounds to me like your cache isn't stopping properly on undeploy - which could be due to a number of reasons, including improper use of start="EAGER".  Can you post your code where you obtain a reference to your cache manager and cache - and/or attempt to start/stop your cache?

                      • 8. Re: Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                        hr.stoyanov

                        Paul,

                        Gou it to  work! Thanks!

                        1. Here is my cache configuration:

                                  <cache-container name="S4GCacheContainer" default-cache="S4GLocalCache">

                                        <local-cache name="S4GLocalCache">

                                            <transaction mode="NON_XA"/>

                                            <eviction strategy="LRU" max-entries="5000"/>

                                            <expiration lifespan="86400000"/>

                                            <file-store passivation="true" purge="true"/>

                                        </local-cache>

                                    </cache-container>

                         

                        2. Here is how I obtain the cache:

                        @Stateless

                        public class ScreensManagerImpl implements ScreensManager {

                             ...

                            @Resource(lookup = "java:jboss/infinispan/cache/S4GCacheContainer/default")

                            private Cache<String, Object> cache;

                        ...}

                         

                         

                        I am not sure I need the purge option, but now I see not classloader issues upon reloading the app!

                         

                        Thanks!

                        • 9. Re: WildFly 8.2 and built-in Infinispan - class cast exception when redeploying wars
                          pferraro

                          Excellent!  You would only need to enable purge if your application requires that your cache is initially empty.