How make working directory files available to WebStart application? - java

We have to make a Java application demo available on Internet using JWS. It goes pretty well; all that's missing is making working directory files available for the application.
We know about the getResource() way... The problem is that we have different plugins for the same application and each one require different files (and often different versions of the same files) in their working directory to work properly. So we just change the working directory when we want the application to have a different behavior.
Currently, the demo is packaged in a signed jar file and it loads correctly until it requires a file from the working directory. Obviously, the Internet users of this demo don't have the files ready. We need a way to make these files available to the WebStart application (read/write access) in its working directory.
We've thought of some things, like having the application download the files itself when it starts, or package them in the jar and extract them on startup.
Looking for advices and/or new ideas. I'll continue working on this... I'll update if I ever find something reliable.
Thank you very much!

I said I would share what I found in my research for something that would fit my needs. Here's what I have so far.
I have found that the concept of current working directory (CWD) does not really make sense in the context of a Java Web Start (JWS) application. This had for effect that I stopped trying to find the CWD of a JWS and started looking for other options.
I have found that (no, I didn't know that) you can refer (using getResource()) to a file in the root directory of a JAR file by simply adding a '/' in front of its name. ("/log4j.properties", for example.) The impact of this is that I can now take any file which is only referred to in a read-only manner in the root of that JAR file (which is really only a ZIP file). You can refer to any file in the root of the JAR file using AnyClass.class.getResourceAsStream. That rules out the problem with read-only files required to run the application, at the cost of a switch in the code telling whether the application is run from a valid CWD or from a JWS context. (You can very simply set a property in the JNLP file of the JWS application and check if that property is set or not to know where to look for the file.)
For write-only files (log files in my case), I used the property , adding a directory with the name of the application: <user.home>/.appname and added log files to it.
Read/write files (which I don't have in my case) would probably simply go at the same place than write-only files. The software could deal with uploading them somewhere if needed, once modified, I guess.
That's the way I deal with the problem for now.

Note there is a service you can explicitly ask for, to get file access to the computer (unless you go all the way and ask for full access (which requires signed jar files)).
Then you need to determine where these files need to go - basically you have no idea what is where and whether you may actually write anywhere. You can create tmp-files but those go away.
Would a file system abstraction talking to the JNLP-server do so you store the users data on the server?

Related

Read a file from same folder as JAR file but still read resources folder when loading from IDE

I've been trying to make jar application that can read a csv file in the same directory as it. This is, however, proving difficult as my means for accessing the file currently is:
InputStream is = getClass().getClassLoader().getResourceAsStream(filename);
Which works for my program running in the IDE and for my tests but doesn't work when I run the program from the compiled jar file. I have no idea how to get it to work for both. I seriously can't understand this path stuff, it seems like there are a million ways to do it and only one of them work for only one specific scenario.
I've been trying to make jar application that can read a csv file in the same directory as it.
Ah, there's your problem. That just isn't a thing.
There are only 2 types of files:
Application Resources
These are read only, and are as much part of your app as your class files are. It is not in any way relevant to think about 'editing' them - that's not the kind of thing they are. It is reasonable to assume that if this resource is somehow missing, the app is as corrupt / misinstalled as it would be if class files are missing.
For this, you use .getResource and .getResourceAsStream. And note that getClass().getClassLoader() is wrong, you want MyClass.class.getResource and then add a slash if you want to go from root (because getClass() potentially breaks when you subclass, and going via classloader is [A] just typing for no reason, and [B] breaks in bootload scenarios. MyOwnClassName.class.getResource never breaks, so, always use that).
This asks java to look in the same place class files are and nowhere else. Your class files are inside the jar files, and not next to them, therefore, it won't find a text file that is sitting next to jar files.
it does not make sense that it does work during development: That means you shoved a file inside the resources folder, which is equivalent to having a CSV file inside the jar file. You must have gone out of your way to tell your build system to do weird things. Don't do that.
If that CSV file is not intended to be user editable it should be inside the jar file and not next to it: That makes it an application resource. Examples of application resources:
You have a GUI, and you need to store the icon files and splash screen art and such someplace.
You ship static data with your app, such as a table of all US states along with the zipcodes they use (could be a text or csv file for example).
Templates of config files. Not config files themselves.
DLLs and the like that you need to unpack (because windows/linux/mac isn't going to look inside jars for them).
You're a webapp and you want to ship the HTML static files along with your webapp.
If this is what your CSV file is, the fix is to put it in the jar, not next to it, then load it with MyClass.class.getResource(name).
Config files and project files
For example:
For a rich text editor (like, say, LibreOffice Writer), the .odt files representing your writings.
Save games for a game.
A config file, which can be edited by the user, or is edited by your own app in a 'preferences' dialog. This stores for example whether to open the app full screen or not, or authentication info for a third party API you're using.
These should not be in the jar, should not be loaded with .getResource at all, and should not be in src/main/resources in the first place.
They also should not be next to your jar! That's an outdated and insecure model (the idea that editable files sit in the same place the app itself sits): A proper OS configuration means that an app cannot write to itself which is most easily accomplished by having it be incapable of writing to its directory. Some OSes (notably, windows) did this wrong for a while.
For example on windows, your app lives in C:\Program Files\MakorisAwesomeApp\makori.jar, and the data files for it live somewhere in C:\Users\UserThatInstalledIt\Documents\MakorisAwesomeApp.
oh linux, your app might be /usr/bin/makori and the data lives somewhere in the home dir. Config data might live in /etc/.
You don't "ship" your config files, you instead make installers that create them. You can do this part in-app by detecting that the relevant config file does not exist, load in a template (that is a resource, shipped inside your jar, loaded with getResource), and write it out, and tell the user to go look at it and edit it.
I really want a CSV file next to my jars!
Well, that's wrong, so, there are no libraries that make this easy. When you want to do silly things its good that APIs don't make that easy, right?
There are really hacky ways to do this. You can use .getResource to get a URL and then 'parse' this. This breaks the classloader abstraction concept (because in java, you can write your own classloaders and they can load from anywhere, not just files or entries in jars), but you can ask for 'yourself' (MyClass.class.getResource("MyClass.class")), pull the URL apart and figure out what's happening - does it start with file://? Then it is a file, so turn it into a j.i.File object, and go from there. Does it start with jar://? find the !, substring out the jar part, and now you know the jar. Make that a java.io.File, ask for the parent dir, and look there for the CSV.
You have to write all this. It's complicated code that is hard to test. You should not do this.

Where to put resources while making jar for Swing desktop application?

I wanted to know where should I keep my resources like I am displaying some images, playing some media files while making executable jar? Should I include it in executable jar or I should keep outside the executable jar?
If I keep the resources outside the jar what URL location URL should I pass in my program to access the images?
Actually the problem is I want to make distributable copy of my jar file.
If I give location of my local system for accessing the images and media files it will work in my system but what when I distribute it in other systems?
It depends on your application.
You can pack resources into the jar. Typically it is good for resources that are never changed: company logo, icons etc. You can read them using getClass().getResourceAsStream().
Other solution is to download the files from server (e.g. over HTTP). This solution is good for media that you do not want to pack together with application. For example video clip you want to play to user. Or, probably localized icons from the previous example or localized messages for multi-lingual applications.
The resources that you are downloading can be cached. You can use User's temporary directory (System.getProperty("java.io.tmpdir")) or sometimes using preferences API.
This isn't a radical answer but you could, in essence, create a resources project for images, properties and the like (media even).
You can then add your resources project (henceforth referred to as "MyProjectWsResources") as a child to your code project (henceforth referred to as "MyProjectWsClient"). Since MyProjectWsResources is in MyProjectWsClient's build path, it makes referencing your resources easier. If you're unclear of what putting something in your project's build path entails, it's saying anything in MyProjectWsResources's src folder is in MyProjectWsClient when it goes to referencing for information (as long as you're not using absolute paths :))
Why go for the approach of multiple projects? IMO, it separates code from resources so you download resources and code separately and your clients need not download the resources projects repeatedly when there are updates to your code only (I feel updates to code are far more frequent as compared to updates to resources). Lesser server bandwidth (important if you're using Java WS or any other packaging/system which I now realize you probably aren't).. still, hope this helps :)
I want to make distributable copy of my jar file.
Fist I will address the only sentence in your question that was not a question.
A great way to distribute a Swing desktop application to multiple users from the click of a link on the net, is Java Web Start.
Deployment with JWS would mean the resources would need to be in a Jar. For best results with the 'auto updating' nature of JWS, the Jar(s) for media would be:
referenced from a separate, sand-boxed, extension so they can be shared with other applications, and loaded/updated separately and lazily (as needed).
Compression:
uncompressed, for video, sound and image
compressed for textual information (HTML, RTF, CSV..)
Put in a path in the Jar that is known to the application. (e.g. /resources/video/vidNNN.mp4)
Resources in Jars are an embedded-resource and must be accessed by URL (or InputStream as mentioned by Alex, but URL is more robust). Quoting the info. page.
URL urlToResource = this.getClass().getResource("/path/to/the.resource");
During development, it is generally best to arrange a build that assembles the resources in the same way the end user will get them - to build the app. each run.
In other cases you might want to leave the resources at a public location on the server and access them as needed, but this effectively makes the server necessary for running the media related parts of the app. It seems your resources are both static (user does not change them) and an 'application resource'.

