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?
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.
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.
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.
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.
There already is a VFSUtils.getRealURL(VirtualFile).
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 :-).
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.
There already is a VFSUtils.getRealURL(VirtualFile).
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.
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
Thanks Adrian and Ales for your feedback and help.