I have a Swing/Java application that is being used for clients and has weekly updates.
The problem is the setup just lay out the classes and their respective directories and on the update I just update the classes.
I want to do a single jar containing all the classes, but I'm not sure how would I be able to update it...
Also some clients need some updates during the week where only one or two classes would be updated.
What is the right way of doing this ?
Im using Eclipse.
EDIT: I know how to create the jar, I just dont know how to dynamically update it.
I would suggest you look into Java WebStart which is designed to do exactly what you need.
You need to first create the finished deployment and then you can look into creating a JNLP file for the deployment, and a way to put all the files to a web server for the user to access. For now just let the user download the whole thing every time you update. When you get more experienced you can look into how you can make incremental updates.
I would strongly recommend including a build number or timestamp in the deployment paths so a jar file is not cached incorrectly in the client by accident.
The general way of doing this, even if only small changes were made, would be to repackage your JAR after each update and give that JAR to a user. The user would replace the existing JAR. How you produce your JAR is up to you. Many IDEs support it, you could write a shell script, use existing build systems like ant or maven or even make, whatever. (See edit below)
If your JAR is very large and deployment is cumbersome, you may be able to split your project into smaller subcomponents, each with their own JAR, and only redistribute the ones containing changes. That may or may not be a major refactoring for you, and it might not even be appropriate. For most small or average size projects, this is generally unnecessary.
As for deployment, there are also a zillion ways to make that easier on the user. You could just give them a JAR file. You could use e.g. install4j. You could use Java Web Start (although its kind of clunky). There are others.
Both install4j and JWS support automatically checking for updates. If you choose to support that feature, all you would need to do is update your distribution site, and users would receive updates automatically. That's also up to you.
But a short answer to your question is: If you have all of your classes packaged in a JAR, no matter how many classes change, you'll want to give the entire updated JAR to the user. The benefit that counters this cost is that a JAR is a nice, compressed, self-contained collection of your application/library's source, which makes management and deployment very convenient.
Edit: Responding to your edit where you specify that you are using Eclipse, Josh M gives you instructions in his comment on your answer. To add to his comment, to export a Runnable Jar you'll have to have a Run Configuration set up which, if you've been running your application in Eclipse already, you probably already have. If not you can create one in the Run menu.
Edit 2: Please refer to Thorbjørn Ravn Andersen's answer as well for some good JWS tips.
Related
I'm trying to make an addresslist in Java, which saves its contents in a Sqlite database.
Therefor (and for other future uses), I tried to create my own library for all kinds of database connections ("PentagonsDatabaseConnector-1.0.jar"). It currently supports Sqlite and MySql.
It references other libraries for them to provide the JDBC-drivers ("mysql-connector-java-8.0.16.jar" and "sqlite-jdbc-3.30.1.jar").
Problem: My Library works just fine if I'm accessing it from its own project folder, but as soon as I compile it and add it to the "Adressliste"-project, it isn't able to find the JDBC-drivers anymore (I can access the rest of my self-written library without problems though). Also, as shown in the screenshot, "PentagonsDatabaseConnector-1.0.jar" brings the JDBC-libraries with itself in "lib"-folder.
LINK TO THE SCREENSHOT
Do you guys have an idea whats wrong?
Thank you for your help!
Ps: Sorry for bad English, I'm German :)
Java cannot read jars-in-jars.
Dependencies come in a few flavours. In this case, PentagonsDC is a normal dependency; it must be there at runtime, and also be there at compile time.
The JDBC libraries are a bit special; they are runtime-only deps. You don't need them to be around at compile time. You want this, because JDBC libraries are, as a concept, pluggable.
Okay, so what do I do?
Use a build system to manage your dependencies is the answer 90%+ of java programmers go to, and what I recommend you do here. Particularly for someone starting out, I advise Maven. Here you'd just put in a text file the names of your dependencies and maven just takes care of it, at least at compile time.
For the runtime aspect, you have a few options. It depends on how your java app runs.
Some examples:
Manifest-based classpaths
You run your java application 'stand alone', as in, you wrote the psv main(String[]) method that starts the app and you distribute it everywhere it needs to run. In this case, the usual strategy is to have an installer (you need a JVM on the client to run your application and neither oracle nor any OS vendor supports maintaining a functioning JVM on end-user's systems anymore; it is now your job – this is unfortunately non-trivial), and given that you have that, you should deploy your jars such that they contain in the manifest (jars are zips, the manifest ends up at META-INF/MANIFEST.MF):
Main-Class: com.of.yourproj.Main
Class-Path: lib/sqlite-jdbc.jar lib/mysql-jdbc.jar lib/guava.jar
And then have a directory stucture like so:
C:\Program Files\yourapp\yourapp.jar
C:\Program Files\yourapp\lib\sqlite-jdbc.jar
C:\Program Files\yourapp\lib\mysql-jdbc.jar
Or the equivalent on any other OS. The classpath entries in the manifest are space separated and resolved relative to the dir that 'yourapp.jar' is in. Done this way, you can run yourapp.jar from anywhere and it along with all entries listed in Class-Path are now available to it.
Build tools can make this manifest for you.
Shading / Uberjars
Shading is the notion of packing everything into a single giant jar; not jars-in-jars, but unpack the contents of your dependency jars into the main app jar. This can be quite slow in the build (if you have a few hundred MB worth of deps, those need to be packed in and all class files need analysis for the shade rewrite, that's a lot of bits to process, so it always takes some time). The general idea behind shading is that deployment 'is as simple as transferring one jar file', but this is not actually practical, given that you can no longer assume that end users have a JVM installed, and even if they do, you cannot rely on it being properly up to date. I mention it here because you may hear this from others, but I wouldn't recommend it.
If you really do want to go for this, the only option is build systems: They have a plugin to do it; there is no command line tool that ships with java itself that can do this. There are also caveats about so-called 'signed jars' which cannot just be unpacked into a single uberjar.
App container
Not all java apps are standalone where you provide the main. If you're writing a web service, for example, you have no main at all; the framework does. Instead of a single entrypoint ('main' - the place where your code initially begins execution), web services have tons of entrypoints: One for every URL you want to respond to. The framework takes care of invoking them, and usually these frameworks have their own documentation and specs for how dependencies are loaded. Usually it is a matter of putting a jar in one place and its dependencies in a subdir named 'lib', or you build a so-called war file, but, really, so many web frameworks and so many options on how they do this. The good news is, usually its simple and the tutorial of said framework will cover it.
This advice applies to any 'app container' system; those are usually web frameworks, but there are non-web related frameworks that take care of launching your app.
Don't do these
Don't force your users to manually supply the -classpath option or mess with the CLASSPATH environment variable.
Don't try to write a custom classloader that loads jars-in-jars.
NB: Sqlite2 is rather complicated for java; it's not getting you many of the benefits that the 'lite' is supposed to bring you, as it is a native dependency. The simple, works everywhere solution in the java sphere is 'h2', which is written in all java, thus shipping the entire h2 engine as part of the java app is possible with zero native components.
I recently started developing a plugin, which consist of several Eclipse Plugin-Projects. I use Maven/Yycho as a build tool and GitHub as version control system.
Now I was wondering what to push to my GitHub repositories. The POM files and Feature/Updatesites as well? It seems that this stuff is:
very User specific (the path are relative to the file structure on my computer)
do other developers need that stuff or should I give them the freedom of choosing their own build tools?
To clarify, I have right now 6 Eclipse projects:
*.plugin1
*.plugin1.tests
*.plugin2
*.releng
*.feature
*.p2updatesite
Would it be good practise to share everything? From my feeling I would say I will only share plugin1+tests & item # 2 (without the pom files) so that everyone can take care themselves about building.
You don't have to add to your repo:
anything that can easily be regenerated
anything with local paths specific to a user
Regarding building, ideally you should version at least a script able to generate the right pom, in order for a new contributor to be able to get going as fast as possible after cloning it.
If you can have config files with only relative paths (instead of absolute one), then you can include those, for others to use.
See for instance ".classpath and .project - check into version control or not?".
I am very new to java and android development and to learn I am trying to start with an application to gather statistics and information like munin does. I am trying to be able to load "plugins" in my application. These plugins are already in the application but I don't want to have to invoke them all separately, but be able to iterate over them. I was trying to use serviceloader but could never get the META-INF/services into my apk. So I am wondering if it is possible to use serviceloader on android
Thanks
EDIT: I am asking about java.util.ServiceLoader, I think it should, but I can't figure out how to get my services folder into META-INF on the apk
There is an open bug report against this issue. See https://code.google.com/p/android/issues/detail?id=59658
The META-INF folder is deliberately excluded from the APK by ApkBuilder; the only comment in ApkBuilder.java is "we need to exclude some other folder (like /META-INF)" but there is no other explanation.
Even after adding META-INF with ant, you will still get in trouble if you want to use Proguard, which refuses to replace the content of META-INF/services/* files or rename them (that's another story, the author wants to keep Proguard agnostic).
However, people using maven may want to check https://github.com/pa314159/maven-android-plugin (the branch named "modified"), that tries to solve both issues. It is a fork from the original "android-maven-plugin" I modified one month ago for my own Android projects.
It also provides a patch for Proguard-4.7
Hope this helps, any feedback is welcome.
I've figured out a solution that may work for some situations. Instead of ServiceLoader, I'm using the org.openide.util.Lookup class / library that comes with NetBeans - it is a superset of ServiceLoader. It does not require NetBeans itself and seems to work ok with Eclipse. It is necessary to replace whatever ServiceLoader functionality you are using in your application with Lookup equivalents, and add the org-openide-util-lookup library. Then, you can just do something like this:
Lookup lookup = new ProxyLookup(Lookup.getDefault(),
Lookups.metaInfServices(myClass.getClassLoader(), "services/"));
And move your ServiceLoader files from META-INF/services/ to services/.
Note that, because of the ProxyLookup, this will continue to work on standard Java environments unchanged (i.e., in those cases it will continue to look in META-INF/services).
Here is a link to the documentation for the library: http://bits.netbeans.org/dev/javadoc/org-openide-util-lookup/org/openide/util/lookup/Lookups.html
UPDATE
After working with this for a couple of days, it seems to function well - I move between environments (standard Java and Android) and it works properly in each location. The primary downside is having to manually copy the files to the /services directory.
It is possible. You may want to check http://developer.android.com/reference/java/util/ServiceLoader.html
ServiceLoader is stuff from the Java language that is not really relevant on Android. I recommend not using it. If you just want to find a list of classes within your .apk to load, there are all kinds of ways to do this -- put in XMl file in res/xml that lists them, use reflection, annotations, etc.
I need to patch a system in production however I have already change the main trunck in CVS. Since there are a lot of changes I do not want to revert the code to a previous version as there is only one class involve.
Could this be done ?
Stop the application.
Safely replace a edited *.class into an existing jar.
Re-start the application.
Many Thanks
Unless the jars are signed by someone else, it can be done. Jar files are just zip files after all, you unzip them, replace the file and zip them up again. If the jars are signed and you have the key, you have to sign the new jar again. (The jar command is the preferred way to do this.)
However it's very bad practice to do this. Trust me, the amount of work you save now will be lost a hundredfold if this way of deploying becomes a habit. Unless there's a real crisis (your application doesn't even run or crashes every ten minutes for example), you should never ever do this.
If you use CVS, you should always tag your releases, but even if you haven't done that, you can check out the trunk as it was on the release date, create a branch from there, apply the change to the branch and rebuild your application.
It takes about ten minutes (plus compilation time) and it's a safe and proper method. You can launch the patched application in your test environment, test that it works and only deploy it afterwards.
Dropping a pre-compiled class file in an existing application can break the code in subtle ways that don't become apparent until several days later. Recompiling and retesting the application takes this risk away, leaving just the much smaller risk associated with any code change.
Yes, you very well can. make sure your new class compiles fine and then update the jar. jar -u is what you're looking for.
I'm trying to figure out the optimum way to develop and release a fairly simple web application, and I'm running into several problems. I'll outline the decisions I've made, because somewhere I've clearly gone off the rails.. Hugely grateful for any help!
I have what I think is a fairly simple web application. It contains a couple of jsps that reference a couple of java beans, and the usual static html, js, css and images.
Decision 1) I wanted to have a clear and clean release procedure, such that I could develop on my local machine and then release reliably to a production machine. I therefore made the decision to package the application into a war file (including all the static resources), to minimize the separate bits and pieces I would need to release. So far so good?
Decision 2) I wanted things on my local machine to be as similar as possible to the production environment. So in my html, for example, I may have a reference to a static file such as http://static.foo.com/file . To keep this code working seamlessly on dev and prod, I decided to put static.foo.com in my /etc/hosts when developing locally, so that all the urls work correctly without changing anything.
Decision 3) I decided to use eclipse and maven to give me a best practice environment for administering and building my project.
So I have a nice tight set up now, except that:
Every time I want to change anything in development, like one line in an html file, I have to rebuild the entire project and then wait for tomcat to load the war before I can see if it's what I wanted. So my questions are:
1) Is there a way to connect up eclipse and tomcat so that I don't have to rebuild the war each time? ie tomcat is looking straight at my actual workspace to serve up the static files?
2)I think I'm maybe making things harder by using /etc/hosts to reflect production urls - is there a better way that doesn't involve manually changing over urls (relative urls are fine of course, but where you have many subdomains, say one for static files and one for dynamic, you have to write out the full path, surely?)
3) Is this really best practice?? How do people set things up so that they balance the requirement for an automated, all-encompassing build process on the one hand, and the speed and flexibility to be able to develop javascript and html and css quickly, as quickly as if one just pointed apache at the directory and developed live? What do people find works?
Many thanks!
Edit: Thanks all for your great responses! If I could mark them all right, I would.. This has really helped me out. What I'm hearing is that best practice is to conserve the structure of the webapp in development, and run it in as close an environment to production as possible. Seems like the differences between people are the extent to which people are prepared to hot deploy resources into the servlet container, circumventing the build process for a little extra speed or convenience. That makes sense. Thanks again.
This is much like what I have to do at work, although we use ant (for now?). Also, while I use an IDE (or two), I refuse to have one as part of my build process, EVER. Somebody needs to be able to understand and tune your build.
Is there a way to connect up eclipse
and tomcat so that I don't have to
rebuild the war each time?
1) I think you're relying too much on your IDE. Usually I have an Ant build.xml that has a couple of tasks: one is "build war" the other is "update jsps." Building the war compiles all the code, packages it, deploys it to Tomcat and restarts everything. Updating the jsps doesn't restart the server, it's just a straight copy from my local files to Tomcat's deployed instance. No restart necessary since they're JSPs. Takes about half a second.
where you have many subdomains, say
one for static files and one for
dynamic, you have to write out the
full path, surely?
2) No way, Jose. So you mean any time the server name changes, you have to recompile your code? If you need to support dynamic URLs you might just want to bite the bullet and take a look at a framework to do the heavy lifting for you. I'm partial to Stripes (which supports dynamic URL rewriting out-of-the-box)... there are others.
To answer #1, I would suggest the following:
Spend some time learning maven to build your .war without eclipse. It's not that hard with the proper archetype. See here for more details: http://maven.apache.org/guides/mini/guide-webapp.html
Maven can generate eclipse projects either through mvn eclipse:eclipse or by using the m2 plugin
For deployment to your local machine and to production, use the maven cargo plugin. http://cargo.codehaus.org/Maven2+plugin and http://blank.jasonwhaley.com/2010/03/automated-deployment-with-cargo-drive.html
To answer question #2, there's nothing wrong with modifying your /etc/hosts file to mimic production. Just have a quick script that lets you add/remove those entries and flushes your dns cache. I do exactly that all of the time. (be sure to make your browser clear its cache frequently also through its relevant setting).
To answer question #3) yes this is how you should be doing things. Each build should result in a single deployable artifact that you can deploy to any of your environments in one step. You need to make sure you can do this without your IDE and use the IDE only as a tool to help you during the development phase.
Others have already answered you, I'll just comment on this (this too long for a comment btw so I make it an answer):
Every time I want to change anything
in development, like one line in an
html file, I have to rebuild the
entire project and then wait for
tomcat to load the war before I can
see if it's what I wanted.
If you change one line in an html file, there's no need to rebuild the entire project.
Note that I always rebuild the full .war and redeploy my .war but this takes less than two seconds (less than one second to rezip the .war [that's really what a .war is, a zipped file] and less than one second to redeploy it) because:
you don't need to recompile your entire project when you simply change one line in an html file
Same when you change one .java file: you can simply recompile that one file and re-war.
I wrote my own Ant build file from scratch (no Maven here) and I've got several targets. I can force a "clean build", that shall re-compile everything but typically I'm simply repackaging and redeploying the .war
You can check it for yourself: build a .war, unzip it in, say, directory dir1, then modify one .html (or one .java/.class file) and build a new .war and unzip that new .war in, say, dir2.
Then compare dir1 and dir2: now fix your build process so that you can create that second .war without needing to recompile everything.
Changing one .html, .java, .jsp, .css, .js / whatever file and redeploying a new .war should be a matter of seconds (less than two seconds if you didn't throw the kitchen sink in your Webapp).
Note that on the very same project, another developer here prefers to "hot deploy" / replace the files directly in the exploded webapp (I prefer to redeploy a .war everytime and because my complete repackage/redeploy takes less than two seconds I'm fine with it that way).
You don't need to reconstruct war file if your project is an Dynamic Web App in Eclipse and configured Tomcat server properly. Follow the below instructions:
1) Check out the below of how to configure tomcat server with eclipse:
http://greatwebguy.com/programming/eclipse/make-eclipse-and-tomcat-play-nice-together/
2) Use relative paths for your application but not absolute paths.
3) If you follow the above 2 steps properly then you have a best environment for development.
during development, you should configure eclipse and tomcat so that no rebuild/redeloy is required. just modify html/css/jsp etc, save, and refresh browser to see the result.
but before deploying to production site, you should do a clean full build and test it carefully.
domains: they should be in a config file; dev and prod should have different config files.