3

I have an application that I'm deploying with Java Web Start. When I was doing unit testing, I noticed a slight problem: whenever my application is run with Java Web Start, a particular operation takes a long time to execute. When run locally, however, it is quite fast.

The particular operation I'm talking about is reading in a large (5k row) Excel file to parse it. This is the line of code:

Workbook wb = WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));

To figure out the problem, I added a way to record the time:

long time1 = System.currentTimeMillis();
Workbook wb = WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));
long time2 = System.currentTimeMillis();
long diff = time2 - time1;
double seconds = (double)diff / (double)1000;
DecimalFormat df = new DecimalFormat("#,##0.00");
System.out.println("Elapsed Time: " + df.format(seconds) + " seconds.");

And this is the ouput:

(local)

Elapsed Time: 4.83 seconds.

(Java Web Start)

Elapsed Time: 35.52 seconds.

BUT THEN, an immediate subsequent run (on Java Web Start) yields this:

Elapsed Time: 1.61 seconds.

My suspicion is that this has to do with the POI library (in particular, the size of the library required to read POI, more specifically, the 13 MB ooxml-schemas-1.0.jar library file). So, my question is: assuming it is the library size, is there any way to prevent this? I have library caching turned on through the control panel, so why does it seem to need to be caching the library? Once it is loaded, it's fast. But it takes forever the first time.

Here's an image of the control panel showing that I am allowing it to store the libraries: enter image description here

Has anyone seen this kind of behavior before? No SSCCE because... well, how do you post an SSCCE with a Java Web Start question?

ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • See also: http://stackoverflow.com/questions/23330156/apache-poi-excel-workbook-creation-taking-a-long-time – Kolban Nov 06 '14 at 15:48

4 Answers4

1

In light of any profiling results, you should critically review the <resources/> attributes specified in the <j2se/> element of your .jnlp and compare them to those in your development environment. In particular, look at those affecting performance, such as heap size and VM type:

<resources>
    <j2se
        version="1.6+"
        initial-heap-size="128m"
        max-heap-size="256m"
        java-vm-args="-server"/>
    …
</resources>
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • All my j2se tag says is ``. I didn't think I'd need any manual resizing of the heap size. This is a very (very) small, lightweight app. It has only one frame. – ryvantage Oct 13 '13 at 12:18
  • Are there any disparities among the settings when you compare the two environments? – trashgod Oct 13 '13 at 16:23
  • Nope I don't add any args to the command line or specify anything in particular. I develop & run through Netbeans when unit testing, so unless unbeknownst to me Netbeans `run` is different from command-line `java myjar.jar`.... – ryvantage Oct 13 '13 at 16:57
  • Using `javaws`, launch a `.jnlp` aimed at your JAR; attach the NetBeans profiler to see what's going on.. – trashgod Oct 13 '13 at 20:11
1

I can see two things that won't be helping. Not sure if they'll account for the full difference, but at least some...

First up, the line

WorkbookFactory.create(new FileInputStream(new File(inputFile.getText())));

You had a perfectly good file object, now you're wasting a load of time and resources buffering it all into memory. As quite clearly explained in the POI documentation, if you have a File, use it directly! You'll save time and memory switching that (as shown in the docs) to:

WorkbookFactory.create(new File(inputFile.getText()));

.

Secondly, from the POI components page:

poi-ooxml requires poi-ooxml-schemas. This is a substantially smaller version of the ooxml-schemas jar ... The larger ooxml-schemas jar is normally only required for development

So, unless you have some very special needs, switch out the complete ooxml-schemas jar for the much much smaller poi-ooxml-schemas jar, which will cover you for all the common use cases. That'll make your loading much quicker too.

