12 Replies Latest reply on May 18, 2010 8:12 PM by cwash

    Exploded jar containing persistence.xml with jar-file elemen

    jaikiran

      I have deployed a sample ear file containing 2 jars file. The EAR file is exploded and even the jar files are in exploded format.

      EJB3Persistence.ear
       |
       |--- META-INF
       | |
       | |--- application.xml
       |
       |
       |
       |--- myapp_ejb3.jar (this is exploded too)
       | |
       | |--- META-INF
       | | |
       | | |--- persistence.xml
       | | |
       | |
       | |--- <some annotated persistent entities>
       |
       |
       |
       |--- myapp2_ejb3.jar (this too is exploded)
       | |
       | |--- META-INF
       | |
       | |--- <some more annotated persistent entities>
      
      
      
      
      
      
      


      My persistent (annotated) entities are present in both myapp_ejb3.jar and myapp2_ejb3.jar. My persistence.xml file is present in the META-INF folder of myapp_ejb3.jar and looks like this :
      <?xml version="1.0" encoding="UTF-8"?>
      
      <persistence xmlns="http://java.sun.com/xml/ns/persistence">
      
       <persistence-unit name="EJB3Persistence">
       <jta-data-source>java:/EJB3PersistenceDS</jta-data-source>
       <!-- <class>org.myapp.entity.User</class>
       <class>org.myapp.entity.Account</class> -->
       <!-- The current jar is by default scanned for entities, so just mention the other jar -->
       <jar-file>../myapp2_ejb3.jar</jar-file>
       </persistence-unit>
      </persistence>


      When i deploy this EAR on 4.2.2 version of JBoss, i get this deployment error:
      15:41:48,844 WARN [ServiceController] Problem starting service persistence.units:ear=EJB3Persistence.ear,jar=myapp_ejb3.jar,unitName=EJB3Persistence
      java.lang.RuntimeException: error trying to scan <jar-file>: file:/D:/JBoss_4_2/server/default/deploy/EJB3Persistence.ear/myapp_ejb3.jar/myapp2_ejb3.jar
       at org.hibernate.ejb.Ejb3Configuration.scanForClasses(Ejb3Configuration.java:619)
       at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:338)
       at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:126)
       at org.jboss.ejb3.entity.PersistenceUnitDeployment.start(PersistenceUnitDeployment.java:246)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.ejb3.ServiceDelegateWrapper.startService(ServiceDelegateWrapper.java:103)
       at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
       at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
       at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
       at $Proxy0.start(Unknown Source)
       at org.jboss.system.ServiceController.start(ServiceController.java:417)
       at org.jboss.system.ServiceController.start(ServiceController.java:435)
       at org.jboss.system.ServiceController.start(ServiceController.java:435)
       at org.jboss.system.ServiceController.start(ServiceController.java:435)
       at org.jboss.system.ServiceController.start(ServiceController.java:435)
       at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
       at $Proxy4.start(Unknown Source)
       at org.jboss.deployment.SARDeployer.start(SARDeployer.java:304)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
       at $Proxy42.start(Unknown Source)
       at org.jboss.deployment.XSLSubDeployer.start(XSLSubDeployer.java:197)
       at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
       at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1015)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
       at sun.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
       at $Proxy9.deploy(Unknown Source)
       at org.jboss.deployment.scanner.URLDeploymentScanner.deploy(URLDeploymentScanner.java:421)
       at org.jboss.deployment.scanner.URLDeploymentScanner.scan(URLDeploymentScanner.java:634)
       at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.doScan(AbstractDeploymentScanner.java:263)
       at org.jboss.deployment.scanner.AbstractDeploymentScanner.startService(AbstractDeploymentScanner.java:336)
       at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
       at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
       at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
       at $Proxy0.start(Unknown Source)
       at org.jboss.system.ServiceController.start(ServiceController.java:417)
       at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
       at $Proxy4.start(Unknown Source)
       at org.jboss.deployment.SARDeployer.start(SARDeployer.java:304)
       at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:766)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
       at $Proxy5.deploy(Unknown Source)
       at org.jboss.system.server.ServerImpl.doStart(ServerImpl.java:482)
       at org.jboss.system.server.ServerImpl.start(ServerImpl.java:362)
       at org.jboss.Main.boot(Main.java:200)
       at org.jboss.Main$1.run(Main.java:508)
       at java.lang.Thread.run(Thread.java:595)
      Caused by: java.lang.RuntimeException: java.util.zip.ZipException: The system cannot find the file specified
       at org.jboss.util.file.JarArchiveBrowser.<init>(JarArchiveBrowser.java:74)
       at org.jboss.util.file.FileProtocolArchiveBrowserFactory.create(FileProtocolArchiveBrowserFactory.java:48)
       at org.jboss.util.file.ArchiveBrowser.getBrowser(ArchiveBrowser.java:57)
       at org.hibernate.ejb.Ejb3Configuration.scanForClasses(Ejb3Configuration.java:610)
       ... 119 more
      Caused by: java.util.zip.ZipException: The system cannot find the file specified
       at java.util.zip.ZipFile.open(Native Method)
       at java.util.zip.ZipFile.<init>(ZipFile.java:203)
       at java.util.jar.JarFile.<init>(JarFile.java:132)
       at java.util.jar.JarFile.<init>(JarFile.java:97)
       at org.jboss.util.file.JarArchiveBrowser.<init>(JarArchiveBrowser.java:69)
       ... 122 more


      As seen in the stacktrace, the relative URL ../myapp2_ejb3.jar is parsed incorrectly which leads to this exception. This problem seems to happen only if the jar file is in exploded format (as a directory). If i zip the jar files as an archive an deploy the same EAR, everything works fine.

      Should i open a JIRA with a simple deployable application?

        • 1. Re: Exploded jar containing persistence.xml with jar-file el

          if I understand the rules correctly, once you put resources in an earfile they're accessible from all components inside that earfile.
          When deployed outside of the content of that earfile, those resources are no longer so available, instead becoming local to the application that deploys them.

          • 2. Re: Exploded jar containing persistence.xml with jar-file el
            jaikiran

             

            "jwenting" wrote:
            if I understand the rules correctly, once you put resources in an earfile they're accessible from all components inside that earfile.


            Are you saying that i should not be having the

            <jar-file>../myapp2_ejb3.jar</jar-file>


            in the persistence.xml? If i remove this entry, the persistent entities in the myapp2_ejb3.jar will not be scanned for deployment.

            • 3. Re: Exploded jar containing persistence.xml with jar-file el
              frankthetank

              Could it be related to your using relative paths in the descriptor?

              I have no idea how jboss loads exploded archives but if the descriptor is copied somewhere else, like to temp, and then read, ../ will not be where we think it will be,

              Just guessing here.

              • 4. Re: Exploded jar containing persistence.xml with jar-file el
                jaikiran

                I spent sometime on this, i can see where the problem is. There's a getRelativeURL method on org.jboss.ejb3.JmxDeploymentUnit class:

                public URL getRelativeURL(String jar)
                 {
                 URL url = null;
                 try
                 {
                 url = new URL(jar);
                 }
                 catch (MalformedURLException e)
                 {
                 try
                 {
                 if (jar.startsWith(".."))
                 {
                 if (getUrl() == null)
                 throw new RuntimeException("relative <jar-file> not allowed when standalone deployment unit is used");
                 String base = getUrl().toString();
                 jar = jar.replaceAll("\\.\\./", "+");
                 int idx = jar.lastIndexOf('+');
                 jar = jar.substring(idx + 1);
                 for (int i = 0; i < idx + 1; i++)
                 {
                 int slash = base.lastIndexOf('/');
                 base = base.substring(0, slash + 1);
                 }
                 url = new URL(base + jar.substring(idx));
                 }
                 else
                 {
                 File fp = new File(jar);
                 url = fp.toURL();
                 }
                 }
                 catch (MalformedURLException e1)
                 {
                 throw new RuntimeException("Unable to find relative url: " + jar, e1);
                 }
                 }
                 return url;
                 }
                


                This logic, using string manipulation, doesn't seem to work when the jar is exploded (i.e. ends with a / since its a directory ex: file:/D:/JBoss_4_2/server/default/deploy/EJB3Persistence.ear/myapp_ejb3.jar/) ).

                To get this working, i modified this piece of code in the JBoss code as follows:
                public URL getRelativeURL(String jar)
                 {
                 URL url = null;
                 try
                 {
                 url = new URL(jar);
                 }
                 catch (MalformedURLException e)
                 {
                 try
                 {
                 if (jar.startsWith(".."))
                 {
                 if (getUrl() == null)
                 throw new RuntimeException("relative <jar-file> not allowed when standalone deployment unit is used");
                 String base = getUrl().toString();
                 jar = jar.replaceAll("\\.\\./", "+");
                 int idx = jar.lastIndexOf('+');
                 jar = jar.substring(idx + 1);
                 File file = new File(getUrl().getFile());
                
                 for (int i = 0; i < idx + 1; i++)
                 {
                
                 file = new File(file.getParent());
                 }
                 url = new URL(file.toURL().toString() + jar);
                
                 }
                 else
                 {
                 File fp = new File(jar);
                 url = fp.toURL();
                 }
                 }
                 catch (MalformedURLException e1)
                 {
                 throw new RuntimeException("Unable to find relative url: " + jar, e1);
                 }
                 }
                 return url;
                 }


                Instead of relying on string manipulation i used the API available on java.io.File to parse the relative URL. I deployed the changed code in JBoss jar and was able to get my application deployed. Also, tested this change with an archived deployment (to make sure i did not break any existing behaviour), even that deployed fine.



                • 5. Re: Exploded jar containing persistence.xml with jar-file el

                  ugly, a dirty hack to get around a restriction imposed by JEE for security reasons.

                  • 6. Re: Exploded jar containing persistence.xml with jar-file el
                    jaikiran

                     

                    "jwenting" wrote:
                    ugly, a dirty hack to get around a restriction imposed by JEE for security reasons.


                    Sorry, i don't get this. Are you saying exploded jars are not allowed?

                    • 7. Re: Exploded jar containing persistence.xml with jar-file el

                      no, I'm saying that the way JBoss does things (i.e. disallowing you from accessing the resources in one application in another unless they're packed together in an ear-file) is correct.
                      That's the way things should be, hacking around that restriction is a bad idea.

                      • 8. Re: Exploded jar containing persistence.xml with jar-file el
                        jaikiran

                         

                        "jwenting" wrote:
                        no, I'm saying that the way JBoss does things (i.e. disallowing you from accessing the resources in one application in another unless they're packed together in an ear-file) is correct.
                        That's the way things should be, hacking around that restriction is a bad idea.


                        Well, the usecase that i have considered here is a single application packaged as an EAR containing multiple jar files with persistent entities. JPA spec allows you to package the entities in multiple jars and specify the relative URL in the persistence.xml (as in the example that i posted). The problem here seems to be just an implementation oversight in parsing the relative URL rather than a deliberate design decision.


                        • 9. Re: Exploded jar containing persistence.xml with jar-file el

                          you are confusing 2 use cases.

                          When deploying your exploded jars you're effectively deploying 2 enterprise applications.
                          Those don't share resources, including persistence units.

                          When deploying them both packaged into a single ear file they are part of a single enterprise application and can share resources.

                          In your hack you're actually creating 2 persistence units with the same name, each a part of its own enterprise application and existing only in that context.

                          This is no oversight on the part of either the expert committee who designed the JEE5 spec or JBoss, it's a quite deliberate design decision.

                          • 10. Re: Exploded jar containing persistence.xml with jar-file el
                            jaikiran

                             

                            "jwenting" wrote:
                            you are confusing 2 use cases.

                            When deploying your exploded jars you're effectively deploying 2 enterprise applications.
                            Those don't share resources, including persistence units.



                            I think i did not put this clearly. Sorry about that. When i say i am deploying the jars in exploded format, the jars are *inside the exploded EAR* file (as can be seen the original packaging hierarchy that i posted) and hence are part of the same application represented by my EJB3Persistence.ear. They are not deployed separately.


                            • 11. Re: Exploded jar containing persistence.xml with jar-file el
                              jaikiran

                               

                              "jwenting" wrote:

                              In your hack you're actually creating 2 persistence units with the same name, each a part of its own enterprise application and existing only in that context.



                              Nope. The piece of code that i modified just tries to resolve the relative URL. Without this code change earlier, the path was being resolved to

                              java.lang.RuntimeException: error trying to scan <jar-file>: file:/D:/JBoss_4_2/server/default/deploy/EJB3Persistence.ear/myapp_ejb3.jar/myapp2_ejb3.jar

                              The myapp2_ejb3.jar was being considered to be inside the myapp_ejb3.jar instead of EJB3Persistence.ear. After this code change the relative URL correctly resolves to

                              file:/D:/JBoss_4_2/server/default/deploy/EJB3Persistence.ear/myapp2_ejb3.jar



                              • 12. Re: Exploded jar containing persistence.xml with jar-file el
                                cwash

                                I made this change as well.  I don't necessarily see a problem, even if there is a security vulenrability (which I'm pretty sure is NOT the case), of making this change to your LOCAL development environment.  We don't deploy files exploded in any other environment, anyway.  I did this so that I can use JRebel to reload changes to class files dynamically.

                                 

                                Thanks for sharing your findings.