is it possible to load jars-in-jars in JWS? - java

I have found MANY threads on packing all dependencies along with the project into one jar package, and it seems like there are many different ways to achieve this (oneJar, FatJar, Ant-build...)
So cooking up my own recipe, I have (after quite some effort) managed to package the project I am working on. In this one jar file, there is the code for the project plus all the jars that the project depends on which are loaded with jar-in-jar-loader that comes with eclipse. The resultant works fine on a number of different platforms, when it's ran through the terminal invoked via java -jar myjarfile.
Peachy, you might say, here's the problem though; when I sign my jar and try to run it via javaws (which is the ultimate goal here) I get an exception which I have decrypted to mean that libraries (in the case below org.apache.commons.lang.SystemUtils) are unaccessible.
So here's my question; is it not possible to load jars in jars when the applications is deployed for Java Web Start? If it is possible, what am I doing wrong? If not, what's the best alternative?
Thanks!
Below is the JNLP file along with the stackTrace I get when I run javaws myJNLPfile
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"
codebase="file:///home/ukirik/workspace/myproject/dist"
href="project.jnlp">
<information>
<!-- Project info -->
</information>
<security>
<all-permissions />
</security>
<resources os="Mac\ OS\ X">
<j2se version="1.6+" java-vm-args="-XstartOnFirstThread"/>
</resources>
<resources>
<jar href="myjar-jws.jar" />
</resources>
<application-desc main-class="org.gvt.RuntimeMain"/>
</jnlp>
java.lang.reflect.InvocationTargetException
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:597)
at com.sun.javaws.Launcher.executeApplication(Launcher.java:1799)
at com.sun.javaws.Launcher.executeMainClass(Launcher.java:1745)
at com.sun.javaws.Launcher.doLaunchApp(Launcher.java:1507)
at com.sun.javaws.Launcher.run(Launcher.java:129)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/lang/SystemUtils
at org.gvt.RuntimeMain.loadSwtJar(RuntimeMain.java:27)
at org.gvt.RuntimeMain.main(RuntimeMain.java:13)
... 9 more
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.SystemUtils
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at com.sun.jnlp.JNLPClassLoader.findClass(JNLPClassLoader.java:332)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 11 more

If you are using the Eclipse jar-in-jar loader I think that you may need this in the jnlp file
<application-desc main-class="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader"/>
That's assuming that your manifest is looking like this...
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 20.1-b02 (Sun Microsystems Inc.)
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
Rsrc-Main-Class: yourapp.mainclass
Rsrc-Class-Path: ./ swt.jar velocity-1.7-dep.jar
Class-Path: .

It seems like the problem is with the classloader.
You may want to use a custom classloader in JWS, as described here:
http://lopica.sourceforge.net/faq.html#customcl
Depending on exactly what you need to do, in terms of packaging, there are a couple of options.

