When distributing a Java application to others, it can be deployed as a JAR file for easy execution.
But is there a way to change a Java class / part of the code after deployment without having to rebundle the whole application again?
If you have an app with say 10 classes where 9 are finalized but one needs to be adjusted according to the individual case. What would be the easiest way to change just one class in an app?
Probably you want to use java web start. If your user starts application via java web start it is automatically being updated if updates are available.
EDIT
It does not provide class-based granularity, but I believe this is not the real issue. It however provides the jar-based granularity, i.e. the newer version of jar is being downloaded only if it was changed.
No, there's not.
You should repackage OR design the one that should be adjusted to be configurable at runtime. If you can modify it using a configuration database and factory that would be the only way to do it without repackaging.
In theory you could create another jar for the customized classes and put it into the classpath before the old jar, and the JVM will load the customized classes. But this is simply looking for trouble...
Better to build two jars, one with the non changing classes and another with the customized classes and rebuild the later when you need it.
Related
I am considering switching my applications existing WFS/WMS "SDK" to GeoServer. However my application has a few special requirements.
I must remain in control full of the applications entry point (main(...)).
I cannot introduce any additional interfaces (such as the GeoServer GUI).
Essentially my application just needs an SDK which exposes our data over an HTTP "/wfs" path. We need to avoid any other interfaces or code being added or exposed. This is unfortunately an unavoidable requirement. Also, until now I have little experience in the GeoServer source code as we have been using a different Toolset. I am of course combing through the source, but am having trouble finding the right classes to get started.
In our existing SDK, I am able to programmatically create a Jetty server with a WFS Servlet assigned to our desired path. One class is provided during the Servlet initialisation which handles communication between our code, and the Servlet.
In order to get a similar setup using GeoServer, I am assuming:
I must add org.geoserver.gs-wfs to my pom.xml dependencies
I must run my own Jetty server in my Main function, and programmatically add the WFS module somehow
I do not yet know:
How to initialise and add the gs-wfs module to my own programatically created Jetty server
How to get a shared instance of the Catalog to add / remove the configured data
With specific focus on points 1 and 2 above, how do I initialise an instance of "just" the GeoServer WFS endpoint?
The path you're taking is too complicated (besides, there is no WFS servlet to start with)... the GeoServer war is the packaging of a modular application, with a selection of modules of common usage included in it.
If you want to remove the GUI you simply go into the packaged war file, and remove any jar that starts with "gs-web". Since you want full control, you probably want to remove also the administrative REST interface, thus remove also all jars starting with "gs-rest". That should get you close to an application that can start, and can run.
I say "close" because this operation is not commonly attempted, and there might be some unintended cross-module dependency preventing it to work.
Another possibility is to check-out GeoServer, get into src/web/ap (or clone it) and edit the pom.xml file, removing all dependencies you don't want... rebuild and you'll get a minimized war file with only the necessary jars.
GeoServer is a lot more complex than just a pick and mix bag of jars. If you want to create a single jar WFS server you will need to start with a copy of the specification and probably an understanding of how GeoTools (the underlying library of GeoServer) works, and about a year or two of development time.
Or you could read the GeoServer manual and turn off the GeoServer GUI. Then all you need to do is master the REST API to load data into it.
I am trying to build an application that runs under JavaSE and Android. Most of the code is the same between the two, but there are some specific functions that need to be separated. I use Eclipse. So I decided to put the shared code in a separate project, and then build one more project for Android and one for Java, which reference the shared project. I put all Java and Android specific functions in one class residing in the Java and Android specific projects. These classes are called UtilsJ (for Java) and UtilsA (for Android). The code in the shared project uses a factory to determine at runtime which version it needs to pick, and then calls the class loader to load the right class. Essentially: if property java.vm.name equals Dalvik, load UtilsA, else load UtilsJ (and of course cast to the Utils interface before returning).
My question is simply if this is a good idea or is something going to eventually break? I've never used class loader before. Any other suggestions how to implement this sharing would also be appreciated.
Generating an interface implementation dynamically is certainly a valid technique. For instance, having a data access interface that has multiple implementations; one each for flat files, MySQL and WebDAV. The program can pick an implementation at run time based on system/platform properties.
But this feels different. If I saw that I had a Java app and an Android app that had a lot of common code, my goal would be to create an Eclipse project that generates a jar file that I could just drop into the libraries of both projects. In that case, the jar file wouldn't contain any code that was incompatible with one platform or the other. So there wouldn't be any reason to have a platform-specific implementation.
Let's take your example some code reading an initialization file. If it's common code, you have an input parameter which is a file. On Android, maybe it's "/data/data/com.whatever.blahblahblah" and on Java you're getting the "user.dir" system parameter for the top level directories. But one way or another, it's a File, and you hand it to your common setup method. That's okay. But if your initialization file read code e.g. needs a Context to get a Resource to read the file for Android, then it's not common code. And it doesn't belong in a library jar for a JVM-hosted app.
So I think that in your case the platform-specific implementation classes are overkill. If it's common code, it's the same code — period.
Let's talk about another example in your comment. If you are using desktop Java, then you are probably using Swing or AWT, so you still have the same issue of running some network task off the UI thread, notifying when it completes, maybe even updating some progress indicator UI while it's processing. Same function, same operation, but the code is so different that I can't see how having it in the same library next to an AsyncTask version could be of any benefit.
And testing might get tricky. Obviously JUnit will work for everything, but some tests would need to run on a device or emulator.
I stated that it was a valid technique, and of course you may have other compelling reasons to choose the multi-platform option. You asked the question; is anything going to break? My answer is: Probably not, but why risk dealing with some heartburn down the road? Speaking for myself, I wouldn't do it. If I had to support multiple MVC apps, my common library would have nothing but M.
I have an ant script that I use to build my J2EE application and create jar files. The problem is the following: Two jar files are necessary for the application to run.
commons-math-2.0.jar
commons-math-1.0.jar
However, I want to only use the 2.0 for a particular package inside the application with the rest of the application using 1.0. How can I build the application to only use the 2.0 version for example with a package name such as com.naurus.eventhandler.risk? Again, I'm using an Ant script, but if there's an easier way to do this sort of thing I'm willing to experiment. Thanks!
If the two jars contain different classes/packages there should be no problem to have all of them in the application classpath. It is then a matter of discipline not to use the classes from the one jar in the other package.
However I guess these two jars contain mostly the same classes/methods? There are many ways of using different versions of the same classes:
Using different ClassLoader instances. I would not qualify it as "easy", far from it means opening the door to a bunch of nasty bugs. (can be helped using a tool like OSGi)
Splitting the application in two processes, these process being launched in the same Ant target and using any mean (CORBA, RMI, REST, etc.) to communicate.
I would not advise using any of these methods though. It would probably be simpler to make all your packages use the same version. Is there any specific difficulty in doing so?
That will be problematic since both JAR files will end up in the same classpath when you deploy your J2EE application. You could achieve what you are trying to attempt with OSGI bundles, which allow each package to have separate dependencies. However, that is a relatively large refactoring of your application.
IMO, it would be best to either:
a) Duplicate the features you need from 2.0 (if the number is small and the license allows it, e.g., package individual classes).
or
b) Spend the time to upgrade the entire application to 2.0
You could use the manisfest in your jar to define the classpath.
http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Although honestly it seems a bit convoluted, but it is your requirement.
I'm trying to make a simple application that loads and runs some classes during runtime. For example, let's say I have this config:
module1.classpath=module1.jar,somelibs1.jar
module1.class=com.blabla.Module1
module2.classpath=module2.jar,somelibs2.jar
module2.class=com.blabla.Module2
Then I need to load libraries specified in module1.classpath and run the module1.class with that libraries loaded. Afterwards I need to load module2.classpath and run module2.class with those libraries.
How do I handle the case when somelibs1.jar and somelibs2.jar have the same classes inside? Basically I'd like to run module1.jar using exclusively somelibs1.jar and module2.jar using exclusively somelibs2.jar. How do I implement that?
I'm guessing I need to create a separate classloader for each of my classes and push the jars in that classloaders. However I'd appreciate some example or at least a confirmation that it is a right way to do that.
This seems to be a pretty good use case for OSGI. I would recommend using OSGI for this as everything you nees is provided by OSGI out-of-box.
But if for some reason you can't use OSGI, then what you need to do is to have a classloader for each module. Load the moduleX.class by a ClassLoaderX, and moduleX.classpath should be added in to ClassLoaderX's path. You can use a set of simple URLClassLoader for this.
Thanks for question. Very interesting.
It seems to you can't use several versions of the same class in one instance of JVM. I've never had this task and I don't know how to implement this.
But let's play. I don't know what is exotic application do you develop. May be you can run many JVMs and each JVM will have exclusive CLASSPATH.
Write application which can run (for example using Runtime.exec()) another JVM and make a conversation to it via some channel (may be network).
I'm developing a Java plugin for an existing Java program. The existing program uses a specific version of eclipse.uml2.* and my plugin does too. Unfortunately I need a newer version for my plugin.
In order to run the plugin, I need to export it into a Jar file (with all jars packed). Then the program executes it. But somehow the new eclipse.uml2.* seem to interfere with the program -> it crashes.
Is there a way to "separate" both versions of the jar files?
An approach will be to use a custom class loader in your application. This can very easily introduce bugs that are difficult to trace, so take care.
http://www.devx.com/Java/Article/31614/1954
This is the exact problem OSGi tries to solve. Would it be feasible to rework the Java app to another plugin platform?
This will be difficult. You conceivably try to use class loader tricks to allow both versions of the eclipse.uml.* classes to be loaded in the same JVM. But as far as the JVM would be concerned they would be different sets of classes, and your plugin and the base java app wouldn't be able to exchange instances.
It is probably simpler (and less risky ... in terms of likelihood of success) to rebuild (and if necessary modify) either the base program or your plugin so that they both work with the same version of the eclipse.uml2.* classes.