Java - where to put application data?

I'm writing a Java application which requires a number of resource files (there will be about 100 files of 20-40K each). They are not edited by the user, but will require periodic updates (the application will have a function to check for changes to the resource files and download them). Ideally, the application should be cross-platform.
Allowing write access to a subdirectory of the program directory is generally frowned upon. If I was doing it as a Windows application I might put them in Application Data, but that's not going to fly cross-platform. What would be the best place to put them?
I would typically create a directory (name starting with a period ".") in user's home directory (System.getProperty("user.home") if I am not mistaken) and use that for application specific storage. Alternatively, you could take the directory name from user at the time of application installation.
Have a directory you use to keep these files in. Put that information in a properties configuration file. When you start up load the configuration file from your application install directory. From that properties file it tells you where to find your file directory. When your installer runs it can write out this configuration file for the platform you are installing on, and that can be OS specific.
Provide a configurable location, but default to a directory in the user's home directory, or in an OS-specific location.
You'll have to deal with this in a platform-specific way no matter what. You have a few options under OS X, though. For unix-like systems either a home directory, or perhaps something under /var.
That said, I don't believe a program managing its own data in its own directory is a bad thing; consider a program with an embedded database or similar. It's much more reliable to use an app home directory.

Problems with deployment, advice needed for a web-based java application

