Tricky Classpath issue - java

Working on an existing application, it runs on Weblogic as a massive ear file.
There is custom code, written by my organization, as well as code written by the vendor that all runs on one classpath when weblogic starts up.
Some of our custom code uses spring 1.2, in the latest version of the vendors code, they use spring3. So we cannot get the ear to completely work unless we can get each component the spring version it needs in order to function. But since they are both using the classpath that weblogic is started on, either spring1.2 or spring 3.0 will be first depending on the order in the classpath.
Am I stuck? Missing something? I've never had to deal with classpaths at this level.
Thanks

Classloaders use a delegation model when loading a class. The classloader implementation first checks its cache to see if the requested class has already been loaded. This class verification improves performance in that its cached memory copy is used instead of repeated loading of a class from disk. If the class is not found in its cache, the current classloader asks its parent for the class. Only if the parent cannot load the class does the classloader attempt to load the class. If a class exists in both the parent and child classloaders, the parent version is loaded. This delegation model is followed to avoid multiple copies of the same form being loaded. Multiple copies of the same class can lead to a ClassCastException.
Think setting the following in weblogic.xml might help
prefer-web-inf-classes Element
The weblogic.xml Web application deployment descriptor contains a prefer-web-inf-classes element (a sub-element of the element). By default, this element is set to False. Setting this element to True subverts the classloader delegation model so that class definitions from the Web application are loaded in preference to class definitions in higher-level classloaders. This allows a Web application to use its own version of a third-party class, which might also be part of WebLogic Server. See "weblogic.xml Deployment Descriptor Elements".*
When using this feature, you must be careful not to mix instances created from the Web application's class definition with issuances created from the server's definition. If such instances are mixed, a ClassCastException results.
Refer to the URL below
Oracle Weblogic Server

Related

NoClassDefFoundError when trying to load class

I am getting a java.lang.NoClassDefFoundError when trying to instantiate some class
I will try to simplify the structure of my projects: I have 2 jar files A (with a.class inside) and B (with b.class) I am trying to instantiate a 'b' class inside 'a' code. JAR A is dependant on JAR B. JAR A is a regular JAR file which is located in application/lib and JAR B is packaged as an EJB_JAR.
I am using glassfish and J2EE with maven I am new to J2EE and I have tried to look up a little for it. I have figured out it might be a class loaders issue, as the Classloader that loads classes from lib ( A) is the Ancestor of the Classloader that loads EARs WARs and EJB_JARs hence because of visibility issues I cannot load class 'b' from 'a'
Also, when I'm trying invoke (using the "expression evaluator") Class.forName("com.package.SomeClass") in the debugger from classes located in Jar-A to load class in JAR-A I get a class, but when I try to load classes located in Jar-B I get the java.lang.NoClassDefFoundError exception.
The thing is, that the passed EJB in the constructor has all the EJB fields properly, so I thought it should work, and, everything was compiled successfully.
How do I solve this problem?
The weirdest thing:
I am using drools which resides in JAR_A and JAR_A has some regular class which tries to call b.class (in JAR_B)
calling b.class from a.class doesnt work,
but calling b.class directly from a rule (which got b.class from CommandFactory.newSetGlobal("Bclass",b))works just fine.
How Could it be?
when I pass it as an Object from JAR_B it works and invokates fine.
Recap
You say:
I am trying to instantiate a 'b' class inside 'a' code. JAR A is dependant on JAR B. JAR A is a regular JAR file which is located in application/lib and JAR B is packaged as an EJB_JAR.
From what I understand, you have a pom.xml to build jar A, which states that jar B is its <dependency/>.
Then I see two possible cases for your deployment scenarios: you are either deploying the jars to the application server as an EAR, where jar A is contained inside this EAR as a library and jar B is a deployment inside it, or you are trying to use B from another, unrelated application.
In either deployment case, this is an error, but it might be due to expressing your dependencies incorrectly, or accessing the EJB incorrectly.
Nested Deployment case
If this is a nested deployment, where jar A is contained in the EAR as a library, you have a dependency expression problem. An EAR library can not have a dependency on the EAR itself, it can only be the other way around. After all, this is the definition of a library, right? :)
You have to refactor your application to match the use case you are trying to implement here. For more info, see the excellent Patterns of Modular Architecture RefCard from DZone.
Application client case
If what you are writing is an isolated (might even be a standalone) client that is going to invoke some operations on the EJB, what you should do is create an interface (local or remote, depending on how you are deploying the client) and package it with the client application and your EJB.
Then use a JNDI lookup in your client application to obtain a reference to the remote EJB and use it via the interface:
Context foo = new InitialContext(remoteJndiServiceProperties);
MyBeanInterface bar = (MyBeanInterface)foo.lookup("com.mycompany.MyBeanInterface");
bar.doStuff();
The remote JNDI registry properties and your bean's business interface name have to be expressed properly, of course. See the EJB FAQ for Glassfish for more info.
It is even simpler if your client is running in the same deployment unit - you can just use the #EJB annotation in that case and inject a no-interface EJB reference.
For more information on standalone clients with GlassFish, see the Developing Application Clients with ACC guide which covers all possible deployment scenarios.
Some theory behind this
Run the application in a debugger (or look at the heap dump taken while your client is invoking methods on the EJB, passing it objects as parameters).
What you will see is that the EJB container (that is, your EJB) is not working with the actual class you think it is, but rather with something called a static proxy class, which is generated on the fly by the container.
Because of this, when you invoke the instanceof operator inside the EJB, checking if the class you're working with is of the correct type, it will evaluate to true, but when you try to typecast it, you will get a ClassCastException.
This is required by the EJB specification and there is not much you can do about it, except pass the objects not as references, but rather as serialized data (which is going to cost you).
It works the other way around, too, because the container must be able to intercept anything done to the EJB from outside of it, and react (such as unauthorized use of restricted methods, transaction handling, etc.).
BTW, a lot of what you are describing above is illegal. ;)
Manually loading classes using Class.forName() inside an EJB container, for example - the EJB container should manage the lifecycle of your objects and anything you can not obtain using a factory method, or even better, using "compatible" mechanisms such as CDI producers and dependency injection, should be passed to your EJBs as a parameter.
What is also questionable is the way you try to pass an instance of the EJB to an application running outside of the container. If you need to access your EJBs to invoke methods on them, you should do it by means of an EJB client, in your case most probably through a remote interface.
Also, look up the definition of classloader hell if you still want to pursue your approach - you might want to start with this article, but I guess it's just as good as any other.