The problem you're running into is that you're passing org.gvt.RuntimeMain as your main class for your jar in your JNPL file, but that's a one-jar jar. Because it's a one-jar jar, you need to provide class com.simontuffs.onejar.Boot instead, as
<application-desc main-class="com.simontuffs.onejar.Boot"/>
The reason for it, is that the one-jar plugin will generate that class, which will make use of a classloader that understands jars within jars, and then invoke your org.gvt.RuntimeMain class (it figures it out through looking at the manifests's One-Jar-Main-Class: header).

Related

FileNotFoundException during JNLP download

I was looking for a solution of this problem for weeks now, but did not find anything, which really related to my problem / or I already tried all suggested solutions, without any success.
I have a JNLP file, which is downloaded by the javaws properly (I think), but then before launching, it complains about not finding some files in the /tmp directory. Exact error message is:
CouldNotLoadArgumentException[ Could not load file/URL specified: /tmp/tmp_cache8259898691262575141.tmp]
at com.sun.javaws.Main.launchApp(Unknown Source)
at com.sun.javaws.Main.continueInSecureThread(Unknown Source)
at com.sun.javaws.Main.access$000(Unknown Source)
at com.sun.javaws.Main$1.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.FileNotFoundException: /tmp/tmp_cache8259898691262575141.tmp (Nincs ilyen fájl vagy könyvtár)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at com.sun.javaws.jnl.LaunchDescFactory.buildDescriptor(Unknown Source)
... 5 more
I checked the /tmp, the folder is of course there, and is writable. Funny thing is, that during downloading the tmp_cacheNNNNNN.tmp files are there! They appear one-by-one, as the download progress moves on. However when the download is finished something (javaws?) deletes all of them, and then starts to complain about missing them.
I have JNLP caching turned on (and intend to have it cached locally). I tried with JRE 1.8.0_40, 1.8.0_65, 1.8.0_66, all gives the same result. Same result on windows and linux, both complain about missing files in the temp folder.
The last JRE I managed to start is the 1.8.0_25, and seems to work with 1.8.0_72 (beta). However the downloaded jar files are still not cached! (if I open up the jcontrol application and look into the cache, the JAR files are not there, and I also don't know why).
My JNLP looks like this:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="7.0+"
codebase="http://localhost:8080/jbaf-server/jnlp/swing-client"
href="http://localhost:8080/jbaf-server/clientDownload/client.jnlp" >
<information>
<title>Swing Client</title>
<vendor>www.xy.z</vendor>
<description>Swing Client</description>
<description kind="short">Swing Client</description>
<homepage href="www.xy.z"></homepage>
<icon href="images/jnlp-icon.png"/>
<icon kind="splash" href="images/jnlp-splash.png"/>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.8+" initial-heap-size="256m" max-heap-size="1024m"/>
<property name="jnlp.versionEnabled" value="true" />
<jar href="jbaf-swing-client.jar" version="0.3.0" main="true"/>
.... (lots of jar files)
<jar href="spring-expression.jar" version="4.2.3.RELEASE"/>
<jar href="spring-tx.jar" version="4.2.3.RELEASE"/>
<jar href="commons-codec.jar" version="1.10"/>
</resources>
<application-desc main-class="org.jbaf.swingclient.Main">
<argument>http://localhost:8080/jbaf-server</argument>
<argument>false</argument>
</application-desc>
</jnlp>
The JARs are signed with self-signed cert.
I have no idea why this happens. Anyone faced such a problem?
Finally I managed to find the problem!
It was caused by following HTTP headers set by Tomcat:
Cache-Control
Pragma
Expires
I did not set these headers in my Servlets, but it seems that these were added by some of the filter previously. I set these header values to "" (empty string), and the JDK started to cache my files, and the application was started finally OK!
However if you set the Cache-Control to no-cache, the JDK still fails to start the application. The files are saved to the System/User temp directory, but afterwards it will not start, because the temp files are removed. This was only working with JDK 1.8.0_72 (BETA), all previous version failed!
Long story short: if you have problems with your JNLP where the WebStart tells you not finding files in the temp directory, check your HTTP Response Headers!

How to run FindBugs off of Ivy downloaded JARs

I've got Ant and Ivy setup so that I can use Ivy downloaded JARs to run PMD. Trying the same with FindBugs, setting the findbugs.home Ant property to ivy-jars/findbugs, where the Ivy JARs go. I initially got the error that it couldn't find the JAR files under the ${findbugs.home}/lib directory. I fixed that by changing Ivy to download the JAR files into ivy-jars/findbugs/lib. However, this gave rise to the new error:
Executing findbugs FindBugsTask from ant task
Running FindBugs...
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/bcel/classfile/ClassFormatException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.apache.bcel.classfile.ClassFormatException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
This turns out to be caused by three problems:
I retrieved the JAR files using symlink="true". FindBugs dereferences the symlink to findbugs.jar and looks for all of its other JAR files under the same directory, but the way Ivy structures its cache only the findbugs.jar is in that directory. This can be fixed easily enough by not using symlinks.
FindBugs wants its JAR files to sometimes have the filename format [artifact].[ext] and sometimes have the format [artifact]-[revision].[ext], which can be solved by doing <ivy:retrieve> two times with different pattern values.
FindBugs wants the file name for the BCEL JAR file to be exactly bcel-6.0-SNAPSHOT.jar rather than bcel-findbugs.jar or bcel-findbugs-6.0.jar; this can be fixed with a symbolic link.
I consider this to just be a workaround, rather than a true solution, since #2 and #3 can't be how FindBugs is intended to be used under Ivy. So if anyone knows the right way to do it, please provide a better answer.
Contrary to the documentation, the home attribute is not required. Instead, you can provide a nested classpath element, which can be any path-like structure.
The following Ant target works for me:
<target name="findbugs" description="Run findbugs on the code">
<ivy:retrieve/>
<ivy:cachepath pathid="findbugs.classpath" conf="findbugs"/>
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" classpathref="findbugs.classpath"/>
<findbugs>
<classpath refid="findbugs.classpath"/>
<class location="my-analysis-target.jar"/>
</findbugs>
</target>
Where my ivy.xml is:
<ivy-module version="2.0">
<info organisation="meh" module="meh"/>
<configurations defaultconfmapping="findbugs->default">
<conf name="findbugs"/>
</configurations>
<dependencies>
<dependency org="com.google.code.findbugs" name="findbugs" rev="3.0.1" conf="findbugs"/>
</dependencies>
</ivy-module>

Exception when trying to save images

When starting my Java application, I get exceptions when trying to save images. In Eclipse, however, everything works fine. The application is built using fatjar and the necessary libraries (jar_imageio.jar and ij.jar) have been selected for export as well.
I tried using ImageIO and ImageJ:
a.) ImageIO:
ImageIO.write(image, "jpg", new File(f));
Exception in thread "main" sun.misc.ServiceConfigurationError:
javax.imageio.spi.ImageWriterSpi:
Provider com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageWriterSpi
could not be instantiated: java.lang.IllegalArgumentException: vendorName == null!
at sun.misc.Service.fail(Unknown Source)
at sun.misc.Service.access$200(Unknown Source)
at sun.misc.Service$LazyIterator.next(Unknown Source)
at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(Unknown Source)
at javax.imageio.spi.IIORegistry.<init>(Unknown Source)
at javax.imageio.spi.IIORegistry.getDefaultInstance(Unknown Source)
at javax.imageio.ImageIO.<clinit>(Unknown Source)
b.) ImageJ:
IJ.saveAs(image, "jpg", f);
java.lang.NoClassDefFoundError: Could not initialize class javax.imageio.ImageIO
at ij.plugin.JpegWriter.saveAsJpeg(JpegWriter.java:49)
at ij.plugin.JpegWriter.save(JpegWriter.java:28)
at ij.io.FileSaver.saveAsJpeg(FileSaver.java:340)
at ij.io.FileSaver.saveAsJpeg(FileSaver.java:332)
at ij.plugin.filter.Writer.run(Writer.java:24)
at ij.plugin.filter.PlugInFilterRunner.processOneImage(PlugInFilterRunner.java:256)
at ij.plugin.filter.PlugInFilterRunner.<init>(PlugInFilterRunner.java:105)
at ij.IJ.runPlugIn(IJ.java:158)
at ij.Executer.runCommand(Executer.java:127)
at ij.Executer.run(Executer.java:64)
at ij.IJ.run(IJ.java:249)
at ij.IJ.run(IJ.java:296)
at ij.IJ.saveAs(IJ.java:1579)
As #Victor says I think you should look at
Exception in thread "main" sun.misc.ServiceConfigurationError:
javax.imageio.spi.ImageWriterSpi:
Provider com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageWriterSpi
could not be instantiated: java.lang.IllegalArgumentException: vendorName == null!
I had this issue just yesterday and it was tricky. There are similar questions here. I found if I included jai_imageio in the jar and did not modify the manifest file to include the contents of the JAI manifest file or combine the files in the services folder of META-INF in your build then I had a number of errors similar to yours. My application did work though without JAI included since JAI was installed locally I opted to build it with JAI included for the time being.
Opening you jar you will find a directory called META-INF. In there is the file MANIFEST.MF. I use Maven to include the JAI things in the Manifest file so it looks like
Manifest-Version: 1.0
Implementation-Title: com.sun.media.imageio
Implementation-Version: 1.0_01
Built-By: myName
Specification-Vendor: Sun Microsystems, Inc.
Created-By: Apache Maven
Implementation-Vendor: Sun Microsystems, Inc.
Build-Jdk: 1.6.0_43
Specification-Title: Java Advanced Imaging Image I/O Tools
Specification-Version: 1.0-mr
Extension-Name: com.sun.media.imageio
Main-Class: myMain
Archiver-Version: Plexus Archiver
You should have your name and your main class substituted in there. You could just modify this file and jar it up yourself on the command line if you don't use Maven (or Ant) to get it working. I had the extra issue where some of my included jars were overwritting files in the services folder of META-INF. Instead I merged these files using Maven's Shade plugin.
add this lines into build.xml (solved for me)
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Built-Date" value="${TODAY}" />
<attribute name="Implementation-Title" value="MyApp" />
<attribute name="Implementation-Vendor" value="MyCompany" />
<attribute name="Implementation-Version" value="${version.num}-b${build.number}"/>
</manifest>