Gagravarr
  • 47,320
  • 10
  • 111
  • 156
  • True, but does not explain the webstart-vs-local time difference – finnw Oct 13 '13 at 10:45
  • I spent a lot of time configuring the POI libraries for this app. Don't ask me why, but the `poi-ooxml-schemas` jar didn't work. The whole thing was quite confusing and took me forever to figure out, but now it works. But yeah, the small library didn't work. – ryvantage Oct 13 '13 at 12:24
  • Also, `WorkbookFactory.create(new File(inputFile.getText()));` throws a compiler error, there is no method for `WorkbookFactory.create(File file)`. Not sure why they would include that in their docs?? That's the only reason I used a `FileInputStream`. – ryvantage Oct 13 '13 at 12:27
  • 1
    Sounds like you're using an ancient version of POI then. Upgrade to the latest version, and most likely both will work properly! – Gagravarr Oct 13 '13 at 15:28
  • Hmm... Indeed it is POI 3.5, but that's because I couldn't get 3.9 to work. The round peg went through the square hole LOL :) – ryvantage Oct 13 '13 at 16:47
  • Try 3.10 beta 2, that's the latest available. The [list of bug fixes since 3.5 is rather long](http://poi.apache.org/changes.html#3.5-final) so you'd gain a lot of fixes by upgrading! – Gagravarr Oct 13 '13 at 18:26
1

If you in your jnlp by mistake set the download attribute to lazy, you should state that you want to download this library eagerly

<resources>
        <jar download="eager" href="uploads/lib/guice-multibindings-3.0.jar"/>
</resources>

Which means they will be cached before application launches

By default, jar and nativelib resources will be downloaded eagerly, i.e., they are downloaded and available locally to the JVM running the application before the application is launched. The jar and nativelib elements also allow a resource to be specified as lazy. This means the resource does not have to be downloaded onto the client system before the application is launched.

from http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/syntax.html

Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74
  • The `download` preference is not stated in the .jnlp file, so `eager` is the default. Either way, I don't think it is downloading the library files each time. I think the problem is that it is taking forever to LOAD the libraries, not download them. – ryvantage Oct 13 '13 at 12:21
  • Yes, it is the default for jar-resource. But if it for example was a nested dependency inside another jnlp, it could help – Aksel Willgert Oct 13 '13 at 12:28
  • Nope, no other .jnlp files here. Just a simple Netbeans-generated launch.jnlp. Since j7u25 I've done away with `Component.jnlp` – ryvantage Oct 13 '13 at 12:29
  • Maybe check: http://stackoverflow.com/questions/5770807/java-webstart-slow-requesting-libraries-from-invalid-folder – Aksel Willgert Oct 13 '13 at 12:46
  • Wow. Definitely an interesting thread :) But yeah my .jars are indexed correctly. :) Looks like Netbeans fixed that bug. – ryvantage Oct 13 '13 at 13:07
1

I had a similar issue but with loading a .docx document (XWPFDocument) from a file. While doing it locally, it took under 1 second to load the file; however, doing it via Java Web Start it took around 35 seconds for me, and even half an hour for my colleague. Here's how I got it solved, hopefully it might solve this issue as well.

The culprit was the Apache XMLBeans library, or rather the incorrect way it has been used in Apache POI. The XMLBeans library included with the Apache POI release is version 2.3.0 and the jar file is xmlbeans-2.3.0.jar. If you include this in your classpath while launching a program locally, it'll work just fine. However, if you include it in your .jnlp file as a resource and launch your program with Web Start, it'll work really slowly as you explained. If you open the Java Console and set trace level to 5, you'll see that when you load the .docx file, the program will look for a resource xbean.jar even though you probably don't even have this in your .jnlp file. This will cause the program to look for the resource until it times out, and probably will try again many times, causing the slow loading time.

There's a bug report about this in the POI Bugzilla from 2011 (Bug 51660).

I solved this by downloading XMLBeans version 2.5.0 and instead of including the xmlbeans-2.3.0.jar I included the xbean.jar and jsr173_1.0_api.jar in the classpath and as resources in the .jnlp file.

Mxalis
  • 21
  • 2
  • Great answer. I will look into it later and see if it works. Still haven't resolved this problem. I'll let you know. – ryvantage Apr 23 '14 at 18:37
  • @Mxalis This looks like a great answer but I'm having trouble understanding the last setence. I can't find XMLBeans v2.5.0 to download. Do you (or anyone else) have a link to such? – Kolban Nov 07 '14 at 02:11
  • It seems like you can't download it from the XMLBeans project page anymore, but it's still hosted in the Apache archives at http://archive.apache.org/dist/xmlbeans/binaries/ (file xmlbeans-2.5.0.zip). The files you need to include at lib/xbean.jar and lib/jsr173_1.0_api.jar instead of the xmlbeans-2.3.0.jar – Mxalis Nov 10 '14 at 09:38