Tomcat: how is working the shared lib directory? - java

I made search on subject, but didn't find anything easy to understand...
We have a tomcat (v5.5). There is many webapp deployed on it. Each webapp has all librairies in the WEB-INF/lib directory. So there is a lot of duplication.
A classic library (XXX_API) was created in order to organize some common methods. So this librairy is added in each webapp to compile but not deployed with them. This librairy is deployed in shared directory of Tomcat.
We tried to integrate some DAO using JdbcTemplate of Spring 3.1.1 in the common librairy.
So we had to deploy Spring librairies in shared directory in order to deploy our XXX_API.
Now, we can't launch all applications.
Some of them crashed with these exception : java.lang.IllegalArgumentException. Class org.springframework.jdbc.config.JdbcNamespaceHandler does not implement the NamespaceHandler interface.
For information, they are developped with Spring 2.0.6 :(
The problem seems to be localized in the applicationContext.xml.
So, here my questions :
how is working the shared directory of Tomcat ?
Is it loaded in priority compared to the lib directory of the web app ?
Is just a pb about namespace declared in applicationContext.xml ?
Is it possible to have both spring versions ?
Thank you.

What you are really asking is how the classloaders load, in what sequence, etc. This page explains all of the classloaders that are involved in a webapp's execution inside of the tomcat container quite well. It tells where they look for classes, in what sequence, and which classes can be seen by each webapp as well as the container itself. Note, changes to this are significant across tomcat versions.
http://tomcat.apache.org/tomcat-5.5-doc/class-loader-howto.html

The main use that i've seen for the shared lib folder is for things like jdbc drivers, jta transaction managers and other infrastructure like things that:
The container needs to have available (in the case of jdbc and jta, to create jndi datasources and the jta user transaction)
Are environment specific, like the jdbc driver, when you are going to use the OCI version of the oracle driver. In this case, you have to match the ojdbc.jar file with the version of the native oracle client library installed on that machine. Another example would be jms connectors.
Anything that uses native libraries, as loading that jar multiple times would cause issues when it tried to load the native library a second time.
I wouldn't go putting actual app libraries like spring in the shared lib folder.

Probably because one class is loaded by app classloader, another by shared classloader.
Save yourself the trouble, don't use shared directory. What for? To save some disk space?

So, i have deleted all spring jars in each web application. I imported the spring lib (3.1.1) present in shared directory. And i unchecked them (under netbeans) to not have them in the build.
I even changed the declaration in web.xml, applicationContext.xml and Spring Servlet in order to be standardized with servlet v2.5.
All seems to be fine now...

Related

How to configure Classpath in Websphere application server?

I need to add log4j jar in classpath of WAS server but I am unable to put it. Please suggest.
I tried to add this jar in start script of WAS server.
As Michael Ransley mentioned, you need to determine who needs log4j. If it is a web application, then WEB-INF/lib is the best location.
If it used by EJB components then place the log4j as a utility jar in the EAR.
Alternatively, create a Shared Library and associate the shared library to your application.
Another choice would be to associate the shared library to your server (instead of the application) in which case, it becomes available to all the applications that are running on that server.
Storing in the App Server lib/ext or the other base classpath(s) is usually a bad idea. The reason is this could cause conflicts (log4j does not cause conflicts but other Jars could likely cause conflicts) and might prevent the application server from even starting up.
Also remember, depending on where the log4j.jar is kept (or associated via shared libraries) different class loaders would be picking up this JAR file.
From the Admin console, select Environment->Shared Libraries
Then in the page displayed, select New and follow the directions to add you library.
It depends why you want to add it. Do you need access to log4j from within your applications, if so you can add it into the application (i.e. in the WEB-INF/lib directory), if you are writing a component that needs to run within the WebSphere runtime (i.e. a JMX library) then you can put it into WebSphere/AppServer/lib/ext.
If you have multiple webapps that needs to share the same log4j.xml, you could drop it in IBM\WebSphere\PortalServer\shared\app\\
Otherwise, put it in web-inf/lib of your web app.
PROFILE_ROOT/properties
this folder is on the classpath, and its used to store properties
if you have different profiles for example for test or integration they may have different settings
source

How to load files into session bean

I have a java EE application EE5 EJB3. I develop using NetBeans 6.7 and GlassFish 2.x
I need to have a configuration file (*.xsl, *.xml) that is deployment/client specific.
My questions are:
1) where do I put files that are external to the ear file?
2) How do I load the files into a session bean? can I use injection?
I manage to inject a #Resource for the file name using the ejb-jar.xml.
Many thanks in advance.
G.
I guess this is not what you are expecting but the right answer is that you shouldn't do it! According to the EJB specifications and more precisely the Programming Restrictions:
An enterprise bean must not use the java.io package to attempt to access files and directories in the file system.
And this statement is followed by this explanation:
The file system APIs are not well-suited for business components to access data. Business components should use a resource manager API, such as JDBC, to store data.
The reasons behind this statement are:
Accessing the file system isn't transactional and would compromise component distributability.
Accessing the file system from an EJB would compromise its deployability (the resource isn't under the EJB container's control and the EJB can't be moved easily in a cluster).
Accessing the file system is a potential security hole.
Now that you know this, if you still want to do what you had in mind and if your EJB container doesn't restrict using classes from the java.io package, then I would put a read-only file on the classpath, preferably in a JAR, and access it using the getResource() or getResourceAsStream() methods of java.lang.Class. But really, you should keep the specification in mind, it's there to help you build portable applications.
If you can assemble one EAR per target deployment (maybe maven profile can help in this area), then you can then load it like a resource.
Another option would be to have a look at J2EE Application Deployment Specification (JSR-88) to have one EAR with N deployment plan per environment.
You can also decide to store the file on the filesystem (even though it's prohibited). If you want the path to be in the ejb.xml then you need again to assemble or deploy the EAR in different ways - no big gain then. Another option would then to use a Glassfish Custom JNDI Resource to have the possibility to configure the path right from the admin console. The your app. can load the file according to the path that is configured.
See this question: Process files in Java EE.
The specification forbids file access using java.io, it does not forbid file access in general.
One of the main reasons that files cause problems in enterprise applications is that they are hard to use safely and efficiently in a multi-user environment. In particular, file locks can heavily constrain scalability.
Using a class loader to read a configuration file once per session as suggested by Pascal is unlikely to cause problems on most application servers, except possibly in the case of hot deployment.
JNDI properties can be used as an alternative to a configuration file. JNDI properties are defined in the deployment descriptor and bind a value to a JNDI name at deployment time. The application can look up the value from inside the application using the JNDI name.

Tomcat parent webapp shared by configurable children webapps

Currently, we support many clients using the same web app, but each client has a different configuration for accessing their database, setting files etc. As the client list grows, updating the web apps is becoming increasingly arduous, and the duplication of resources is a waste of memory, file space, etc..
What we'd like to do is have a parent web app which is shared by all children web apps. Then have each child web app carry only files specific to them. When the child web app starts up, Tomcat loads the web app from the parent web app and then overrides any files defined in the child web app following an identical package structure.
We've been googling around and haven't found a ready or complete solution. Solutions we've looked at:
Tomcat common/share - could handle class and JAR files, but we don't see a way to handle static and JSP resources residing above the WEB-INF dir.
CATALINA_BASE appears to be more suited for running multiple instances of Tomcat which we'd rather avoid
A Maven possible solution, but we are not big fans of Maven, so would rather avoid it also.
Anybody have suggestions or ideas on how to solve this? If Tomcat configuration is not possible, what about a different application server (such as Glassfish) or a tool for doing dynamic file updated (such as OSGi, rsync). Would like to remove the resource duplication if possible.
Thank you.
There is no such thing as "parent" or "child" webapps. It's not part of J2EE spec and AFAIK it's not supported by any application server.
That said, your problem is twofold:
1) Having shared resources. This part is pretty easy assuming "resources" means static resources (images / CSS / javascript / etc...).
If they are truly shared (e.g. you don't need to have a separate version in some of your webapps), host them elsewhere (separate "common" webapp or put Apache in front of your Tomcat and host them there.
If you do need to have "local" versions of some of those resources you may be able to do some clever conditional URL rewriting or simply write a servlet that would check whether particular resource exists locally and, if not, take it from "common" location.
Precompile your JSPs so you only have to deal with JARs.
If your Tomcat instance only hosts your apps, you can indeed put your JARs in shared (or lib in the latest version); otherwise you can deploy them with each application .
2) Simplifying deployment. I'm not really sure what the big problem is here... It's rather trivial to write an Ant (batch, shell, what have you) script that would assemble and deploy WARs based on "common" and "per-app" directory structures.
Alternatively, you may want to take a look at using JNDI to severely reduce the number of files that have to be deployed (in theory, to a single context.xml for each application).
You can build parent-child hierarchy if you use Spring at your web-apps - Using a shared parent application context in a multi-war Spring application.
I.e. you can define all shared stuff at the 'parent' context and have 'child' contexts just to use it.
If all you had was setting file and configuration changes you could manage these through the context.xml and then you can point the docBase of each application context at a common directory for all the applications to share the same source.
the drawback to this is changes to the application will require a tomcat restart.
This does not however solve your problem if you want to override logic.
A option that I am exploring for a similar scenario is to move the client custom portion into ajax widgets / gadgets. Then have it be part of the configuration files to tell the application which version of the gadget to pull for which client.
you can review documentation for having applications share a docbase here http://tomcat.apache.org/tomcat-5.5-doc/config/context.html

How do you manage embedded configuration files and libraries in java webapps?

I'm currently working on a j2ee project that's been in beta for a while now. Right now we're just hammering out some of the issues with the deployment process. Specifically, there are a number of files embedded in the war (some xml-files and .properties) that need different versions deploying depending on whether you are in a dev, testing or production environment. Stuff like loglevels, connection pools, etc.
So I was wondering how developers here structure their process for deploying webapps. Do you offload as much configuration as you can to the application server? Do you replace the settings files programmatically before deploying? Pick a version during build process? Manually edit the wars?
Also how far do you go in providing dependencies through the application servers' static libraries and how much do you put in the war themselves? All this just to get some ideas of what the common (or perhaps best) practice is at the moment.
I think that if the properties are machine/deployment specific, then they belong on the machine. If I'm going to wrap things up in a war, it should be drop-innable, which means nothing that's specific to the machine it's running on. This idea will break if the war has machine dependent properties in it.
What I like to do is build a project with a properties.example file, each machine has a .properties that lives somewhere the war can access it.
An alternative way would be to have ant tasks, e.g. for dev-war, stage-war, prod-war and have the sets of properties part of the project, baked in in the war-build. I don't like this as much because you're going to end up having things like file locations on an individual server as part of your project build.
I work in an environment where a separate server team performs the configuration of the QA and Production servers for our applications. Each application is generally deployed on two servers in QA and three servers in Production. My dev team has discovered that it is best to minimize the amount of configuration required on the server by putting as much configuration as possible in the war (or ear). This makes server configuration easier and also minimizes the chance that the server team will incorrectly configure the server.
We don't have machine-specific configuration, but we do have environment-specific configuration (Dev, QA, and Production). We have configuration files stored in the war file that are named by environment (ex. dev.properties, qa.properties, prod.properties). We put a -D property on the server VM's java command line to specify the environment (ex. java -Dapp.env=prod ...). The application can look for the app.env system property and use it to determine the name of the properties file to use.
I suppose if you have a small number of machine-specific properties then you could specify them as -D properties as well. Commons Configuration provides an easy way to combine properties files with system properties.
We configure connection pools on the server. We name the connection pool the same for every environment and simply point the servers that are assigned to each environment to the appropriate database. The application only has to know the one connection pool name.
wrt configuration files, I think Steve's answer is the best one so far. I would add the suggestion of making the external files relative to the installation path of the war file - that way you can have multiple installations of the war in the one server with different configurations.
e.g. If my dev.war gets unpacked into /opt/tomcat/webapps/dev, then I would use ServletContext.getRealPath to find the base folder and war folder name, so then the configuration files would live in ../../config/dev relative to the war, or /opt/tomcat/config/dev for absolute.
I also agree with Bill about putting as little as possible in these external configuration files. Using the database or JMX depending on your environment to store as much as it makes sense to. Apache Commons Configuration has a nice object for handling configurations backed by a database table.
Regarding libraries, I agree with unknown to have all the libs in the WEB-INF/lib folder in the war file (self-packaged). The advantage is that each installation of the application is autonomous, and you may have different builds of the war using different versions of the libraries concurrently.
The disadvantage is that it will use more memory as each web application will have its own copy of the classes, loaded by its own class loader.
If this poses a real concern, then you could put the jars in the common library folder for your servlet container ($CATALINA_HOME/lib for tomcat). All installations of your web application running on the same server have to use the same versions of the libraries though. (Actually, that's not strictly true as you could put overriding versions in the individual WEB-INF/lib folder if necessary, but that's getting pretty messy to maintain.)
I would build an automated installer for the common libraries in this case, using InstallShield or NSIS or equivalent for your operating system. Something that can make it easy to tell if you have the most up to date set of libraries, and upgrade, downgrade, etc.
I usually make two properties files:
one for app specifics (messages, internal "magic" words) embedded in the app,
the other for environment specifics (db access, log levels & paths...) exposed on each server's classpath and "sticked" (not delivered with my app). Usually I "mavenise" or "anttise" these one to put specific values, depending on the target env.
Cool guys use JMX to maintain their app conf (conf can be modified in realtime, without redeploying), but it's too complex for my needs.
Server's (static ?) libraries: I strongly discourage server library use in my apps as it adds dependency to the server:
IMO, my app must be "self-packaged": dropping my war, and that's all. I have seen wars with 20 Mbs of jars in it, and that's not disturbing for me.
A common best-practice is to limit your external dependencies to what is offered by the J2EE dogma: the J2EE API (use of Servlets, Ejbs, Jndi, JMX, JMS...). Your app has to be "server agnostic".
Putting dependencies in your app (war, ear, wathever) is self-documenting: you know what libraries your app depends on. With server libs, you have to clearly document these dependencies as they are less obvious (and soon your developers will forget this little magic).
If you upgrade your appserver, chances that the server lib you depends on will also change. AppServer editors are not supposed to maintain compatibility on their internal libs from version to version (and most of the time, they don't).
If you use a widely-used lib embedded in your appServer (jakarta commons logging, aka jcl, comes to mind) and want to ugrade it's version to get the latest features, you take the huge risk that your appServer will not support it.
If you relies on a static server object (in a static field of a server class, e.g. a Map or a log), you'll have to reboot your appserver to clean this object. You loose the ability to hot-redeploy your app (old server object will still exists between redeployments). Using appServer-wide objects (other than those defined by J2EE) can lead to subtle bugs, especially if this object is shared between multiple apps. That's why I strongly discourage the use of objects which resides in a static field of an appServer lib.
If you absolutely need "this object in this appserver's jar", try to copy the jar in your app, hoping there's no dependency on other server's jar, and checking your app's classloading policy (I take the habit to put a "parent last" classloading policy on all my apps: I'm sure I won't be "polluted" by server's jars - but I don't know if it is a "best practice").
I put all configuration in the database. The container (Tomcat, WebSphere, etc) gives me access to the initial database connection and from then on, everything comes out of the database. This allows for multiple environments, clustering, and dynamic changes without downtime (or at least without a redeploy). Especially nice is being able to change the log level on the fly (although you'll need either an admin screen or a background refresher to pick up the changes). Obviously this only works for things that aren't required to get the app started, but generally, you can get to the database pretty quickly after startup.

Place MySQL connector JAR in WEB-INF/lib of my WAR instead of in $CATALINA_HOME/common/lib?

I'm about to use MySQL with Hibernate on a Tomcat 5.5.x server.
Do I have to put mysql-connector-java-[version]-bin.jar in $CATALINA_HOME/common/lib/ or could I place it in WEB-INF/lib inside my WAR file with my other library dependencies?
It would be easier to have it in my WAR in WEB-INF/lib, as I could get it using the Maven repository that way. Are there any big draw backs to having it there instead of in the common libraries directory of Tomcat?
If your jar is in common then it's loaded globally in tomcat. Every webapp sees it. If you put it in your webapp only your webapp sees it. What I assume Boris is referring to is if some part of your global tomcat config loads something that needs a mysql connection (like a connection pool) then it's going to need the jdbc driver, so it'll need it in common. Otherwise, no.
I believe there's a security configuration you can set up in the tomcat config that stores its config in a db. If you use this, it'll need a driver.
Why would you want stuff in webapp/WEB-INF/lib? well, because it's modular, it's part of your webapp, if you move your webapp somewhere else it doesn't need an extra part of it that's part of your tomcat installation. Maintenance is much easier if you can drop your webapp directly in a stock tomcat installation. Another reason- if you have multiple webapps, they're all going to use the jars in common, which could cause library conflicts and version issues.
In general, put as little in common as you can get away with. Even if you only have a single app.

Categories

Resources