jws application can't load swing-layout

I have an old application that use swing-layout and i have to make it usable via java webstart . It runs fine from netbeans but if I launch it using jws I got this error :
exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/jdesktop/layout/GroupLayout$Group
at Gui.Accueil.jMenuItemConsPHActionPerformed(Accueil.java:2331)
.....
Caused by: java.lang.ClassNotFoundException: org.jdesktop.layout.GroupLayout$Group
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at com.sun.jnlp.JNLPClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 41 more
I have tried to add swing-layout in the jnlp file but I get this error when I run it :
com.sun.deploy.net.FailedDownloadException: Impossible de charger la ressource : http://my_url:8080/___JWSappclient/___app/test/lib/swing-layout-1.0.4.jar
this the jnlp :
<jnlp spec="1.0+" codebase="" href="">
<information>
<title>test </title>
</information>
<eligible>True</eligible>
<security>
<all-permissions/>
</security>
<resources>
<jar href="./lib/swing-layout-1.0.4.jar"/>
</resources>
</jnlp>
Thanks .
First edit :
I have removed and tried with many path but it's almost the same error com.sun.deploy.net.FailedDownloadException: Impossible de charger la ressource : http://url/___JWSappclient/___app/test/lib/swing-layout-1.0.4.jar
I tried to change swing-layout name to sl.jar but it didn't help .
What I dont understand is why jws try to download the swing-layout.jar from the server ?
The element <eligible> does not appear in the JNLP File Syntax, and your file is malformed as shown. In your previous question on this topic, you mentioned needing to support Java 6. To support Java 5, specify it in <resources>. The JAR containing org.jdesktop.layout.GroupLayout appears correct, but the path is suspicious. Try something like this:
<resources>
<j2se version="1.5+" />
<jar href="lib/swing-layout-1.0.4.jar"/>
</resources>
Addendum: I don't understand why JWS tries to download the swing-layout.jar from the server.
The JNLP client downloads all JARs from the server via HTTP. Each JAR must be accessible using the relative path specified in the href attribute. In particular, the directory containing your application JAR and JNLP file must also have a lib directory containing the layout JAR.
test/
application.jnlp
application.jar
lib/
swing-layout-1.0.4.jar