WebSphere DynaCache Desalinization issue

I have two portal web project
project1
project2
I have a shared library(sharedLibrary.jar) set which is used in both the above project. My shared library is used to lookup dyna cache and set/get data from it.
I am setting a my own bean bean(say it is com.test.UserBean) to dyna cache from project 1.
Now from project 2 am trying to retrieve the bean(com.test.UserBean) from cache. When doing so i am getting classCastException.
but when I assign it like below it was showing me the that the object is com.test.UserBean
Object obj=distributedMap.get();
My bean implements Serializable interface and has a serialVersionUID field.
I am not sure what happening here. Is it a class loader issue/something else.
Can any one shed some more light on this ?
This is less likely a serialization issue and more likely a classloader issue.
If the class was truly loaded by both portlet web applications by a single, common class loader then instances can be shared via DynaCache.
If however two different classloaders are used to load the same .class from the same .jar (on disk) and the two applications share a single instance (e.g. via DynaCache distributed map) you will encounter a ClassCastException - even though, as you've seen, myInstance.getClass().getName() yields the same string.
To confirm this you can enable a service and use the WebSphere classloader viewer. This will let you, per module, troubleshoot your "two classloaders, one class" issue. There is a companion doc on the InfoCenter doc which walks you through the troubleshooting process. The classloader viewer will show you which .jar and which classloader was used to load the com.test.UserBean in each module. For example, you may have accidentally packaged the jar in WEB-INF/lib of one and not the other and have parent-last classloading enabled.

Can I run code before servlet class loading on Tomcat?

I'm doing some runtime bytecode manipulation on some of my business objects, and it's very important that they be loaded in the right order. Currently I'm simply calling Class.getSimpleName() on them in the right order in my Startup servlet. This has been working just fine, but if there's a better way, I'm all ears.
Now, however, I need a method in one of my servlet filters to return a concrete business object type. This is causing the classloader to load that particular business object class first (out of order) and things break.
What I'd like is to be able to run my getSimpleName() hack before any of my servlets or filters are loaded. Is there some place I can put code that runs before the classloader even loads my filters?
Yes, you can.
Look at ServletContextListener.
The tomcat class loader works in this fashion.
if you want to load any classes before any of you web-app classes load, then you can put those classes in a jar file and deploy it to tomcat common library, these classes will be loaded before your web application classes are loaded by the class loader.
You can check the documentation of how apache tomcat class loader works here

Concurrent access causes ClassCastException (X cannot be cast to X), or how to resolve such class loading problems in JBoss

