I need to make SLF4J working inside the WebLogic application. According to Buttso [1] and Oracle [2], one need to copy files into domain/lib directory:
slf4j-api
slf4j-jdk14-1.6.0.jar
Then define the following handler in logging.property file:
handlers = weblogic.logging.ServerLoggingHandler
and start WebLogic with following parameter attached.
-Djava.util.logging.config.file=C:\tmp\logging.properties
I understand why the property file must be defined globally. But I don't understand, why JARs must be copied into domain/lib directory of the WebLogic. I tries to leave them inside my WAR file, but it doesn't work.
Is there a way to retain the log libraries under the control of the application? Where is this limitation come from? It is possible to utilize the JDK14 logging infrastructure of the Weblogic directly from the application as:
java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger("my.logger.Name");
LOGGER.info("JDK14 Anonymous info");
It works as expected. The handler weblogic.logging.ServerLoggingHandler is able to successfully intercept the message and forward it into WSL log file. Why SLF4J bridge is not able to do the same?
[1] Using SLF4J with WebLogic Server Logging
http://buttso.blogspot.com/2011/06/using-slf4j-with-weblogic-server.html
[2] How to Redirect SLF4J to the WebLogic Logging System?
https://support.oracle.com/epmos/faces/DocumentDisplay?id=1507456.1 (Oracle subscription needed)
SHOT DESCRIPTION:
It works perfectly with SLF4J packaged with the application. The important thing is that the API slf4j-api and the implementation slf4j-jdk14 must be loaded by the same classloader.
LONG DESCRIPTION:
By default the Weblogic classloader has a priority. If both libraries (slf4j-api and slf4j-jdk14) are located in domain/lib directory nothing can go wrong.
If slf4j-api is located in the application classpath but NOT in the Weblogic classpath, two things can happen:
SLF4J finds some wrong implementation packaged with the application. For example it could be a logback as mandatory dependency of some third party library. In this case the messages will be forwarded into the wrong implementation and they won't reach the WebLogic logging infrastructure.
SLF4J finds some implementation inside the WebLogic classpath. In this case the application will be most probably fail to be deployed because of ClassCastException.
As I said, it is possible to have all the SLF4J logging libraries inside the application. For example it is needed, if the WebLogic server is a shared instance and not under your control. Two things are needed to be done:
Ensure that only a single SLF4J implementation is packaged with the application. In our case it is slf4j-jdk14. Do maven clean to be sure, all the leftovers from previous tries are removed from WAR file!
Enforce the usage of the application classloader for loading the SLF4J library. It is done by WEB-INF/weblogic.xml like this:
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
<wls:weblogic-version>14.1.1.0</wls:weblogic-version>
<wls:context-root>test-oauth</wls:context-root>
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>
Here is a useful example how to find out, which classloader was responsible for a given class or instance.
Which classloader loaded a class of the provided instance
Related
I have a maven web app project, where I use JodaTime. JodaTime is not directly referenced in my maven project, but is a part of a transitive dependency. In other words, my web app war, has another project of mine as a direct dependency, and that jar contains JodaTime.
I am getting an error after executing these two lines. It compiles fine though.
DateTime firstDate = new DateTime();
firstDate = firstDate.withYear(2016);
And here is my error:
java.lang.NoSuchMethodError: org.joda.time.DateTime.withYear(I)Lorg/joda/time/DateTime;
I know that these kinds of errors can happen if I compile and run with different versions of a library, like this answer says, but the withYear() has been around since JodaTime 1.3, since 2006, and I can't see that I could ever have imported a version that old. I've even checked my final war-file, and the only JodaTime library present, is 2.9.2.
The two lines runs fine if I create a main-method snippet, and run it from within the same project in eclipse. They only fail upon compilation into a war file, and running from my weblogic 10.3.2 server.
Does anyone have any idea on how I can proceed to debug this one?
WebLogic 10.3.6 includes this on the classpath:
joda.time_1.2.1.0.jar
This is earlier than the 1.3 that has the missing method.
Your code compiles, which is a good indication that your app's classpath has at least Joda 1.3.
Thus I suspect this is a WebLogic classpath issue. When your app uses libraries that are also on the WebLogic classpath, you need to tell WebLogic which library to use. You do this with the prefer-application-packages element in src/main/webapp/WEB-INF/weblogic.xml.
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">
<context-root>myApp</context-root>
<container-descriptor>
<prefer-application-packages>
<package-name>org.joda.time.*</package-name>
<package-name>org.slf4j.*</package-name>
<package-name>org.slf4j.impl.*</package-name>
<package-name>org.slf4j.spi.*</package-name>
<!-- others here -->
</prefer-application-packages>
</container-descriptor>
<!-- rest of weblogic.xml here -->
</weblogic-web-app>
WebLogic has a classpath analysis tool called wls-cat to help locate these conflicts, described in this blog post. One caveat - do not just copy wls-cat's prefer-application-packages block into your webapp and think you're done - you need to resolve each conflict one by one. Sometimes that means excluding dependencies from your webapp or using scope provided.
My setup includes a weblogic 12c server which hosts several applications. The application which i am writing has log4j configuration property with appenders that are specific to this application. I have packaged the property in app EAR and deployed it to weblogic.
I want the log4j setup in weblogic to pull configuration from this property file. Will i still need a global configuration file put in inside the domain root folder? . The thing that confuses me is, why do i need to have log4j configuration in domain root if i already have it inside the application ( while i load using PropertyConfigurator) .
I did copy the log4j and wllog jars to domain/lib but i am not happy with copying anything to server directories since i want this to be driven by the deployed EAR.
I am new to Weblogic so might be something obvious. Tried several links on the web but none of them answers my question. I have been referring to this thread for the setup. https://community.oracle.com/thread/1063248
Make sure log4j jar is in APP-INF/lib
Make sure your log4j config file is in the root classpath for the ear (APP-INF/classes)
If you don't have one already, add a weblogic-application.xml (see http://docs.oracle.com/cd/E24329_01/web.1211/e24368/app_xml.htm#WLPRG389) to your META-INF directory at the EAR level, and in there include a prefer-application-packages element with package-name of org.apache.log4j
JBoss AS7 Developer Guide mentions the following classloading preference from a higher priority to lower priority:
1. System Dependencies - These are dependencies that are added to the module automatically by the container, including the Java EE api's.
2. User Dependencies - These are dependencies that are added through jboss-deployment-structure.xml or through the Dependencies: manifest entry.
3. Local Resource - Class files packaged up inside the deployment itself, e.g. class files from WEB-INF/classes or WEB-INF/lib of a war.
4. Inter deployment dependencies - These are dependencies on other deployments in an ear deployment. This can include classes in an ear's lib directory, or classes defined in other ejb jars.
However, I do not understand the DIFFERENCE between #2 and #3. What kind of dependencies could be classified under category 2 above vs category 3. To me, they look the same.
As an example of migrating my Spring application from JBoss 4 to JBoss 7, I encountered a NoClassDefError for quartz 1.6 jar that our application had been using. The quartz 1.6 jar is right inside the WEB-INF/lib folder of my application. This means it correctly falls under Category 3 above. But most articles on web indicate that I have to put it in either as a JBoss 7 module or define it in the jboss-deployment-structure.xml. Why ???
I have also read the migration guidelines and did the TattleTale exercise as pointed in those guidelines. But don't quite get it on what do I do with the report? I read the answer to this Best Practice for loading 3rd party JARs in JBoss AS7 standalone deployment? - looks like quite some amount of effort will be required for the migration. Does not seem like a quick trivial task considering the numerous dependencies an application can easily have. Can someone please confirm this?
I guess I need a guideline about
For which jars do I create a module.xml? (Possible candidates -
Spring, Quartz, Apache , C3P0 connection pools etc) ???
For which jars do I have a jboss-deployment-structure.xml? (What
could be good candidates here?)
For which jars do I leave them in web-inf/lib folder? (Application
uses certain specialized math libraries - like colt.jar, excel
graphing libraries like - jxls.jar, poi.jar - these seem like good
candidates here).
JBoss AS releases used to manage their set of libraries in different ways. Earlier, Release 4.x was used to define the core server
libraries into the JBOSS_HOME/server libraries. Thereafter, each server definition had its specific library into the server//lib folder.
JBoss AS 7 follows a real modular approach deprecating all earlier approaches. The server bootstrap libraries are now located at the root of the application server. There you can find the jboss-modules.jar archive, which is all you need to bootstrap the new application server kernel, based on the JBoss modules.
For which jars do I create a module.xml? (Possible candidates -
Spring, Quartz, Apache , C3P0 connection pools etc) ???
If there are any dependency jars those could be created as modules and define in the module.xml. Also you need to defined the dependencies of the define library.
ex.
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="rezg.rezg-dto">
<dependencies>
<module name="org.apache.log4j" />
</dependencies>
<resources>
<resource-root path="rezg-dto-1.0.0.jar"/>
</resources>
</module>
Connection pool can be configured as a module and the procedure for installing a new module
requires copying the .jar libraries in the appropriate modules path and adding a
module.xml file, which declares the module and its dependencies.
For which jars do I have a jboss-deployment-structure.xml? (What could
be good candidates here?)
All the dependency jars should be defined in here. Also you can define either in the MANIFEST.MF or standalone.xml.
For which jars do I leave them in web-inf/lib folder? (Application
uses certain specialized math libraries - like colt.jar, excel
graphing libraries like - jxls.jar, poi.jar - these seem like good
candidates here).
If there are any jars which is used only in your ear or war then those could be defined in WEB-INF/lib.
However, it is recommend to use as modules.
We're building new systen using slf4j as logging facade. When deploying on newly Weblogic 12c, we found this error on console log:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/Oracle/Middleware2/modules/org.slf4j.jdk14_1.6.1.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [zip:/opt/Oracle/Middleware2/user_projects/domains/m3/servers/AdminServer/tmp/_WL_user/test/t030q4/war/WEB-INF/lib/slf4j-log4j12-1.6.4.jar!/org/slf4j/impl/StaticLoggerBinder.class]
after googling, we found that this is just a warning, slf4j will bind first found logger, which in this case is weblogic's system logger framework. Is there any way to make it bind to logging framework in our WAR file? Having <prefer-web-inf-classes> in weblogic.xml does not help
The filtering should not be done on classes but on resources, because SLF4J looks for the StaticLoggerBinder.class as a resource and not as a class.
Include this in your weblogic-application.xml as well:
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
<wls:package-name>org.apache.commons.*</wls:package-name>
</wls:prefer-application-packages>
<wls:prefer-application-resources>
<wls:resource-name>org/slf4j/impl/StaticLoggerBinder.class</wls:resource-name>
</wls:prefer-application-resources>
and your logger will be used instead of the one inside the System ClassLoader.
For WAR file you should use prefer-application-packages in weblogic.xml like described in this and this posts.
In your case it will be something like
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>
We were also having this issue and since we are required to configure the logging using Log4J this was an issue. However, using prefer-application-packages seems to work so far, i.e. putting a weblogic-application.xml file in the META-INF folder of the EAR with the following:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-application.xsd http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd" >
<prefer-application-packages>
<package-name>org.slf4j</package-name>
</prefer-application-packages>
</weblogic-application>
(ok the specified xmlns is an old one but it works, you may update it if you want, I just took ours and removed the unrelated parts).
We still have the aforementioned warning but it uses Log4J as required. In fact, if you look at the URL specified on the next line in the logs (omitted here in the question), it says:
The warning emitted by SLF4J is just that, a warning. SLF4J will still bind with the first framework it finds on the class path.
So I guess it still uses the normal class-loading mechanism for loading org.slf4j.impl.StaticLoggerBinder, which we actually configured to prefer the one in our EAR (i.e. make it the first on the classpath).
Yet, the warning remains but it works. Fixing the warning would be good but probably not possible without altering WebLogic's provided libraries.
I don't believe SLF4J provides a way to force its own version, since it's based on self-discovery in the classpath.
So, if you have administration rights on WebLogic, the simplest solution is to upgrade the SLF4J version of WebLogic to 1.6.4 by updating the file on WebLogic installation folder.
Otherwise, you can try to build an EAR instead of a WAR and follow the recommendations here, although I doubt it will work if prefer-web-inf-classes doesn't work in a WAR.
I have been working on this problem for one whole day but in vain without any effective solution.
I have an ear file packaged with an ejb and a handful of jar files (including hibernate and the other dependent jar files).The ejb is stateless and enabled as a web service.
The ear file has been packaged using maven and has the below structure
ear->projectrelatedejb.jar
->hibernate.jar
->otherdependent. jar
->META-INF/application.xml
->META-INF/manifest.mf
The application.xml and manifest file are automatically generated by maven when I do a package.
When I deploy this ear file on glassfish it gets deployed with the ejb methods being accessible using web services. However when accessing the application (using soapui),
the ejb methods that perform some database functionality using hibernate throw java.lang.NoClassDefFoundError for the hibernate api during runtime.
It is obvious from the error that the hibernate jars are not on the classpath during runtime but since the jars are within the ear Glassfish should have
added it to the application classpath.
I tried various options like adding the classpath entries to the manifest.mf during the package (by using the element addClasspath with the maven-ear-plugin) which didn't do any good.Also with Glassfish we cannot add the dependent jars as modules to the application.xml unless the jars are application client jars
(Glassfish wouldn't deploy the ear file if the application.xml has the dependent jars declared as modules).
I also tried placing the jars in the lib directory within the ear (which isn't actually required) and with the manifest Class-Path header referencing the jars in the lib directory which also didn't fix the problem.
The quick and dirty fix which I can do to get this working is to place the hibernate and the other the dependent jars in Glassfish's lib directory.However,this is a bad practice
and I am somewhat reluctant to do it.
I would really appreciate if someone can provide me with a working solution to this problem.I have gone through the net looking for this problem
but couldn't find any solution.
Wondering if its a bug with glassfish or does glassfish need something special to reference the jars in an ear.
Thanks in advance.
I found a similar problem which is discussed here: http://www.tricoder.net/blog/?p=59.
Simply put, try putting the libraries in EAR/lib directory and according to JEE5 spec, glassfish will add them to class path automatically.
I used Server Library option to deploy application JARs and it worked for me.
Right click on your EAR-> Properties -> Libraries-> Add Library -> Create -> give name and change type in Library Type to Server Libraries then add JARs that should be deployed and confirm.
I work with NetBeans 7.0.1 and GlassFish server 3.1
When you say you added classpath entries to manifest.mf, which manifest.mf do you refer to? The one in ear-root/META-INF/manifest.mf ? Try adding a META-INF/MANIFEST.MF to your ejb module with Class-Path entries!