12 Replies Latest reply on Dec 8, 2017 4:33 PM by coque_pmb

    ClassLoading delegation Wildfly 11

    coque_pmb

      Hello,

       

      I'm migrating from Glassfish to Wildfly a project which uses eclipselink as JPA persistence provider.

       

      I managed to get it working adding eclipselink jar to module as described for example here: Migrate from GlassFish to WildFly - Ralph's Open Source Blog

       

      I use Netbeans as IDE and everything goes right: I can deploy the application and it runs as expected, access database, etc...

       

      However, at development time, every time I make a change in the source code and I save it, Netbeans re-deploys the project (this is the behaviour I want), resulting in a ClassCastException.

       

      I faced this issue in the past working with GlassFish and it was resolved adding

       

                      <class-loader delegate="false"/>

       

      to glassfish-web.xml, so that eclipselink classes are loaded from the WAR rather than from app server.

       

      I found that WildFly had a similar approach to this (see Chapter 3. Migrate Your Application - Red Hat Customer Portal ) using "java2ParentDelegation=false" property, but unfortunately this is not recognized by modern versions of WildFly. I also tried to add a <exclusions> node (<module name="org.eclipse.persistence"/>) to jboss-deployment-structure, but then the WAR is not even deployed (I get a loop error).

       

      I would like to solve this since it is currently a hell to develop... having to stop - undeploy - compile - deploy every single change I introduce in the code if I want the application to run.

       

      Is there anything I'm missing? Any help?

       

      Kind regards,

       

      Jorge

        • 1. Re: ClassLoading delegation Wildfly 11
          jaikiran

          Please post the complete exception stacktrace that you notice when you redeploy the application.

          • 2. Re: ClassLoading delegation Wildfly 11
            coque_pmb

            Hi, many thanks, yes here it goes:

             

            12:24:36,729 ERROR [stderr] (ServerService Thread Pool -- 83) java.lang.ClassCastException: com.pmb.framework.persistence.DProyectoBase cannot be cast to com.pmb.framework.persistence.DProyectoBase

            12:24:36,729 ERROR [stderr] (ServerService Thread Pool -- 83) at com.pmb.framework.entidades.AplicacionWrapper.reiniciar(AplicacionWrapper.java:196)

            12:24:36,729 ERROR [stderr] (ServerService Thread Pool -- 83) at com.pmb.framework.listeners.ServerInitWrapper.inicializarServidor(ServerInitWrapper.java:204)

            12:24:36,729 ERROR [stderr] (ServerService Thread Pool -- 83) at com.pmb.maden.listeners.ServerInit.contextInitialized(ServerInit.java:72)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:205)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:174)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:239)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:99)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:81)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

            12:24:36,730 ERROR [stderr] (ServerService Thread Pool -- 83) at java.util.concurrent.FutureTask.run(FutureTask.java:266)

            12:24:36,731 ERROR [stderr] (ServerService Thread Pool -- 83) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

            12:24:36,731 ERROR [stderr] (ServerService Thread Pool -- 83) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

            12:24:36,731 ERROR [stderr] (ServerService Thread Pool -- 83) at java.lang.Thread.run(Thread.java:748)

            12:24:36,731 ERROR [stderr] (ServerService Thread Pool -- 83) at org.jboss.threads.JBossThread.run(JBossThread.java:320)

             

             

            Kind regards,

             

            Jorge

            • 3. Re: ClassLoading delegation Wildfly 11
              jaikiran

              What does your application packaging look like? Is it an .ear or is it just a .war? Where exactly does this class com.pmb.framework.persistence.DProyectoBase reside within this packaging? Can you also post a snippet from your com.pmb.maden.listeners.ServerInit.contextInitialized and com.pmb.framework.entidades.AplicacionWrapper.reiniciar code?

              • 4. Re: ClassLoading delegation Wildfly 11
                coque_pmb

                Hello, thanks again, I'll try to explain:

                 

                - The application package is a .war.

                 

                - It is a main project and a library project included in the .war.  This library is a kind of framework developed by myself which I use in several projects (though no other project is deployed at the same time in the server at this time)

                 

                - the entity class  com.pmb.framework.persistence.DProyectoBase  is declared and "entity-anotated" in the library project and extended within the main project.

                 

                - the main project contains a class "com.pmb.maden.listeners.ServerInit" which is annotated as @WebListener, so its contextInitialized method is executed every time context is initialized, this is, every time the application is re-deployed.

                 

                  This listener class extends another (abstract) class on the framework library, and contextInitialized method loads main project init properties and calls super.performInit() method passing it specific project init properties.

                 

                - The library performInit() method does some initialization steps (all working ok) and inits Persistence Unit successfully. After that, it calls com.pmb.framework.entidades.AplicacionWrapper.reiniciar(), where the error happens.

                 

                - com.pmb.framework.entidades.AplicacionWrapper is a helper abstract class included in the framework library which only has static methods and properties. The referred method reiniciar() creates a query over the entity class com.pmb.framework.persistence.DProyectoBase:

                 

                  1 Query qproyectos = em.createNamedQuery("DProyectoBase.findAll");

                  2 final List<DProyectoBase> proyectos = (List<DProyectoBase>) qproyectos.getResultList();

                 

                  3 for (DProyectoBase p : proyectos) {

                     ...

                    

                    }

                   

                The "3" line above is where the classcastexception is thrown (DProyectoBase cannot be casted to DProyectoBase). It works well on deploy but fails on re-deploy. In these situations List<DProyectoBase> is populated however.

                 

                What I learned some time ago when deploying over GlassFish is that this happens because of classLoading is delegated by default to application server, so the magic "<class-loader delegate="false"/>" in glassfish-web.xml solved the problem.

                 

                I guess Eclipselink library (included as a Wildfly module) keeps a reference to DProyectoBase using application server classLoader. When project is re-deployed, DProyectoBase entities referenced in still alive Eclipselink library don't match against new classLoader signature and thus I get a classcastexception where it is obvious that we are dealing with same class.

                 

                Well, I hope I could explain it.

                 

                Thanks a lot for your help

                 

                Jorge

                • 5. Re: ClassLoading delegation Wildfly 11
                  jaikiran

                  That's a clear enough explanation, thanks.

                   

                  How are you getting hold of the EntityManagerFactory and EntityManager? If you are creating them yourself, are you making sure to close them in the contextDestroyed callback method of the listener?

                  • 6. Re: ClassLoading delegation Wildfly 11
                    coque_pmb

                    Hello, the EntityManagerFactory is created at contextInitialized callback:

                     

                      EntityManagerFActory = emFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, System.getProperties());

                     

                     

                    And it is again closed at contextDestroyed callback:

                     

                     

                      if (emFactory.isOpen()) {

                        emFactory.close();

                      }

                     

                     

                    However, after reading your question, I added some traces to check if everything is going right... and to my surprise, that code is not called upon redeploy! since I suspect contextDestroyed callback is not even called. This is the trace, where you can see that persistence unit seems to be stopped (but not by my code):

                     

                     

                    15:47:56,862 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 18) WFLYUT0022: Unregistered web context: '/' from server 'default-server'

                    15:47:56,901 INFO  [org.jboss.as.jpa] (ServerService Thread Pool -- 76) WFLYJPA0004: Stopping Persistence Unit Service 'Maden.war#MadenPU'

                    15:47:56,948 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-5) WFLYSRV0028: Stopped deployment Maden.war (runtime-name: Maden.war) in 89ms

                    15:47:56,950 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-2) WFLYSRV0027: Starting deployment of "Maden.war" (runtime-name: "Maden.war")

                     

                     

                    I double checked the code and don't understand why it is not executed.

                     

                    Do you see any inconsistence?

                     

                    Again, many thanks for your help,

                     

                    Jorge

                    • 7. Re: ClassLoading delegation Wildfly 11
                      coque_pmb

                      Hi again, I just found another strange thing: I said in my previous post that contextDestroyed callback is no called upon re-deploy, and it is true... but only upon FIRST re-deploy. I found by chance that second, third, ... re-deploys do call contextDestroyed listener method.

                       

                      If this is the case I can check that the EntityManagerFactory is properly closed as expected, but it does not affect the ClassCastException on the contextInitialized() callback afterwards, which is still thrown.

                       

                      I don't know if this makes any sense, but again I double checked this is what happens.

                       

                      Kind regards,

                       

                      Jorge

                      • 8. Re: ClassLoading delegation Wildfly 11
                        jaikiran

                        How exactly do you trigger the application redeployment from the NetBeans IDE? Also, is there any chance you can attach a simple application (preferably a buildable source) which reproduces this issue on WildFly 11?

                        • 9. Re: ClassLoading delegation Wildfly 11
                          coque_pmb

                          Hi,

                           

                          Redeployment is automatically triggered by netbeans on save (I'm using 'redeploy on save' checkbox at project properties ).

                           

                          And yes, of course, I will isolate the issue in the simplest possible project and will attach it including steps to reproduce on WildFly 11. I'll need one day however to do it, so will come back tomorrow with it!

                           

                          Kind regards,

                           

                          Jorge

                          • 10. Re: ClassLoading delegation Wildfly 11
                            coque_pmb

                            Hi again, well... I have been working on this, building a super-simple project to demonstrate the issue... but this super-simple project works! context is destroyed as expected and entities do not generate any class-cast exception upon re-deploy, same environment, same conditions.

                             

                            So... obviously WildFly is doing its job...

                             

                            I will start my current project from the scratch and will see where the problem comes from. Will come back to this thread to post the results, though no idea how long it will take.

                             

                            I'm sorry Jaikiran for time spent by you on this but certainly thank you for your help!

                             

                            Jorge

                            • 11. Re: ClassLoading delegation Wildfly 11
                              jaikiran

                              Good to know. If this does turn out to be some issue in WildFly, with your larger application, feel free to report back.

                              • 12. Re: ClassLoading delegation Wildfly 11
                                coque_pmb

                                Hello, after a full day investigating I found where the problem came from:

                                 

                                While constructing the httpSession, the httpServletRequestWrapper was adding an attribute to the session in order to store there different configuration accross different requests in the same session.

                                 

                                This attribute added to the httpSession was implementing the interface HttpSessionBindingListener whith the purpose of storing a reference map to every active session handled by the application.

                                 

                                The implementation I had used was provisional and was left in my framework code due to the fact that GlassFish never complained. Just removing the interface (I don't really need that capability at the moment) and its implementation code has solved the problem.

                                 

                                Now I can redeploy on save my project and Persistence Unit is successfully unload and load again. Now development experience will come back from black & white to color again!

                                 

                                Many thanks Jaikiran for your support. I can confirm now that WildFly is doing its job. The issue had nothing to do with ClassLoading. I don't understand why <class-loader delegate="false"/> solved the problem in GlassFish.

                                 

                                Kind regards,

                                 

                                Jorge