Skip to main content
Announcements
A fresh, new look for the Data Integration & Quality forums and navigation! Read more about what's changed.
cancel
Showing results for 
Search instead for 
Did you mean: 
Anonymous
Not applicable

[resolved] java.lang.ClassNotFoundException when deploying job in runtime

Hello Team,
I am using log4j in my custom java component. In talend job I have separate tLibraryLoad component to import log4j jar file. Everything works fine as long as I test it in talend studio. But as soon as I export this job and deploy it to runtime I get ClassNotFoundException (below). I export job by right-click > build job > OSGI bundle for ESB. Then I copy jar file into Runtime_ESBSE\container\deploy folder. It deploys fine. But when I invoke service, I get this error. 
I checked other posts on the forum that recommend dropping jar file into container/lib/ext - tried that, did not help.
Please advise.
Thank you!
Svetlana
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Layout
at local_project.generalinformationservice_0_1.GeneralInformationService.tRESTRequest_1_LoopProcess(GeneralInformationService.java:7910)
at local_project.generalinformationservice_0_1.GeneralInformationService$RestServiceProviderImpl4TalendJob.processRequest(GeneralInformationService.java:1051)
... 28 more
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Layout cannot be found by local_project.GeneralInformationService_0.1.0
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:389)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:352)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:344)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:160)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
Labels (5)
1 Solution

Accepted Solutions
Anonymous
Not applicable
Author

Hello Svetlana
the usage pattern is - as the project dependency set the Log4J or SLF4J version which is provided by the runtime (I believe in the TESB 5.6.2 it's Log4j 1.2.5 but please check yourself). Use only the simple Logger interface as xldai mentioned
private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MyClass.class);
logger.info("hello!");