Log4jConfigListener cannot be found -- context fails to start

I am trying to set up a web application on Eclipse. I am using Tomcat 6.0 and jdk 1.6.0_23.
For some reason I am getting this error:
SEVERE: Error configuring application listener of class org.springframework.web.util.Log4jConfigListener
java.lang.ClassNotFoundException: org.springframework.web.util.Log4jConfigListener
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4078)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4630)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
at org.apache.catalina.core.StandardService.start(StandardService.java:519)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
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:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Jan 24, 2011 11:44:08 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4078)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4630)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
at org.apache.catalina.core.StandardService.start(StandardService.java:519)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
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:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
I checked if all libraries have been added to the build path and everything seems correct. log4j-1.2.15.jar is included and all the necessary spring libraries.
I am very confused as to what the problem especially because the project was working fine in another computer. Any help with this problem will be highly appreciated.
Naftal
Reticulogic's second suggestion is correct. However, in Eclipse Helios, the "Java EE Module Dependencies" option has been removed. The fix for Helios is as follows:
Right click on your project in Eclipse and go to Properties-->Deployment Assembly
Click "Add..."
Select "Java Build Path Entries" and click "Next"
select "Maven Dependencies" and click "Finish"
The org.springframework.web.util.Log4jConfigListener class is definitely not in your classpath.
The first thing I would suggest is that you turn up the logging level in Tomcat -- in the conf folder -- to "ALL" or "DEBUG" so that you can see exactly what is going on in the container that is preventing this class from being found.
Second, I'd recommend you check your JAR files for the missing class file by running grep, if on linux/mac:
# run at the root of your lib folders:
grep -ri "org.springframework.web.util.Log4jConfigListener" *
The above command will return all JAR files that contain that package. Once the JAR file is isolated, then you can further troubleshoot.
Third, make sure you don't have any conflicts. Multiple versions of Log4j being in your classpath will wreak havoc. How is the system supposed to know which org.springframework.web.util.Log4jConfigListener package to load if there are 2 of them? Tomcat has 3 different classpath folders:
shared/lib
lib
webapps/yourapp/WEB-INF/lib
Make sure you have only one log4j JAR file in only one of these folders.
A simple solution is to clean the Tomcat directory in Eclipse. It worked for me.
If you are using maven and eclipse
1) Look in your web project .classpath file. If you have a classpath entry "org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER", then make sure the attribute is there as well.
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
2) If that does not work, then right click on your web project in eclipse and go to Properties-->JavaEE Module dependencies. Make sure the Maven Dependencies box is checked.
Then save, build deploy yada yada
Migrating to log4j2?
Don't forget to check your webapp/WEB-INF/web.xml (Web Application Deployment Descriptor) for extraneous Event Listener definitions.
If you use, log4j2, you can find these classes in
org.apache.logging.log4j.web.*
package.
As you can see from the class name org.springframework.web.util.Log4jConfigListener is part of spring framework.
And it was depricated since spring 4.2.1 . So check your spring version.

Categories

Resources