I have developed a command-line (read: no GUI) Java application which crunches through numbers based on a given dataset and a series of parameters; and spits out a series of HTML files as resultant reports. These reports hold a large amount of data in tables, so in order to give the users a easy and quick overview of the results, I utilized the JUNG2 library and created a nice graph.
Here's where it gets interesting; since I would like the graph to be interactive it should be deployed after the application has run and files are generated, whenever the user wants to view the reports. I decided to go with an applet based deployment, however I am not too happy with the current setup due to the following reasons:
I want to make the software as simple to use as possible (my users won't be tech-savvy, and even tech-intimidated in most cases). I would really like to distribute one JAR only, which forced me to put the applet with everything else it needs in a package in the same JAR as the main application.
The applet and the main application need to communicate the results, so I create a xML-based report which is used to hold information. As long as the files are on a local machine and are not moved around it all works fine. Unfortunately I also need the files to be moved around. A user should be able to take the "results" folder to a USB stick, go anywhere plug the stick to another computer and be able to use the report as he/she likes.
For the time being the applets are implemented with the following html code:
<applet code="package.myapp.visualization.GraphApplet.class"
codebase="file:/home/user/myApp"
archive="myApp-0.2.6-r28.jar"
width="750" height="750">
<param name=input value="results/test_name/results.fxml">
</applet>
As you can see this applet will not work if the parent folder is moved to another location.
As far as I know I have a couple of alternatives:
a) Change codebase to point to an URL on our webserver where I could put the jar file. This however creates the problem with permissions, as the applet will not be able to read the results file. Alternative is to upload the results file to the server when the user wants to visualize the graph, although I am not sure if that's a good option due to server security and also if it could be made so that upload happens automatically without bothering the user.
b) I can use a relative path on the codebase attribute, but then the whole folder hierarchy needs to be intact upon copy. This could be a last resort, if I cant come up with a better way to do it.
c) change the deployment method (would like to avoid this alternative to not spend more time on the development phase)
Any ideas? Am I missing something? How could I tackle this problem?
Thanks,
I'm not sure I entirely understand your use-case, but from what I do understand, I would suggest this:
Dump the applet for an application launched using Java Web Start. Have the JNLP file declare a file association for the fxml file type. When the user double clicks an fxml file, it will be passed as an argument to the main(String[]) of the JWS application.
A sand-boxed JWS application can gain access to resources on the local file system using the JNLP API. Here is my demo. of the JNLP API file services.

Load jar file locally

Let's say I have a jar file and I want users to load it locally from the Internet... to speed up the loading I say... how would I go about doing that?
Like when you access it from http://mydomain.com... the jar file is from my documents/game/test.jar
Look up the URLClassLoader class, I think it will do what you want.
Here is a good description:
http://java.sun.com/developer/technicalArticles/Networking/classloaders/
EDIT: Forget it, Unsigned Applets cannot create ClassLoaders.
For an Applet you will need to download everything at once.
It is exactly the purpose of JNLP files (also called "Java Web Start"). Or I have misunderstood your problem...
You can find the official documentation on Oracle website : http://download.oracle.com/javase/1.5.0/docs/guide/javaws/developersguide/syntax.html
An example famous application using this system : SweetHome3D
I'm not sure if I understand your question, but it sounds like you want Java Web Start.
http://download.oracle.com/javase/tutorial/deployment/webstart/index.html
You would create a jnlp file, and put a link to it on your website. Java will take care of downloading the file and starting it. The .jar file would be stored in a cache, and it shouldn't need to be redownloaded unless the cache is cleared or you replace your old .jar file with a new one.

Categories

Resources