9 Replies Latest reply on Nov 9, 2009 5:40 PM by davidcole

    Jar file real path in non-exploded ear

    davidcole

      We deploy our application as a non-exploded ear archive.
      Within our application, we need to compile a java source string into a class at runtime within the application and depend on other classes contained in a jar within the ear.

      We are attempting to use either javac or JavaCompiler to perform the task. Both require you to specify additional classes or jars on the classpath for dependent classes. I am taking a sample class and get a URL to the class using:

      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      Class referenceClass = this.getClass();
      String classRelPath = referenceClass.getName().replace('.', '/') + ".class";
      URL url = loader.getResource(classRelPath);

      However, the class file is loaded using VFS so the URL is specified with the vfszip protocol like this:'

      vfszip:/C:/Apps/jboss/jboss-5.1.0.GA/server/node1/farm/myApp.ear/lib/svrbase.jar/com/myApp/javacode/JavaCodeSourceCompiler.class

      Notice that the class is being referenced relative to the actual ear file which is in non-exploded archive format.

      Jboss copies the library jars from the ear to a tmp directory and I need to find a way to get a path reference to the actual jars that are classloaded by jboss in the tmp directory, not within the ear.

      Is there an option to force VFS or the ClassLoaders to use the real jar file paths or are there any code samples/methods within VFS to get access to the real path of the jar containing the class?

        • 1. Re: Jar file real path in non-exploded ear
          alesj

           

          "davidcole" wrote:

          Is there an option to force VFS or the ClassLoaders to use the real jar file paths or are there any code samples/methods within VFS to get access to the real path of the jar containing the class?

          The temp copy is an implementation detail, which you shouldn't use or care about.

          If you reference some jar in ear's lib via URL,
          the VFS will actually re-use that temp under the covers.

          Or why exactly would you wanna get a hold of the "real" location?

          • 2. Re: Jar file real path in non-exploded ear
            davidcole

            I am running an ear application and need to compile a java source file at runtime from within the application. My choices are to either invoke javac.Main() or use the JavaCompiler class.

            Either case only works if you specify the classpath option '-cp'.
            Neither option uses the curentContext.ClassLoader() to load dependent classes. So, I must explicitly set the classpath with my library jars. When I search the currentContext.ClassLoader for the list of URL's in the ClassPath, the list will be the Virtual File versions, nested within the ear as explained before. javac.Main does not recognize the 'virtual' urls as valid locations. I need to be able to get access to the 'real' locations to specify on the classpath in order to compile successfully.

            • 3. Re: Jar file real path in non-exploded ear
              alesj

              What does it recognize?
              If it's only plain files, then this sounds like a big limitation of javac.Main.

              Afair, our Javassist has some runtime compile options.
              Perhaps you can use that - javassist.jar is already part of core JBossAS.

              • 4. Re: Jar file real path in non-exploded ear
                davidcole

                javac only recognizes simple class files or jars. The only other option that was recently added was the ability to add the wildcard to a directory like /mylib/* to include all jars in that directory.

                What is really disappointing is that the newer JavaCompiler class does have the option to set the ClassLoader on a FileManager object, which I was hoping would allow me to set the WebContextClassLoader to locate dependent classes..doesn't work. The ClassLoader is only used to load classes needed when loading plugins for use when processing Annotations, etc.

                So, javac doesn't recognize nested libraries...jars packaged in a war or ear, etc. I need the path to the jar that gets copied by Jboss outside of the ear.

                I have looked at JavaAssist, BCEL, etc. However, all are really designed to either manipulate existing classes, or create classes on the fly using their API. I was hoping for somethign simpler, because I already have the entire source file as a String and simply want to compile it as is without too much additional effort.

                • 5. Re: Jar file real path in non-exploded ear
                  davidcole

                  I'm not totally satisfied with this as a solution, but is a start for a possible workaround.

                  Given the original vfs path taken from the ClassLoader as a URL, I am able to use the jboss-vfs.jar API to FORCE the creation of a NEW tmp file for my jar that I am then able to get the real path for using the following code

                   String path = url.toExternalForm().substring(0, url.toExternalForm().indexOf(classRelPath) - 1);
                  
                   URL resourceURL = new URL(path);
                  
                   VFSUtils vfsUtils = new VFSUtils();
                   //Get the root location/archive whre the class is located
                   VirtualFile vFile = VFS.getRoot(resourceURL);
                   //Create a temporary file where so we can get a handle to the exact tmp location
                   vFile = vfsUtils.temp(vFile);
                   //Get the URI to the temp file location
                   URI tmpURI = vfsUtils.getCompatibleURI(vFile);
                   //Finally clean the result uri path
                   classFilePath = vfsUtils.stripProtocol(tmpURI);
                  


                  The big drawback is that it takes a second or two to process because jboss literally creates a new tmp copy of the jar. Also, unless I use the VFS API to cleanup, JBoss does not delete the tmp file for me. That in itself is not a large problem, because JBoss routinely leaves behind a lot of files in the tmp folder and we are customarily purging the folder by deleting all files in tmp in the startup script for JBoss

                  I don't consider this a great workaround, but maybe it sheds some light on what I am trying to achieve and maybe someone can point me to a better solution...even if the solution lies within using the VFS API.

                  • 6. Re: Jar file real path in non-exploded ear

                    There already is a VFSUtils.getRealURL(VirtualFile).
                    https://jira.jboss.org/jira/browse/JBVFS-77

                    Anyway, why don't you use the eclipse compiler instead?
                    That's what Tomcat uses to compile jsps using the classloader instead of trying
                    to construct a classpath (which you'll probably get wrong :-).
                    http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JDTCompiler.java

                    • 7. Re: Jar file real path in non-exploded ear
                      davidcole

                      Thanks again for the quick reply. I did actually find and try the VFSUtils.getRealURL(VirtualFile). However, the return value is still just the nested path to my jar within an ear and not to the location it is being loaded by jboss in the \tmp\vfs-nested.tmp directory. The method's intention, I believe, is exactly what I am looking for, but doesn't give me the expected result.

                      • 8. Re: Jar file real path in non-exploded ear
                        alesj

                         

                        "adrian@jboss.org" wrote:
                        There already is a VFSUtils.getRealURL(VirtualFile).
                        https://jira.jboss.org/jira/browse/JBVFS-77

                        Actually this is probably a bad method name choice.
                        This method is not intended to "reveal" the impl details - the temp location.
                        It was added to help security add some file permissions based on location,
                        and since security kicks in very early (before VFS), the returned URL is JDK compliant.

                        So, what this method does is tries to translate VFS url to JDK url.
                        But since VFS understands multiple nested URLs, which is not the case with JDK (afaik),
                        we can actually get diff level of nested resources with the same url.

                        e.g.
                        vfszip://top.jar/2nd.jar/3rd.jar/org/acme/X.java --> jar:file://top.jar!/2nd.jar
                        vfszip://top.jar/2nd.jar/4th.jar/com/foo/Y.java --> jar:file://top.jar!/2nd.jar


                        • 9. Re: Jar file real path in non-exploded ear
                          davidcole

                          Thanks Adrian and Ales for your feedback and help.