Externalising resource Adapter giving : java.lang.ClassCastException someclass incompatible with someclass - java

I am working on externalizing Resource adapter rars.
Earlier, the rar were packaged inside the /lib of war and everything worked good. Now to make the war light and also generic, I want to externalize resource adapter.
What I have done yet
Removed rars from war
installed rar externally through WAS7.0 Admin console
configured J2C connection factories for each RAR
I did a clean ,restart and I got some ClassNotFoundErrors.
Why were these errors there :
Basically the rars use some jars that are present inside /lib. so earlier there was no problem but now when I externalized it, I started getting CNFE`s.
How I resolved:
When we install a rar through WAS admin console , there is an option to provide classpath. I provided the jars that were causing issues on classpath there. And I could deploy and start my application
The problem:
When I login to my application. There is a line of code in one of the jars (that was causing issues and was added to classpath of resource adapter , note that currently this is present inside war and also on classpath of resource adapter), that is doing a type cast.
Now on this statement
I get an exception
java.lang.ClassCastException: com.csc.fs.ra.SimpleMappedRecord incompatible with com.csc.fs.ra.SimpleMappedRecord
I dug up and found that a possible cause is multiple version of same jars. which is a case in my case.
i have a version of jar inside war library and also on classpath of resource adapter.
I am kind of out of ideas here. what to do to resolve this kind of situation. please help
Regards

The RAR and the WAR got their own ClassLoader, even if you use the same version of the jar, each one of them loads the class separately and you get ClassCastException.
Before when it was embedded it worked because the RAR was using the same ClassLoader.
If the RAR are now separate I think you will have to put the jars in a shared library so it will be loaded by a single ClassLoader.

You can check the classloaders. It will show you all jars that are loaded.

Related

How to configure log4j2 with Tomcat 8.5.15

I have log4j2 jars under $CATALINA_HOME/lib:
log4j-api-2.10.0.jar
log4j-core-2.10.0.jar
log4j-jul-2.10.0.jar
export JAVA_OPTS="${JAVA_OPTS} -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager"
In catalina.properties I've got common classloader and I tried to add log4j-jul-2.10.0.jar again even if it is already under the CATALINA_HOME/lib, but no success.
common.loader="${catalina.base}/lib","${catalina.base}/lib/.jar","${catalina.home}/lib","${catalina.home}/lib/.jar","/opt/tomcat/apache-tomcat-8.5.15/lib/log4j-jul-2.10.0.jar"
I have deleted logging.properties under Tomcat and add a new log4j2.xml to path
ERRORMESSAGE:
Could not load Logmanager "org.apache.logging.log4j.jul.LogManager"
java.lang.ClassNotFoundException: org.apache.logging.log4j.jul.LogManager
Any idea why LogManager is still missing or should I use some other jars instead. In another messages they are speaking juli.jar and extras, but in their case they have older Tomcat version, 6 or 7.
You just need to add the log4j2-api, log4j2-core and log4j2-appserver libraries into the Tomcat classpath, provide the log4j2 configuration file and remove the $CATALINA_BASE/conf/logging.properties from your installation.
This is most easily done by:
Creating a set of directories in catalina home named log4j2/lib and
log4j2/conf.
Placing log4j2-api-2.x.x.jar, log4j2-core-2.x.x.jar, and
log4j2-appserver-2.x.x.jar in the log4j2/lib directory.
Creating a file named log4j2-tomcat.xml, log4j2-tomcat.json,
log4j2-tomcat.yaml, log4j2-tomcat.yml, or log4j2-tomcat.properties
in the log4j2/conf directory.
Create or modify setenv.sh in the tomcat bin directory to include
CLASSPATH=$CATALINA_HOME/log4j2/lib/*:$CATALINA_HOME/log4j2/conf
You can force the applications that use the JUL framework to use log4j2 format changing the environment variable LOGGING_MANAGER. You can do this by adding in the setenv.sh file: LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager"
Remember that org.apache.logging.log4j.jul.LogManager is included in the log4j-jul-2.x.x.jar bridge which must be added to your classpath.
refs:
https://db-blog.web.cern.ch/blog/luis-rodriguez-fernandez/2019-03-keeping-your-logs-clean-apache-tomcat-9-log4j2-and-spring-boot
https://logging.apache.org/log4j/2.x/log4j-appserver/index.html
I know that this is a little late to answer this question, but I'm sure it could help someone struggling like me trying to configure tomcat so that it uses lo4j.
I've been working on something similar for the past 3 days, and I found out that the extras folder provided by tomcat's website are not what I need. But, you can still grab them using maven. I was able to configure tomcat so that it uses the mentioned jar files ( tomcat-extras-juli.jar and tomcat-extras-juli-adapters.jar ). Just remember to include the VM argument -Dlog4j.debug to make your life easier and catch errors quicker.
Maven repo: https://mvnrepository.com/artifact/org.apache.tomcat.extras/tomcat-extras-juli-adapters
I came upon the same problem after I included the mentioned jars provided by tomcat's repository. After a quick analysis I found that the interface org.apache.juli.WebAppProperties was not included in the jar file tomcat-extras-juli.jar which is utilized by the file org.apache.catalina.loader.WebappClassLoaderBase. After researching a bit more, I realized that the tomcat jar files are included in the Maven Repo. I downloaded the mentioned jar files under the same version of tomcat ( currently 8.5 ), plugged those jars in my tomcat installation and everything worked as expected. Now my version of tomcat uses log4j instead of juli.
log4j2 jars must be loaded along with bootstrap.jar (tomcat startup) and tomcat-juli.jar (logging)
These jars are present in CATALINA_HOME/bin directory and are responsible for
initialization of tomcat including logging.
In CATALINA_HOME/cataline.bat in case of windows, you will find below code -
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
Here, you should add log4j2 jars at the classpath so that when tomcat starts, these jars are there.
Create in tomcat\bin\ file setenv.bat and add to file:
set "CLASSPATH=%CLASSPATH%%CATALINA_BASE%\bin;%CATALINA_BASE%\bin\log4j-core-2.10.0.jar;%CATALINA_BASE%\bin\log4j-api-2.10.0.jar;%CATALINA_BASE%\bin\log4j-jul-2.10.0.jar"
copy jars files
log4j-api-2.10.0.jar
log4j-core-2.10.0.jar
log4j-jul-2.10.0.jar
to folder tomcat\bin\
create file log4j2.xml in tomcat\bin folder

Tomcat 8 classloading - difference between JAR in [WEB-INF/lib] and [tomcat/lib]

It says here that the common classloader is visible to all web application. So what is the difference between having a JAR file within the WEB-INF/lib folder of my war application and having the same JAR file within Tomcat's lib folder?
This JAR is a provider for a Java SPI that I created. When I have it under WEB-INF/lib, everything works perfectly. But if I try to put this JAR under Tomcat's lib folder (or under shared/lib after configuring it in catalina.properties) I get errors. The second option is better for me because I need total decoupling of my application and the provider.
The error I get is a ClassNotFoundException for the interface that represents my service (which the JAR implements). This interface is in a third project, which is a dependency for my war application.
The tomcat/lib directory should be used for shared libraries for the whole web server and WEB-INF/lib only for one web application.
The difference is the classloader being used. Tomcat has very specific rules for it's classloaders, some of them are counter intuitive. Your problem here, is that a class loaded in one classloader is not compatible with a class loaded in another. Even Object to Object will fail.
The jar containing your interface is loaded by the webapp classloader since it is located in the war-file. The implementation is loaded by the common classloader. This does not contain your interface, so it throws a ClassNotFoundException.
The solution is to move all jars into the same classloader. Either everything in the lib-folder, or everything in your war.
Implementing a plug-in architecture with Tomcat is a rather difficult undertaking. Using something like OSGi would probably help. But for small problems, it's probably overkill. Fun, but overkill.

Java and Tomcat org.json java.lang.ClassNotFoundException

I'm new to servlets, I got java.lang.ClassNotFoundException whenever I try to include JSON library, I search the web and stackoverflow the only suggestion I found is to install dependencies I've Tried org.json , net.sf.json each with its dependencies nothing works and gives the same exception.
Any idea?
JSONObject is contained in java-json.jar. Make sure that have you have java-json.jar in your classpath. There are multiple places to put jars in tomcat depending which class loader you want the class to load.
If this jar is only required by your application then simply put it under your application directory in
WEB-INF/lib
It is worth reading how classes are loaded in Tomcat to place your jars optimally: http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
Try to put the libs for your web app in the directory
WebContent/WEB-INF/lib

my jsp code works only if i keep jars in Tomcat lib apart from lib folde in classpath

In my application I am calling a bean from JSP and displaying data.I have kept all required jars in lib folder and that is in build path.When I run this bean it fetches the data successfully. But when I call this bean in JSP it says No Class defination.I found a workaround for this that is putting all the jars also in the lib folder of Tomcat.(apart from keeping in classpath). Means now i have to deploy the war and also put jars in tomcat lib.but why do i have to do this when jars are already in classpath.
thanks.
It sounds like you might be having a conflict with some of the jars. If one of the jars is depending on something provided elsewhere in the tomcat class loader, or if it is providing the same functionality - you could end up with a problem. You used to see this often with a conflicting XML parser implementations.
This has some more information on what is included: http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html

Tomcat - won't load my META-INF\services\javax.servlet.ServletContainerInitializer file?

I have a web project that has a \META-INF\services\javax.servlet.ServletContainerInitializer file with its content pointing to the fully qualified name of a class that implements the ServletContainerInitializer interface. I basically followed the example given here: http://nullhaus.com/2011/03/using-servlets-3-0-servletcontainerinitializer/
I put debug lines in my class that implements the ServletContainerInitializer interface and it never makes it there. Not even the default constructor...
My application folder structure is as follows:
\MyApp
\META-INF\services\javax.servlet.ServletContainerInitializer
\WEB-INF\classes\
... [list of classes and packages go here]
Any ideas what I need to check for??
Note 1: My Tomcat publishes from an exploded external folder that contains my application
Note 2: I started my Tomcat from Eclipse - if that makes a difference!
Well, I think that you'll need to wrap your initializer class (and it's services-related META-INF directory) into a separate *.jar and put it in the WEB-INF/lib.
This is a JAR service, so I guess it could have something to do with problems with discovering services in a *.war file. Moreover, it doesn't even help if you put your META-INF directory inside WEB-INF/classes and set unpackWAR=false in your Tomcat's server.xml.
HTH.
The first thing to check is that you are actually using Servlet 3.0 and not an earlier version. For Tomcat, this means that you must be using Tomcat 7.0.22
Second, make sure that the \META-INF\services\javax.servlet.ServletContainerInitializer file actually exists in the exploded war file.
Third, when in doubt, configure and start Tomcat directly (not from Eclipse) - I've seen developers have endless problems with configuration of Tomcat using the Eclipse plugin.
For tomcat to load the META-INF directory , it has to be in classes folder . If you are using maven project , just put the META-INF directory inside src/main/resources directory .. on mvn package the same will be copied to classes directory .. No need of separerate jar .. if jar is prefered you can use
HandlesTypes annotation ..
I would like to quote some good explanation from Mark Thomas <markt#apache.org> given on the user mailing list of Tomcat:
Service files are loaded by class loaders from the META-INF/services
directory.
*.jar!/META-INF/services
and
*.war/WEB-INF/classes/META-INF/services
are visible to class loaders
*.war!/META-INF/services
is not.
The servlet expert group recently discussed WAR vs JAR in the context of
Java 9 and mutli-version JARs. The conclusion was (I'm paraphrasing)
that WARs are not a specialised form of JAR and while they share a
common format a feature that is available to a JAR is NOT automatically
available to a WAR unless the Servlet spec (of Java EE spec) explicitly
states otherwise.
Containers are free to add container specific extensions if they wish
but they come with the usual (lack of) interoperability warnings.
http://mail-archives.apache.org/mod_mbox/tomcat-users/201808.mbox/

Categories