The pattern, log level, log file, ... is to be configured in the property file etc/org.ops4j.pax.logging.cfg (so you don't refer the inner classes). This way you be reusing the logging infrastructure already provided. I know you may be limited with the features of the Pax Logging API implementation (e.g. I did not find any way to do any XML configuration supporting the compressed log archives), but for the rest you should be ok with that.
Gabriel

View solution in original post

12 Replies
Anonymous
Not applicable
Author

Hi,
"in my custom java component"  do you mean tJava component?
If yes, do you use any other specific class from org.apache.log4j.* package except Logger class? or just using Logger class to log something such as:

org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(testLog.class);
logger.info("hello!");

For nomal usecase, you don't need to load log4j using tLibraryLoad because log4j classes are loaded by default.
Regards.
Anonymous
Not applicable
Author

Hi xldai,
I use tJavaFlex component which calls java methods from my own external java library. Those methods are the ones that use log4j. Yes, I use other classes from org.apache.log4j.*. The reason being is that I could not make it work directly with log4j.properties config file, so I decided to do all logger configuration programmatically in java.
Please see attached screenshot of my tJavaFlex component configuration. It makes call to java:
GeneralInfoService service = new GeneralInfoService();
GetJobTitlesResponseDTO response = service.getJobTitles();
inside GeneralInfoService i do log4j configuation as this:
import org.apache.log4j.Appender;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
...
...
        PatternLayout layout = new PatternLayout();
        String conversionPattern = "%-7p %d %c %x - %m%n";
        layout.setConversionPattern(conversionPattern);
 
        // creates console appender
        ConsoleAppender consoleAppender = new ConsoleAppender();
        consoleAppender.setLayout(layout);
        consoleAppender.activateOptions();
 
        // creates file appender
        FileAppender fileAppender = new FileAppender();
        fileAppender.setFile("C:/Talend/nsc1.log");
        fileAppender.setLayout(layout);
        fileAppender.activateOptions();
 
        // configures the root logger
        Logger rootLogger = Logger.getRootLogger();
        rootLogger.setLevel(Level.DEBUG);
        rootLogger.addAppender(consoleAppender);
        rootLogger.addAppender(fileAppender);
        logger = Logger.getLogger(GeneralInfoService.class);
        logger.debug("this is a debug log message");
        logger.info("this is a information log message");
        logger.warn("this is a warning log message");

Again, it works perfectly fine in studio and breaks when i deploy it to runtime on the same machine.
Please advise.
Thank you very much!
Svetlana
0683p000009MCvV.png
Anonymous
Not applicable
Author

Hi Svetlana
just a hint to check - in the generated OSGi bundle - could you check if the org.apache.log4j package is imported? You can doing by inspecting the META-INF/ folder of the jar file and as well try to see the Karaf console and type 'headers <bundle id>' , you should see what packages are imported..
g.
Anonymous
Not applicable
Author

Hi Gabriel,
I checked generated jar osgi bundle. In manifest.mf file I see the following lines related to org.apache.log4j:
Import-Package: ...resolution:=optional,org.apache.log4j ;resolution:=optional,...
Private-Package: ... log4j.properties...
Executing headers command for the bundle id brings same results:
Import-Package =
....
org.apache.log4j;resolution:=optional,
...
Private-Package =
...
log4j.properties,
...
it does not appear on Bundle-ClassPath line though, where my java library shows up:
Bundle-ClassPath = .,lib/systemRoutines.jar,lib/json-path-1.2.0.jar,lib/json-sma
rt-2.1.0.jar,lib/userRoutines.jar,lib/NelsonESBServiceLib.jar
Thank you,
Svetlana
Anonymous
Not applicable
Author

Another thing that absolutely puzzles me is when I do configuration using a file (log4j.xml for example) in java, i.e.
static Logger logger = Logger.getLogger(GeneralInfoService.class.getName());
..
DOMConfigurator.configure("C:\\Users\\zvers\\workspaceEclipse\\ServiceLib\\properties\\log4j.xml");
..
it works perfectly in eclipse, it works perfectly in talend studio, but as soon as i move osgi bundle to runtime - log file which is specified in log4j.xml is not being updated at all. In runtime i lose all the logging.
Thank you!
Svetlana
Anonymous
Not applicable
Author

Hello Svetlana
about the resolution - in the header printout - I don't know how you see it. I see dependencies which are optional, but not resolved as red. Then the bundle resolves, starts, but the code throws an exception trying to load the class.
Apache Log4j is already part of the TESB deployment (pax-logging-api). So it is ok that it's not bundled in your jar file. But - you should rely on the version provided by the TESB. It may happend that you're using different version and the class package won't resolve.
Logging is provided by the Pax Logging framework, so the configuration can be found in the etc/org.ops4j.pax.logging.cfg file
g.
Anonymous
Not applicable
Author

Hi Gabriel, 
I see log4j as resolved. Please see attached. 
I removed tLibraryLoad that had log4j load in talend job and I still get same ClassNotFoundException in runtime environment but it works fine in studio.
Thank you,
Svetlana
0683p000009MCve.png
Anonymous
Not applicable
Author

Hi, Svetlana
Like gusto said, the Runtime container is using pax-logging-api as Logging framework which wrap log4j, slf4j, common logging etc. but for some reason it only packed limited classes in the org.apache.log4j package
Category.class
Level.class
Logger.class
MDC.class
NDC.class
Priority.class
PropertyConfigurator.class
For nomal usecase it would be OK but in your case, some other log4j classes will be used during runtime. the "org.apache.log4j ;resolution:=optional" shouldn't appear in the Import-Package: of generated Manifest of the bundle in case you're using tLibraryLoad to load log4j lib.
the correct Manifest should look like:
Import-Package:  .... (no org.apache.log4j....) ....
Bundle-ClassPath:  .... ,lib/log4j-1.2.15.jar, ....  (or other log4j version)
Private-Package: .... org.apache.log4j, org.apache.log4j.spi, (other sub package of log4j ) ....
Could you try to remove the "org.apache.log4j" from Import-Package: of the bundle manually and try it again?  it maybe something like a bug in 6.0.1.  (I checked with TESB 6.1.1 it generates the correct OSGi headers)
Regards.
Anonymous
Not applicable
Author

Hi xldai,
Yes, that worked! I manually removed org.apache.log4j from Import-Package section of manifest file and it fixed the issue. Thank you so much for this workaround 0683p000009MACn.png! Next I tried to build osgi package again, this time made sure that I dont have tLibraryLoad or any dynamic library reference to any log4j library and I also removed log4j from Studio\workspace\.Java\lib. I still get incorrect manifest with log4j included which I had to modify manually. I will install new version of Talend to see if it works.
Thank you again!
Svetlana