I have just written a java application to talk to a blood machine. And it posts its data to a web server using OAuth security and XML, and the application works great.
But now I need to distribute it to customers who have these machines. This program is in a .jar file and its also requires other .jar files which are in my project/dist folder.
During the execution it uses little .png files which are displayed as icons on the screen, that the user can click etc.
I want to some how wrap all of this together (including the images) and distribute them either by an installer or i can use a web server.
What is the best way to accomplish this, i tried to copy the .jar and the dist folder (as per the instructions that came out of netbeans) but when I run java -jar myfile.jar it prints out the text i had from the IOException because i have not included the .png files.
Code for the PNG files:
Im using this:
try
{
databaseimage = ImageIO.read(new File("image/database.png"));
databaseDisconnectedImage = ImageIO.read(new File("image/database_delete.png"));
}
catch (IOException ioe)
{
System.out.println("Problem Creating Systray: "+ioe.getMessage()+" Current Working Directory is: "+System.getProperty("user.dir"));
}
You have a number of alternatives including the following:
Build an installer that installs the relevant files on the user's machine. You can either write it from scratch or use a commercial or open-source tool to create the installer. (Installing on multiple operating system types gets complicated ...)
Restructure your application so that all resources (e.g. images) are fetched via the classpath rather than directly from the file system. Then create an executable "Uber-JAR", by exploding all of the dependent JARs and resources, assembling the files into one tree, and JAR-ing the tree. (The JAR is made executable by adding a couple of entries to the manifest.)
Create a JNLP launcher for the application. This only works if the end-user is going to be able to access the website that hosts the application files, but it neatly solves the problems of updating the application, and ensuring that the user is using an up-to-date JVM.
Which is best? Each alternative has pros and cons, and you will need to work out which is best for you.
Heavy-hitting solution is to use Maven and create an executable jar, a.k.a. an assembly, a.k.a. a jar-with-dependencies. A jar can contain both its dependencies and the meta-data to run it properly.
java -jar Client-1.0-SNAPSHOT-jar-with-dependencies.jar
Would work. I assume there's a similar solution using Ant, which is another tool to build Java programs.
More manually: Just think for a second - whatever command including the classpath you use to run your program, make sure to save that into a script. All files that it needs bundle it up into a .zip and send that over, with the instructions to unzip and cd into it. Ultimately you're just running a bunch of files, you just need to send them over and preserve directory structure so your script will work.
Related
I'm re-using a standalone Swing-based Java class which backs up and restores mysql databases.
I've tested running it from a Windows batch file (.bat) on my dev system, and it works there.
But, if I run the batch file on a different Windows , I get a "main class not found" exception.
However, when I run the command directly on the command line, it works.
The command in the batch file to run it is:
java -cp lda-services.jar;bip-services-1.6.0.0-SNAPSHOT.jar;decryptor-1.6.0.0-SNAPSHOT.jar;slf4j-api-1.7.31.jar;commons-io-2.6.jar com.ilcore.util.SosaMaintenanceJFrame
The SosaMaintenanceJFrame class is contained in the lda-services jar.
Here's the error message:
Error: Could not find or load main class com.ilcore.util.SosaMaintenanceJFrame
Caused by: java.lang.ClassNotFoundException: com.ilcore.util.SosaMaintenanceJFrame
The class is definitely in the jar file, as I've extracted it the file and seen it.
Any thoughts on why this would be happening? I need to run inside a batch file so the user can just click on it to run it.
Most likely explanation
Your paths are relative, which means that the batch file isn't going to work unless you run it from the right place. In general, having a batch file that has an invisible rider stapled to it with: "I break in mysterious ways if not run from the appropriate dir" is a crappy batch file - make it better.
Better solution
Or, even better, get rid of it. You don't need batch files to distribute java programs.
Proper ways to distribute java programs:
The modern take is very very different from what you have here: JREs are dead, you must ship an installer that does the whole thing, notably including a java runtime (no longer called a JRE, and one you ship and keep up to date if relevant). That's perhaps a bridge too far for what you're doing here. Relevant tools include jlink.
A slightly less modern take involves jars with manifests:
Your jar file should contain a manifest. This manifest must contain 2 relevant entries:
Class-Path: lda-services.jar bip-services-1.6.0.0-SNAPSHOT.jar decryptor-1.6.0.0-SNAPSHOT.jar slf4j-api-1.7.31.jar commons-io-2.6.jar
and
Main-Class: com.ilcore.util.SosaMaintenanceJFrame
You can use jar's -m switch, or just include the manifest (it's just a file in the jar): it's at META_INF/MANIFEST.MF and it's a text file, each line is an entry, and an entry consists of a key: value pair.
When a jar contains this, just double clicking the jar and running java -jar thejar.jar will then take care of it all: Java will load the stated jars as part of the classpath, and these, crucially, are resolved as paths relative to the directory the jar is in, so it DOES work when you try to launch them from elsewhere, i.e. if you do:
C:
CD \
java -jar "c:\Program Files\MyApp\myapp.jar"
it works fine, whereas that batch script would fail due to being in the wrong place.
Build systems let you define the manifest too, check your build systems docs for how to do this, it'll be easy, and there are tons of tutorials if you search the web for e.g. 'manifest executable jar maven' or whatnot.
You can consider making a shaded jar. But I wouldn't.
A shaded jar takes all your dependencies and packs them into your main jar, so that there is only one jar. There is now no need for a Class-Path entry (the jar you run is obviously already on the classpath and there's nothing else to include) and your app is shipped as 'just' a single jar file.
But this is mostly a red herring: There are no consumer JREs anymore so you've made the user experience from a D- to a D. If you actually care about giving your users a nice experience, there's no getting around an installation process of some sort and once you have that, having the separate jars is no longer a problem. Separate jars are less hairy when signed jars are involved, are much easier to keep up to date, and have a significantly faster turnaround (when you build your stuff and want to ship what you built, shading takes ages, so it's nice to cut that step out). The faster your CI system tells you about failing tests, the better.
Meet in the middle
You don't have to upgrade to modules and the like. What you can do instead is use something like launch4j. The aim is to end up with a zip file along with the installation instructions: Make a dir somewhere. unzip this zip in it. Doubleclick 'myapp.exe'. Done.
The zip would contain an entire JRE, all your jar file deps, and your main app, and an exe file which launch4j made for you, that launches your app using the JRE packed into the jar. This means you know exactly which JRE is being used, and it'll work even on systems that didn't have one installed yet (which, these days, should be all of them - the notion of 'end user downloads a JRE from oracle and the user + oracle work together to keep that thing up to date and security-issue-free', is dead).
The fact that it's an EXE is nice: Now if the user e.g. alt+tabs through their apps, they get your app, with your name, and your icon, instead of 'javaw.exe' with an ugly coffee mug logo.
But when I try running it from the jar file generated by Maven, however, I get a "class not found" exception.
Even if you didn't get that error, you'd get another one unless you'd used Maven Shade, as that's the only way you're going to run that with a single jar. My guess as to why that particular error occurs is that the app class you're attempting to run is in fact in one of the *SNAPSHOT* jars
I have written a quick Java wrapper that fires off the NMAP executable and waits for it to finish. I am using Eclipse. I would like to include the NMAP source/executable
in my Java jar file so that I have a self-contained package.
Within Eclipse I have added the NMAP folder hierarchy. Within Eclipse I can see Java firing off the NMAP utility correctly, and waiting for the utility to end before exiting.
So far, so good. I then export a JAR file for with eclipse. I can see the NMAP folder hierarchy present. However when I try to run the JAR file it is having trouble finding nmap.exe. Can a foreign executable be called from with a jar file? if not, what are
my options? If so, why can't it find it within the jar file when it could find it within Eclipse?
Thanks.
You will need extract the .exe and its required support files onto the disk before you can access them as regular files (which execution through standard methods requires, I believe). You can look up examples of how to copy a resource from a jar to a file using getResourceAsStream() on one of your class files in the jar.
Once extracted, you can execute is as you are doing now (you might need to ensure execution rights, etc. based on your OS)
The "execute native program" facility does not understand how to invoke EXE-files inside other files (like ZIP or JAR).
If you want to do this, you must extract the files to a file system location and invoke it there. Due to the diversity of Linux distributions (PowerPC? other library versions etc) you should probably ask the user to install it instead and invoke that instead of bringing your own.
To my knowledge, you cannot execute an executable embedded in a jar file.
One solution would be to embed the executable in the jar file. Then use getClass().getResourceAsStream("/path/to/executable") to retrieve the bytes and output them to a temporary file (File.createTempFile()). On UN*X system, you will have to chmod u+x file before trying to execute. Eventually, you could delete the temp file or create the file once and reuse it everytime and call deleteOnExit().
Of course, this solution implies that you have executable(s) that work on all platforms.
Your solution probably works in eclipse because your "executable" file is not in a jar.
You may also have to be careful of how you are distributing this because Nmap isn't free for use in commercial software.
There is an open source library for Java to call Nmap but it assumes that Nmap is installed on the OS on which you are running your code. That API is Nmap4j and it is on sourceforge.net.
Is there a workaround or a solution to having to place the javax.comm.properties file and the win32com.dll file in their respective folders?
My program works fine when I have the files stored as below:
%JAVA_HOME%/jre/lib/ext/comm.jar
%JAVA_HOME%/bin/win32com.dll
%JAVA_HOME%/lib/javax.comm.properties
This worked well until IT changed the permissions on our computers so that we can no longer write to these folders. I'd like to be able to install the Java program I wrote that uses the serial port once without needing to re-install it every time IT decides to update our JVMs. Does anyone know of a way to do this?
It's always a good practice to decouple the execution of your application from the configuration of the machine it is running on. In your case the first task will be identifying where you want to store the extra libraries and configuration files that are needed (its probably best to bundle them with your application). Once that is done, then you can configure your application to find them at launch:
Assuming the following directory tree:
myapp
|
--lib (archives and shared libraries stored here)
|
--resources (configuration files go here)
You could do:
java -Xbootclasspath/a:myapp/lib/comm.jar -cp "myapp/lib/*:myapp/resources" -Djava.library.path="myapp/lib"
Your JAR and DLL files would go into the lib sub-folder, and the property file would go into the resources subfolder.
I have a Java application installed. The jar is bundled into an .exe file using Launch4J. Now I want to create a patch for this application.
If I create another jar containing only updated files, how can I refer it in the original code?
I have java application installed. ..Now I want to create a patch for this application.
This is one of the strengths of the Java Web Start launch technology that comes with the J2SE. Simply update the Jar on the server, and the next time the app. launches, it will be updated.
The update can be honed for your use-case, configured to be done lazily or eagerly, before or after launch, or even programatically controlled using the JNLP API's DownloadService.
..And the jar is bundlled into an .exe file ..
'Unfortunately', JWS works on Windows, ..and Mac., and *nix - so you may have to expand your horizons.
BTW - I have no idea how to do the same with Launch4J, but then, that is really the wrong question. I aim to provide an answer to the right question, which is "How do I deploy & update a Java rich client?". ;)
I've never worked with Launch4J, however I think you should try to affect the classpath. JRE always loads the classes from the classpath. From this point of view, jars have no added value and just serve as a containers for your *.class files and resources.
Now, if you succeed to configure your tool to do something like:
classpath = C:\Temp\my_patch_path;$your_current_classpath
then its enough to put your changed files into C:\Temp\my_patch_path (of course preserving the package structure). JRE will load your classes first in this case.
Hope, this helps
Mark
It is might not be possible to do this without changing the contents of the exe.
I want to evaluate a software solution where multiple people have submitted JAR files to perform a task on Windows.
Is it possible to check whether the JAR file performs any additional unwanted behaviors besides those it claims to perform on your machine?
First, you can use a JVM set with SecurityManager to do run your application in a way that it can have limited access to sensitive functions.
You can also set up a "sandbox" so the jar cannot have permissions outside of the sandbox... you could use chroot or a similar tool in a linux/unix environment.
1. You could use software from Sysinternals:
http://technet.microsoft.com/en-us/sysinternals/bb842062
You can see is program's writing or deleting something from hard drive with HardMon, or monitor any changes with RegMon... Check out their website, they have much programs and you can monitor practically everything!
2. Or you could install Sandboxie:
http://www.sandboxie.com/
and then run you program within sandbox ("virtual filesystem"). When you run a program inside of sandbox, you can see what files did the program make, and the best thing is that any changes that the program did will be undone when it exists, so it can't harm your system. :)
3. Also, you could try to decompile JAR file:
http://www.google.hr/search?sourceid=chrome&ie=UTF-8&q=java+decompiler
Yes and No. By default java programs can do the same things any native program on your system can do. This includes deleting and replacing any file it can access, depending on your operating system and your user privileges this may affect system critical files.
It is possible to restrict what java applications can do, applets and webstart programs usually are secured this way. Alternatively you can run any program as a different/restricted user or in a sandbox to limit the damage it can do.
If you do not trust the library/program always run it in one of the restricted environments mentioned above. It may crash if it does something it should not do, but it will be unable to do any damage.
I tried the solution from jensign.com and it looks like it restricts almost everything. The .jar application that I used to test wasn't even able to download a website. However I'm not an expert at this stuff so I can't tell if it is a 100% safe solution.
The JAR'd application can be launched under fully restrictive sandbox conditions (very similar to Java applet default security sandboxing):
java -jar -Djava.security.manager PropsFrame.jar
cite from jensign.com
Try a decompiler, like Java Decompiler:
http://jd.benow.ca/
It decompiles the .jar file, and shows you the source, though keep in mind it might be copyrighted:
By the way, why don't you ask for them to submit the source code as well, instead of just the .jar files?
Basically, .jar files are like souped-up zip files, and I believe even WinRAR can open .jar files. A quote from their site:
Java Archive File (a compressed file
for applets and related files) (.JAR)
Short for Java Archive, a file format
used to bundle all components required
by a Java applet. JAR files simplify
the downloading of applets since all
the components (.class files, images,
sounds, etc.) can be packaged into a
single file. Additionally, JAR
supports data compression, which
further decreases download times.
JAR file support is the same as ZIP
file support. JAR = ZIP + manifest.
The Microsoft VM supports uncompressed
and compressed JAR levels 0 and 1, but
not signed JAR.
WinRAR provides basic operations for
JAR files created by other tools: view
contents, extract files, show comments
and archive information.
You can use the convert function to
convert .jar files into .rar format.
You do not need to have any external
programs to handle these formats.
After extracting with WinRAR, you can view the source by following this link as an alternate method to JD.