I have a problem concerning JBoss and class loading.
Here is the configuration I am working with. I have two instances of JBoss 4.2.3.GA on the same server. On each instance an application is running, and these applications are communicating with each other. There is an utility class, packed in both applications archives. This utility class is strictly the same in both applications.
This usually works fine, but in particular situations, I get ClassCastException. The case is the following:
A user is using a web application, which calls the application on the first JBoss instance (let's call it the application A). And application A calls the application B (on the second instance). This particular call takes several seconds to succeed.
If another user is trying to use the web application in a similar context (call to application A, which calls application B), and if this call happens during the first user call, I get systematically a ClassCastException : X cannot be cast to X (where X is my utility class, shared by both applications).
I found some information, and I deduced it was a class loading problem. Indeed, in this particular context of concurrent calls, my utility class is not loaded by the same class loader. I put a print command to see which class loader is used. In usual behavior, org.jboss.mx.loading.UnifiedClassLoader3 is used to load classes. In the particular described above, the application B seems to used a different class loader for the second user. My print command gave me the following:
WebappClassLoader
delegate: false
repositories:
/WEB-INF/classes/----------> Parent Classloader:java.net.FactoryURLClassLoader#de8209
My guess is that application B return an instance of my utility class loaded by this WebappClassLoader, and application A (which is using UnifiedClassLoader3) cannot cast it.
But i don't get why the UnifiedClassLoader3 cannot be used in this case, on application B. And why is this WebappClassLoader used ?
All I know about the class loading configuration in my JBoss instances is that class loading isolation is used, the following configuration is used for both applications :
<jboss-app>
<module-order>strict</module-order>
<loader-repository>applicationAorApplicationB.ear</loader-repository>
</jboss-app>
Do you have any advice to resolve this problem? How can I configure jboss class loader to avoid these class cast exception?
I precise that there is no hot deployment: I clean the server each time I deploy the applications.
If JBoss is using different classloaders for different packages, it is actually following the behavior according to the spec. For many releases it did not do this. You can disable WAR classloader isolation. See the JBoss documentation for more information.
You can also use a variety of different methods that do not require the applications to be in the same classloader for communication, and this would make your applications more specification compliant. See this stackoverflow question for more details.

How does class loading work when the same class exists in different applications on the same server?

I have multiple web-apps running on an app server and each web-app WAR file contains a copy of the same jar file.
Does this mean that a class in that jar file will be loaded multiple times in the JVM, once for each WAR file it exists in? Following on from that, if I have a static synchronized method in such a class, is it only synchronized among threads within the web-app it exists in but not synchronized against the same method in the same class in a different jar file in a different WAR file? (Hope the question makes sense, will clarify if necessary).
If this is the case I presume the best solution is to remove the jar file from each WAR file and deploy it to a shared classpath folder on the server?
A Java classloader typically works by looking for classes in one or more places in a fixed sequence. For instance, the classloader that loads your application when you run it from the command line looks first in the rt.jar file (and others on the bootclasspath), and then in the directories and JAR files specified by your classpath.
A webapp classloading is similar in principle, but a bit more complicated in practice. For a particular webapp, a webapp's classloader looks for classes in the following order. For example Tomcat 6 looks for classes in this order:
Bootstrap classes of your JVM
System class loader classes (described here)
/WEB-INF/classes of the webapp
/WEB-INF/lib/*.jar of the webapp
$CATALINA_HOME/lib
$CATALINA_HOME/lib/*.jar
Of course, once the classloader has found the class it is looking for, it looks no further. So classes with the same name later in the order won't get loaded.
The complication is that the web container has one classloader for each webapp, and these classloaders delegate to other classloaders that manage the common classes. In practice, this means that some classes will only ever be loaded once for the entire container (e.g. 1. and 2.) and others may get loaded multiple times by different classloaders.
(When a class is loaded more than once, it results in distinct Class objects and distinct class statics. The versions of the class are different types as far as the JVM is concerned and you cannot typecast from one version to the other.)
Finally, Tomcat can be configure to allow individual webapps to be "hot loaded". This entails stopping a webapp, creating a new classloader for it, and restarting it.
FOLLOWUP
So ... synchronizing a static method will not protect access to a shared resource where the class has been loaded multiple times?
It depends on the details, but it probably won't. (Or to look at if another way, if a class has actually been loaded multiple times, then a static method of each "load" of the class will access a different set of static fields.)
If you really want a singleton application class instance to be shared by multiple webapps in the same container, it is simplest if you put the class into $CATALINA_HOME/lib or the equivalent. But you also should ask yourself if this is good system design. Consider combining the webapps, or to using request forwarding etc instead of a shared data structure. The singleton pattern tends to be troublesome in webapps, and this flavor is even more so.
Java EE application servers typically use multiple classloaders to isolate applications from each other, and allow new versions of one application to be deployed without affecting other apps.
You get patterns such as several WAR files and one EJB file in an EAR with a hierarchy of classloaders, each WAR having it's own.
This does lead to duplication as you describe, but this is not necesserily a bad thing. It means that you can even have different versions of the same JARs deployed a the same time, and that may actually be benficial, allowing incremental migration to new versions.
Some application servers (WebSphere for exmaple) have explicit support for a shared library concept, and I do use that.
Be wary of just popping JARs into arbitrary classpaths, you run the risk of destabilising the app server itself.
Most application server use most specific along a path takes precedence policy.
If you have multiple library that do the same thing, You should consider to put them inside application server lib (f.e: TOMCAT_HOME/lib)

Categories

Resources