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.
Related
I am maintaining a Spring Boot project. There is this code:
BufferedReader reader = new BufferedReader(new FileReader("./setting_mail_sender.txt"));
Where should the file be located in this case?
In 'the current working directory'. And where is that? Who knows!
Whomever wrote that code messed up. It's not a good idea to use the CWD for anything in any java code unless you specifically know you want it. And generally, that's only the case when you're writing command line tools in the vein of the various tools you find in your average linux distro's /bin dir - a rare occurrence, given that the JVM isn't really designed for that kind of thing.
There are 3 different best practices for 'data files' depending on the nature of the data:
Static, unchanging data - as much part of your app as your class files are. These should be loaded with MyClass.class.getResource("name-of-resource.txt") and shipped the same way your classes are. For example, inside the jar file.
Config files. These should usually be in System.getProperty("user.home") - the user's home dir; /Users/yourusername on macs, /home/yourusername on linux, C:\Users\YourUserName on windows. Best practice is to ship a 'template' version of the settings file if relevant in the jar file, and upon detecting that there is no config file present at all, to write out the template (and you load the template in via MyClass.class.getResource). If a template is not a good idea, something in a similar vein. Bad practice is to have the installer do this, and have your app be broken or leave the user having to peruse complex documentation to (re)create the config file. A different way to do it right is to have a config page in your app (a window, menu bar setting, web app thing - something with a user interface) where you can change settings and the config file is simply the way you store that data.
Changing data files. For example, you ship H2 (an all-java database engine) with your app and it needs to write its database file somewhere. This is a bit tricky; user home is not the right place for such data files, but you can't really 'find' the dir where your app is installed either. Even if you can, on non-badly-designed OSes, apps usually cannot (and should not!) be able to write to that location anyway. The location where this data is stored should definitely be configurable, so one easy way out is to require that the user explicitly picks a place. Otherwise I'm afraid you're stuck having to write per-OS code - find /Users/myusername/Library/Application Support/yourappname on mac, which is the right place. As far as I know there is no library to do this right.
None of them involve 'require that the user start the app with the right CWD'. There are good reasons for that: It can be hard to configure, and it's not something users think of to configure. For example, when setting up a java app as a recurring task in windows, you can configure the working dir for such a process, but it's not something that's usually considered as crucial configuration. When running a java app from the command line, who knows what the working dir is. You'll end up with an app that usually works, except in some circumstances when it magically doesn't, and most of your users have no idea that the difference between the magic run that works and the one that does not, is the directory they were in when they started the java app.
If you can edit that code, do so - figure out which of the 3 different kinds of data this is about (sounds like the second bullet: Config stuff, so should be in user home, and the app's name should be part of the file name) - and fix it. for example, that should be:
try (var in = Files.newBufferedReader(Paths.get(System.getProperty("user.home"), "myapp-mail.conf")) {
}
This solves a whole bunch of problems:
Uses try-with to avoid resource leakage.
Reads from user.home, avoiding current working directory as relevant setting.
Actually uses UTF-8 encoding (whereas your code will, at least until java 17, do 'platform default'. It's somewhat unlikely you want that, as it means your config file is not portable; copying it from one computer to another may break things. You presumably don't want this.
If errors occur, the error messages are improved (one of the downsides of the 'old' file API).
If you can't change this code, figure out what the CWD is; put the files there, and ensure that, however you start this spring boot project, you always start it from that directory. If you can't change this code but you can run some code in that JVM, you can print it: System.out.println(Paths.get(".").toAbsolutePath()) will show it to you.
I'm making a game, in Java, that has these following important features:
1) Connects to a remote Server (which i made), and will check for updates and install them if necessary
2) is NOT A SINGLE .JAR FILE (ie. has multiple .jar's and other things, such as .png, .wav, etc)
3) JAVA WEB START IS NOT AN OPTION, AS I WANT TO MAKE THIS ALL MYSELF
keeping the things above in mind, i have run into a problem. i have no clue how to implement a multiple "patch" update system. currently i have 1 .txt file, that the server reads from, and sends the files listed in the .txt to the client, which then moves them into place. The problem is, that is only useful for maybe 2 updates. I'm looking for a more useful, long term solution, and i need some help. here are some of the things i've thought of:
1) have a zip folder named after each version (problem: how would the client get ALL of the most updated files
2) have a .txt file INSIDE of each jar containing the version (problem: cant do that with png's or wav's, and i dont know how i would read the txt file to begin with)
i really need some help, i've tried googling it, i've thought about it for going on 3 weeks now, and cannot think of anything.
QUESTION: how would i make a game/program update with multiple patches?
Firstly, the best solution by a long, long way is to use Webstart / JNLP.
But if you insist on not using it (for whatever reason then) then it is technically possible. However:
It is messy and complicated.
It will either be very inefficient ('cos you have to load the entire program each time the user), or the user has to trust you enough to install your program with permissions that will allow it to install random stuff on his machine without notice.
The way to do it is to split the game into a launcher part and an application part. The launcher needs permissions to write and delete (non-temporary) files, and fetch stuff from the internet. It "calls home" to find out the latest version(s) of the application files, and then downloads and installs them. It has to cope with all sorts of error conditions, and it needs to make sure that nothing can trick it into installing bad stuff on the user's machine, etcetera, is someone spoofs your update service.
Of course, JNLP takes care of all of this, and lots more besides. People are going to be more willing to install the JNLP infrastructure that yours ... which might be insecure, or actively nasty (for all they know). (I for one wouldn't install a self updating application on my machine unless it was supplied by a company with impeccable credentials.)
I think you need here JNLP framework.
JNLP provides followed things:
allows to user to download jars from server
on launch verifies if application need to update
runs on local JVM
Actually, every java application you can convert to JNLP. Just to sign on all jars that your game contains, create executable jar from your game and create single Web page from where you can download your game
Kind of hard to explain in one line but my problem is essentially like this:
I made a java applet that I want to run on a web page that I packaged into a .jar file. I'm able to get the applet working fine using the <applet> tag but the problem is, if the user views the page source, they will see:
<applet archive="directory/program.jar">
Assuming .jar files can be easily opened and all the class files decompiled, all the user would have to do is go to www.url.com/directory/program.jar to download my .jar and they would have all my source code :(
So I'm wondering if there is either a way to protect my code/jar from being decompiled (other than obfuscation) or to use some kind of server-side script to feed the contents of the .jar directly to the browser from a server-side location not publically visible.
Any help is appreciated.
This is fundamentally impossible.
Java applets run the client.
Anything that runs on the client can be disassembled and modified by a sufficiently advanced user.
You should move your sensitive logic to the server and invoke it using HTTP requests ( and remember that the user can use Fiddler).
While you're at it, you should probably replace your applet with HTML and Javascript.
Other than obfuscation or encryption, no--one way or the other, the browser will have access to the jar.
You might be able to create an applet that loads more functionality at runtime.
There is no effective way to block access to the source code of any page; for the page to be readable by browsers and search engines, the source code has to be accessible, and therefore can be viewed and/or copied. That's just how the web works. HTML is sent as a text document and interpreted client-side.
Disabling the right-click is little more than an annoyance, and it works sporadically in alternative browsers. Even if you succeed, the View Source option in the menu is always present. The viewer could also use a download tool such as Wget, or even get the page from the Google cache without visiting your site at all.
Edit: Oops! I misunderstood your question. You should follow #SLaks advice and "move your sensitive logic to the server and invoke ot using HTTP requests ( and remember that the user can use Fiddler)."
While quantum mechanics do rule the universe, they have less of a grip on your code than you might suspect. You cannot both deploy code to the client browser and not deploy code to the client browser. You have the option of doing one or the other.
You can prevent direct browsing to your .jar file by locating it beneath the WEB-INF directory in your WAR file. This will also prevent <applet archive="directory/program.jar"> from working.
Once the jar is beneath the WEB-INF directory you will need something to feed the resource to the client browser; the Spring resources servlet is good for this (If you are using Java and Spring). I feel confident that other such tools exist. With the Sprint resours servlet, your would deploy your applet with something like this: <applet archive="resource/program.jar".
If you write your own resource distributor, you can add security to make it harder to get the jar file; perhaps add a header to your requests like IRGud: <user_id here> and fail any request that does not have that header (or acceptable contents in the header).
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?
I need assistance finding a delivery method that best fulfills the following requirements:
We wish to deliver a single file to my clients.
Clients should be able to launch this file from the operating system shell - much like running an '.exe' on Windows.
After being launched, the program/script should be able to display a window with HTML content. this may be done using a stand alone program, a runtime or by running within a browser.
We need the ability to embed a resource within the delivered file, such as an mp3 file, which i can later extract programmatically.
Optimally, the solution should run on Windows, Mac and Linux machines. Less than perfect cross-platform interoperability is acceptable, but we want as broad a penetration as possible.
Clients should not need to pre-install anything (unless it is done transparently), pre-configure anything, or approve any thing for this to happen.
For example:
We could use a regular executable file, written in C++ to do this, but it will not be cross-platform.
We could use a sliverlight XAP file, an adobe Flex file or a Java JAR, but internet explorer warns users when local content is launched. In addition these approaches mean that we have less than perfect penetration, even though it is acceptable in these cases.
We could use a python (or equivalent) script, but the installed-base (penetration) of the python interpreter is not good enough.
Using a standard HTML is not enough because of the difficulty of embedding resources in it. Embedding Silverlight XAML or uuencoded content in HTML causes IE to display a warning.
Using something along the lines of a jpeg as a delivery method is not rich enough since we need to display HTML.
..but internet explorer warns users when local content is launched..
I don't get it, what's the problem with IE saying "Hey this app is trying to run your files!"
I don't mean you don't have a good reason for this, it is just, I don't get it.
IE will only warn the user if the app has not been downloaded and try to access local resources, for instance if running from an applet or a JNLP like this one:(click on the first orange button you see )
But if the users download the jar and run it from the computer ( double click on it ) the app is local and can run without problems.
The jar file is a zip file after all, so you can attach your mp3 file with it. Double click is supported in the desired platform, and the HTML content could be either a local file ( un-packed along with the mp3 file ) or an internet web page.
Java is preinstalled on those OS already.
"internet explorer warns users when local content is launched"
There's a reason for this. How can they distinguish your excellent, well-behaved, polite application from a virus?
Since the line between your app and a virus is very, very blurry, go with any of Silverlight XAP file, an adobe Flex file or a Java JAR.
The IE business is a good thing, not a bad thing.
You could try using the 'Jetty' application server.
This supposes there is a working java environment on the target machine.
Jetty is java servlet container but it is possible to configure
everything (web server, html templates, applications, etc.) in a
single executable jar, which launches the web server and opens a default page.
Exactly how the jar file is launched will vary from platform to platform
but otherwise the user interface will be identicle, and, as its a java application
you can do pretty much anything one it has started.
Sounds like MIME HTML does exactly what you want - unfortunately, it is not supported by many browsers other than IE.
I'd investigate Adobe AIR. It can display both HTML and Flex content in a desktop application without using a web browser. However this will require installation of the AIR runtime, also I'm not sure if the Linux version is out of the beta stage.
http://www.adobe.com/products/air/
You can also use a binary for each platform.
As per your description the app is very simple, and porting from one platf to another sounds like just matter of re-compile and offer binary based on the dist.
Is this an option?