i have an API that is being written for a large group of 40 or so applications to share.
my problem is currently they plan on having the API as a simple library included in each war file for each program. the problem thats going to occur is when two apps are running on the same instance with different versions of the api library. ive had a lot of problems in the past with this.
i seem to remember a while ago something where i can wrap my library into an ear file or something and deploy it to tomcat to make it global. simply including it in the lib folder won't work because it will include hibernate systems that have to be deployed to allow the api methods to access the database. then in each application i would have an interface i can implement that allows me to call those api methods. very similar to local EJB3 but not as complex and didn't require an enterprise level server to implement.
anyone else remember something like this or was it a bad dream on my part?
You will have problems if you use a single jar shared by all the webapps, since it will then be impossible for two apps to use a different version of a library. But if each webapp has its own version of the library in its WEB-INF/lib, the container shouldn't have any problem: each webapp has its own classloader, which doesn't see the libraries of other webapps.
Related
I´m working in the design of a java web application capable of executing custom code or precompiled classes uploaded by the users, focused mostly in simple validations of datasets.
The custom class must be constrained to a predefined interface and only some libraries and classes must be available to the custom class.
My first solution is to use a custom Classloader capable of loading .jar files from a defined directory in the file system. This approach seems to work but i´m concerned about the security and compatibility of this solution.
Is possible to limit the classes that can be imported by the custom class and run the code in a sandbox in order to avoid some actions like opening files or sockets?
When the loaded class will be unloaded?
application Servers like Weblogic have some restriction about using custom classloaders?
I have evaluated another solutions like OSGi Bundles, but it looks really complex and the support is limited in some applications server also i´m not really sure if OSGi is the right technology for this particular usage. Embedded Scripting Languages like Groovy o Javascript are discarded because the project owner wants the custom code precompiled and written in Java.
What would you recommend for this problem?
OSGi is a good fit for an application that wishes to accept external code (plugins). All the requirements you mention (predefined interfaces, loading jars, mutiple classloaders) are all covered by OSGi services and bundle management. Bundles can be installed, started, stopped, uninstalled, etc, including in runtime.
OSGi support in web application servers is not really that limited. You could even considered embedding an OSGi framework.
Security-wise you will need a solution around security managers.
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.
A quick question for best practice please if anyone can help.
I am about the implement my project onto a webserver running tomcat. This will host quite a few domains which are mainly static with just HTML code. Mine however includes a database connector and also some JAX jars.
My question is
For best practice is it better to put the .JAR files into $TOMCAT_HOME/lib so that they are avaialable to all webapps, (maybe used by others in the future), or should I keep them in the WEB-INF/lib folder which is webapp specific. If I then build another webapp that uses these JARs I would then have to duplicate them in the WEB-INF/lib folder for that new webapp.
I know it would work either way but what is best practice please.
I would tend to keep them per-webapp. That gives you the opportunity to upgrade one webapp without having to touch the others. So you can roll out fixes etc. to one app without having to rebuild/retest the others.
An application server like Tomcat is designed to be able to isolate webapps from one another, enabling them to change independently, use different versions of the same libraries etc. Unless you are absolutely sure that your apps will always need the same version, and will always be ready to upgrade simultaneously (or never) to newer versions, then keeping them per-webapp makes more sense.
To summarize the issue I'm encountering, I have an EJB which uses version A of a library (let's call it dep-vA.jar). dep-vA.jar is packaged in the root of the EJB's jar file. The domain lib folder in the application server contains version B of the same library (let's call it dep-vB.jar). When calling the EJB, I get an error due to dep-vB.jar file being loaded rather than dep-vA.jar.
I guess the first part of this question is, does Sun One Application Server v9.1 isolate EJBs from each other? I was under the impression that it does. But it seems like another application loaded dep-vB.jar and this EJB is directly using it without loading its own.
The second question is, if the app server does isolate EJBs, does it load dependencies from the EJB's jar file before looking in the application server's lib folders? I was under the impression that this is also true, but maybe not...
Is anyone familiar enough with Sun application servers to explain why dep-vB.jar is being loaded rather than dep-vA.jar? Is there any way to get it to load dep-vA.jar without changing what's in the application server's lib folders? (I would hesitate to do anything that might affect other applications on the server)
Thanks.
I guess the first part of this question is, does Sun One Application Server v9.1 isolate EJBs from each other? I was under the impression that it does. But it seems like another application loaded dep-vB.jar and this EJB is directly using it without loading its own.
According to Sahoo (which is a GlassFish developer), the Java EE spec does not mandate class loading isolation among modules of a single ear so the behavior can be different from one app server to another. With Sun ONE, my understanding of the documentation is that EJB-JARs are isolated.
The second question is, if the app server does isolate EJBs, does it load dependencies from the EJB's jar file before looking in the application server's lib folders? I was under the impression that this is also true, but maybe not...
It's a parent-first strategy (and to my knowledge, Sun ONE allows to change the delegating mode for webapps only).
That being said, what happens if you list dep-vA.jar in the Class-Path entry of the MANIFEST.MF of the EJB-JAR?
See also
Chapter 2 Class Loaders of the Sun Java System Application Server Platform Edition 9 Developer's Guide
Packaging EJB 3 Applications
I haven't used that particular server, but I do know that in WebSphere, there is an option to use PARENT_FIRST or PARENT_LAST classloading. You would be looking for an equivalent of PARENT_LAST where the classes are loaded from the EAR first before going up to the server.
I would assume that such a configuration is possible in any app server, as you should always be able to enforce your application specific jars to be loaded over any others.
At our shop, we are maintaining roughly 20 Java EE web applications. Most of these applications are fairly CRUD-like in their architecture, with a few of them being pretty processor intensive calculation applications.
For the deployment of these applications we have been using Hudson set up to monitor our CVS repository. When we have a check-in, the projects are set to be compiled and deployed to our Tomcat 6.0 server (Solaris 10, sparc Dual-core 1.6 GHz processor, 2 GB RAM...not the beefiest machine by any stretch of the imagination...) and, if any unit-tests exist for the project, those are executed and the project is only deployed if the unit-tests pass. This works great.
Now, over time, I've noticed myself that a lot of the projects I create utilize the same .jar files over and over again (Hibernate, POI (Excel output), SQL Server JDBC driver, JSF, ICEFaces, business logic .jar files, etc.). Our practice has been to just keep a folder on our network drive stocked with all the default .jar files we have been using, and when a new project is started we copy this set of .jar files into the new project and go from there...and I feel so dirty every time this happens it has started to keep me up at night. I have been told by my co-workers that it is "extremely difficult" to set up a .jar repository on the tomcat server, which I don't buy for a second...I attribute it to pure laziness and, probably, no desire to learn the best practice. I could be wrong, however, I am just stating my feelings on the matter. This seems to bloat the size of our .war files that get deployed to the server as well.
From my understanding, Tomcat itself has a set of .jar files that are accessible to all applications deployed to it, so I would think we would be able to consolidate all of these duplicate .jar files in all our projects and move them onto the tomcat server. This would involve only updating one .jar file on the server if, for example, we need to update the ICEFaces .jar files to a new version.
Another part of me says that by including only one copy of the .jar files on the server, I might need to keep a copy of the server's lib directory in my development environment as well (i.e. include those .jar files in eclipse dependency).
My gut instinct tells me that I want to move those duplicated .jar files onto the server...will this work?
I think Maven and Ivy were born to help manage JAR dependencies. Maybe you'll find that those are helpful.
As far as the debate about duplicating the JARs in every project versus putting them in the server/lib, I think it hinges on one point: How likely is it that you'll want to upgrade every single application deployed on Tomcat at the same time? Can you ever envision a time where you might have N apps running on that server, and the (N+1)th app could want or require a newer version of a particular JAR?
If you don't mind keeping all the apps in synch, by all means have them use a common library base.
Personally, I think that disk space is cheap. My preference is to duplicate JARs for each app and put them in the WAR file. I like the partitioning. I'd like to see more of it when OSGi becomes more mainstream.
It works most of the time, but you can get into annoying situations where the jar that you have moved into tomcat is trying to make an instance of a class in one of your web application jars, leading to ClassNotFoundException s being thrown. I used to do this, but stopped because of these problems.
I really don't think putting libraries in common/lib is a good idea. The idea behind the use of war files as applications into a servlet container, is to have a real idea of isolation between your webapps. You could face errors like deploy some third party WAR (with it own libraries inside WEB-INF/lib) and it behave unexpectedly because it loaded other version of one of it libraries from the common one (remember that the regular behavior for load classes is first look at the common classloader and if you don't find the class look into the one for your webapp). Don't even mention how painful could be to move some application to other servlet container or an Application Server.
As mentioned before, you could use maven to deal with jar dependencies, and if you like the homogeneous use of libraries, define a POM parent (maven jargon) across all your applications.
In my experience you should be very careful with sharing libraries between web applications by moving them into the web container itself.
Let them live in WEB-INF/lib so your wars are self contained (you WILL be glad you did one day).
What you might consider is employing maven or Ant Ivy to pull in library jars from a common repository instead. This is very useful and should not be a problem in your scenario.
Edit: A notable exception is the Metro library - web service layer from Glassfish - which needs to be in the web container and not in the web application.