I am using a jar file given by my client in CQ5.6.1. Some classes in the jar file requires log4j. So I created a Osgi bundle having the client jar and log4j jar files using Eclipse. I installed this into the Osgi Bundles of CQ and activated the bundle. The class from the client jar is correctly invoked from my components jsp, but the client jar is not able to locate the log4j classes. I am getting the error java.lang.ClassNotFoundException: org.apache.log4j.PropertyConfigurator not found. I also tried putting the log4j jar into the install folder under my app\ in CQ, but that also didn't help. I searched in google but couldn't find a suitable solution yet. Any help to resolve is highly appreciated. Thank you.
Your log4j bundle needs to export the org.apache.log4j package, and the client bundle needs to import it. Sling scripts see all exported packages.
You can use the OSGi console at /system/console/bundles to verify that those exports and imports are correct, the client bundle's status page should show that it imports the package from the log4j bundle.
If the exports are correct, the cause might also be some log4j or client code loading the PropertyConfigurator using a thread context class loader (TCCL) or another mechanism that does not play well with OSGi. If it's TCCL you can work around the issues by setting that TCCL yourself around code that loads the PropertyConfigurator.
CQ does provide the slf4j logging APIs out of the box, so if you can convince your client to switch to those that's probably easier.
Related
I’m trying to use JAXB 2.2.11 in an osgi environment (Liferay DXP). I am having issues creating a JAXBContext. Based on some other sources found while researching like this and this, I have determined that in an osgi container I need to provide the correct classloader for JAXB to instantiate the context. So I have code like this:
ClassLoader cl package.with.jaxb.objects.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("package.with.jaxb.objects ", cl);
This code causes a null pointer exception with the following stack trace:
Caused by: java.lang.NullPointerException
at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:129)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:201)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:146)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:371)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:446)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:409)
Looking at the source for ContextFinder I can see that context must be null on line 129:
throw handleClassCastException(context.getClass(), JAXBContext.class);
I thought perhaps the problem was that my module has a dependency on jaxb-api 2.2.11 but the jaxb-impl classes are provided by rt.jar at runtime and are probably newer than 2.2.11 because Liferay DXP runs on JDK 1.8. To get around this issue, I have tried including jaxb-impl.jar 2.2.11 as a dependency in my osgi module, thinking then the jaxb-api & jaxb-impl versions would match. After that, trying to create a JAXBContent using the same code as above results in the following error:
ClassCastException: attempting to cast jar:file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/rt.jar!/javax/xml/bind/JAXBContext.class to bundleresource://623.fwk616113009:13/javax/xml/bind/JAXBContext.class. Please make sure that you are specifying the proper ClassLoader.
By the looks of this message, the JAXBContext that is getting instantiated is from the version of JAXBContext that is loaded via rt.jar. This is very confusing to me because I would expect the version of JAXBContext loaded by my module’s classloader to be used since I’ve included jaxb-impl.jar in my module and I’ve specified my module’s classloader is the one to be used in my call to JAXBContext.newInstance. Can anyone shed some light on how I can get jaxb 2.2.11 to work in an osgi container?
*Please note that I can’t upgrade the version of jaxb-api used by my module because the JAXB code is actually in a 3rd party jar that requires jaxb 2.2.11 (I have just eliminated the 3rd party jar from the equation for now by writing some test JAXB code).
After extensive research I found the following solution. Since it seemed like passing the bundle class loader as suggested by the accepted answer in this post had to be correct, I followed the path of figuring out why I was getting a NullPointerException when I tried that. After carefully looking over the source code for jaxb-api to follow the stack trace of the NullPointerException, I could see that the jaxb-api code does things like
classLoader.loadClass("com.sun.xml.internal.bind.v2.ContextFactory")
where classLoader is my bundle's class loader (since that's what I passed in) and ContextFactory is actually a class in jaxb-impl which is loaded by the bootstrap class loader. This is where the problem lies because my
bundle's classloader isn't going to be able to see classes loaded by the bootstrap class loader. This threw me for a while because I'm not used to how class loaders work in osgi. I incorrectly was thinking the classes loaded by the bootstrap class loader would be visible because I'm used to web app class loading where there is delegation. In osgi class loaders
are completely isolated from each other, things are only visible if they are exported. To get around the issue I found some helpful posts talking about similiar issues. It turns out there is a concept
called boot delegation in osgi where you can specify a list of classes/packages to always be loaded via the bootstrap classloader. So the end result is two steps:
1) Switch the thread's class loader to your bundle class loader before calling the code to get the JAXBContext:
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
// ObjectFactory here is in the same package as my classes to be marshalled
ClassLoader objectFactoryClassLoader = ObjectFactory.class.getClassLoader();
Thread.currentThread().setContextClassLoader(objectFactoryClassLoader);
// JAXB code goes here
} finally {
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
2) Specify packages to be loaded using the boot delegation mechanism. This list needs to include the transitive dependencies of the classes you need loaded. In my case, I'm using Liferay so the list
is specific to Liferay and it goes in portal-ext.properties configuration file. Luckily I found this post where someone had done most of the work for me:
module.framework.properties.org.osgi.framework.bootdelegation=\
__redirected,\
com.liferay.aspectj,\
com.liferay.aspectj.*,\
com.liferay.portal.servlet.delegate,\
com.liferay.portal.servlet.delegate*,\
com.sun.ccpp,\
com.sun.ccpp.*,\
com.sun.crypto.*,\
com.sun.image.*,\
com.sun.jmx.*,\
com.sun.jna,\
com.sun.jndi.*,\
com.sun.mail.*,\
com.sun.management.*,\
com.sun.media.*,\
com.sun.msv.*,\
com.sun.org.*,\
com.sun.syndication,\
com.sun.tools.*,\
com.sun.xml.*,\
com.yourkit.*,\
org.eclipse.persistence.internal.jaxb,\
org.eclipse.persistence.internal.jaxb.*,\
javax.xml.*,\
sun.*
Helpful links:
Why can't JAXB find my jaxb.index when running inside Apache Felix?
What is the difference between bootdelegation and DynamicImport-Package in osgi
https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-dxp-and-weblogic-
https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/bundle-classloading-flow
http://apache-felix.18485.x6.nabble.com/Classloading-for-JAXB-td4834670.html
Here is the workaround that worked for me using JDK 11, Liferay DXP/7.2, OSGI, with a sample Jax-RS web service created from Dev Studio. The error I was getting was as follows when trying to access the web service:
JAXBException occurred : Implementation of JAXB-API has not been found
on module path or classpath..
com.sun.xml.internal.bind.v2.ContextFactory cannot be found by
org.apache.aries.jax.rs.whiteboard_1.0.4.
What worked for me was to define the context factory at the system level to override the predefined context factory. Add the following system variable to your system
javax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
For example you can add this in your setenv.sh/bat file in Tomcat, or in eclipse you can access your server Launch Configuration, Arguments tab, under VM arguments
-Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
This worked without adding any extra libraries since Liferay already has those libraries included.
How does this work? Refer to the javadoc for JaxBContext and read the Discovery of JAXB implementation Section. Using the /META-INF/services/javax.xml.bind.JAXBContext file did not work for me.
I hope this helps someone.
One final note for DXP users, if you get a permission denied on your service then you need to read about Service Access Policies
The best place to see how it should be done is Apache Karaf. It doesn't install any JAXB-API bundle - instead it uses org.apache.servicemix.specs.jaxb-api-2.2-2.7.0.jar inside lib/endorsed directory.
This way you won't use JAXB-API provided by rt.jar.
For implementation - it's best to use ServiceMix version of JAXB bundles:
org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxb-impl:2.2.11_1
org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxb-xjc:2.2.11_1
My project is using log4j2, and everything looks fine until running an application that uses a third party library that uses log4j 1.x. When our application starts, we get an annoying stack trace involving a ClassNotFoundException on org.apache.log4j.ConsoleAppender. I noticed that one of our dependencies has a log4j.properties inside its jar referencing org.apache.log4j.ConsoleAppender, so I'm guessing that's the reason for the stack trace. A couple other dependencies causing this error include most anything using JBoss logging classes, like embedded glassfish and the eclipse persistence packages.
I tried adding log4j-1.2.bridge api jar to the classpath and it had no effect.
It seems a little ridiculous to include both the jars for log4j2 and log4j1.x in our application classpath. Is there any other alternative or fix?
These links provided answers for me:
https://issues.apache.org/jira/browse/LOG4J2-172
https://issues.jboss.org/browse/JBLOGGING-95
It looks like we are using an out-dated version of JBoss logging that doesn't support log4j2. However, I'm still not sure what to do for the one dependency that includes a log4j.properties.
[edit] It turns out adding log4j-jcl-2.0 jar worked for that dependency.
Reading the documentation of redhat (https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html/Development_Guide/chap-Class_Loading_and_Modules.html) I found that the application server classloader
has a priority list when loading classes that are used to avoid any conflict between
loaded classes, The order is as below
Implicit dependencies.
These are the dependencies that are added automatically by JBoss Enterprise Application Platform 6, such as the JAVA EE APIs. These dependencies have the highest class loader precedence because they contain common functionality and APIs that are supplied by JBoss Enterprise Application Platform 6.
Refer to Section 3.7.1, “Implicit Module Dependencies” for complete details about each implicit dependency.
Explicit dependencies.
These are dependencies that are manually added in the application configuration. This can be done using the application's MANIFEST.MF file or the new optional JBoss deployment descriptor jboss-deployment-structure.xml file.
Refer to Section 3.2, “Add an Explicit Module Dependency to a Deployment” to learn how to add explicit dependencies.
Local resources.
Class files packaged up inside the deployment itself, e.g. from the WEB-INF/classes or WEB-INF/lib directories of a WAR file.
Inter-deployment dependencies.
These are dependencies on other deployments in a EAR deployment. This can include classes in the lib directory of the EAR or classes defined in other EJB jars.
I tried to test this order by using a JSF webapp (rich faces) in my EAR archive
My ear is as below :
sample.ear
--- sport.war
--- mysql.jar
--- lib
Usescase 1 : I added the JSF jars under the webapp (sport.war/WEB-INF/lib): [jsf-api-2.1.14.jar/jsf-impl-2.1.14.jar/portletbridge-api-3.1.2.Final.jar/portletbridge-impl-3.1.2.Final.jar], the jboss server started well and I don't have any exception
Usescase2: I added the JSF jars under sample.ear/lib
==> When I start the jboss server I get an exception (it sounds that the application server loaded the module JSF provided by jboss Implicit dependencies instead of the one in my sample.ear/lib)
I can't understand why in the 1srt usescase the Class Loading Precedence is not respected while in the 2sd usescase the Class Loading Precedence is respected?
Could you please clarify me this point
ENV
JBoss EAP 6.1.0.GA (AS 7.2.0.Final-redhat-8)
JDK 6
Without seeing the exact deployment exception that you got it is difficult to diagnose the issue.
In the first scenario the packaged libraries are loaded in the same class loader as your application.
In the second scenario the packaged libraries are loaded in a separate module and class loader.
The above means that , The deployment issue you were having fo not have to be related to Class Loading Precedence they could also be related to Class Loading Isolation.
Also Jboss and EAP already come with a prepackaged implementation of JSF, and you might be experiencing collisions due to version mismatch
If you were looking to replace the default JSF implementation on JBoss the better option to do so would have been to put the new JSF implementation in a static module, just like the default one , and have Jboss load it on demand.
I get below error and the log files is not created. I know log4j.properties is not being picked correctly
log4j:WARN No appenders could be found for logger
log4j jar is in lib and classpath
log4j.properties is in src folder and gets loaded to classes folder on build
I tried many ways to fix this error like adding services folder with log4j implementation class to fix WAS logging conflict also tried sfl4j
Has anyone found a way to fix log4j issue with WAS7 or later ?
You can troubleshoot Log4J itself by specifying the log4j.debug=true system variable. Then you'll know exactly what's going on with Log4J, internally.
Does your log4j.properties file contain any logger definitions? perhaps you can paste the file here?
I had this same problem (WAS ignoring my META-INF/services/org.apache.commons.logging.LogFactory file).
The problem was solved when I downgraded commons-logging to 1.0.3, to match WAS version. Check this article for more info.
Consider using the Java Logging framework instead, which is built into the standard Java Runtime Environment and requires no additional installations or configuration. The relevant classes are in the java.util.logging package and there is an overview of the process for using them here (it works in a very similar way to log4j).
I'm developing a web application using JSF 2.0, NetBeans 6.9.1, GlassFish Server 3.1, mojarra 2.0.3, and JasperReports 3.7.6. Included in my project library is the jar file "xerces-2.8.0.jar". This file was imported as part of the JasperReports jar file library. Whenever I try to deploy, run, or debug my project through NetBeans, I receive this error:
java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED! DTD factory class org.apache.xerces.impl.dv.dtd.DTDDVFactoryImpl does not extend from DTDDVFactory.
After any change in my project my build fails, and I receive the above error, when I try to deploy, run, or debug it. I have to restart the server and run/debug a second time. I've searched the internet and cannot find a solution to this problem. I've looked at the jar file in question, and and DTDDVFactoryImpl does indeed extend from DTDDVFactory - I don't know why I'm receiving this error. While I can eventually get my project running, it would be much nicer if I wasn't receiving this error.
Can anyone please tell me how I can fix this? Do I need to remove this file from my project library? Do I need to update this file with a newer version/older version?
If you provide your own xerces.jar, you have to do that through the Endorsed Standards Override Mechanism (java -Djava.endorsed.dirs=/path/to/xerces.jar), you are not allowed to just add it on the classpath (and will sooner or later run into trouble if you do). Let me explain.
JAXP is the Java API for XML Processing. The creation of JAXP objects (like parsers, XSLT transfomers, DOM Documents) is done through the factory/factory-method pattern so you can plugin a new JAXP implementation (it has to be newer than the one provided in your JRE). Xerces provides (part of) a JAXP implementation and contains endorsed standards (an endorsed standard is a Java API defined through a standards process other than the Java Community Process, see the Endorsed Standards Override Mechanism). You'll run in all kinds of troubles if you don't use the ESOM.
I got this error when using Selenium with Glassfish. I got around it by copying XML jars (xerces-*, xalan-*, xml-apis*, serialize*) from selenium/libs/ to $AS_HOME/lib/endorsed (for Glassfish 2) or to $AS_HOME/glassfish/lib/endorsed for Glassfish 4.