Upgrade log4j to log4j2 in OSGi environment (Eclipse plugin) - eclipse

I have an OSGi application (Eclipse plugin) that contains several bundles.
I have a com.domain.dependencies bundle that, as the name suggests, contains dependencies. There is NO code in this bundle. The concept is that all 3rd-party dependencies used by 1+ other bundles are contained in this bundle and made available to other bundles within the plugin. This has always worked for the past decade or so that this plugin has evolved.
The above bundle 'pulls in' log4j - an older log4j version 1.x. So, log4j has always been exposed as an available library to other bundles that use com.domain.dependencies.
Due to the recent security issues with log4j2, a company security directive/edict has stated that all use of log4j or log4j2 must be upgraded to log4j2 v2.16.0
Initially I thought I'd just change the declaration in the build.gradle file for com.domain.dependencies to pull in that newer log4j2 but discovered that log4j2 is split in to 'core' and 'api' jars. OK so I tried to use those instead. I then followed the Apache migration steps for moving from log4j 1.x to 2.x, updated all the code etc.
After the above, compilation fails. None of the other bundles 'see' log4j2 as they saw log4j. A bit of Googling and I see people talk about creating OSGi Fragments. What's a Fragment? I've read a bit about them and feel none the wiser when it comes to my issue.
I should point out that my plugin also has a dedicated bundle com.domain.log, which depends on com.domain.dependencies and it's the com.domain.log bundle that contains the log4j.properties file (which also needs tweaking for log4j2). This logging bundle wrapped log4j (and soon to be log4j2) to expose logging features to the other bundles within the plugin.
So when it comes to using fragments, I am confused. I see some articles on the internet suggest at least 2 bundles are required. I don't know if these have to be new, or if I can re-use my existing arrangement of bundles. I struggle to relate those articles to how things are currently set up in my plugin, but I wish to maintain the idea that com.domain.dependencies supplies dependencies to other bundles and has no code of itself, while also having the com.domain.log continue to expose the same logging functionality to the other bundles that need it.
My instinctive feelings are that com.domain.log which exposes logging functionality to my other bundles, should use log4j-api, while com.domain.dependencies should obtain log4j-core (implementation) and expose it to com.domain.log. However, I can imagine too many different ways to try and set this up, and all will fail unless I am doing it the right way. Basically, I need help from somebody who knows how to in an OSGi environment.
So, how should I wire-in log4j2 to mimic the traditional behaviour/functionality in my OSGi environment?

Related

Why do the JBoss/wildfly BOMs not contain all of the provided modules?

Wildfly 8.x ships with BOMs for easy dependency management: https://github.com/wildfly/boms
These are useful for the module-based classloading described here: https://docs.jboss.org/author/display/WFLY8/Implicit+module+dependencies+for+deployments
However, when I look in $JBOSS_HOME\modules\system\layers\base, I see many, many more included modules. For example, dozens of org.apache modules like commons-lang, etc. are included.
These deps are also not in the JBoss parent POM: https://github.com/jboss/jboss-parent-pom
Nor the Java EE specs: https://github.com/jboss/jboss-javaee-specs
For these dependencies (ones not in the BOMs or in the docs), how is the developer supposed to know they are provided? What is the intended dependency management strategy for developers using tools like Maven, etc.
Not all modules used by the server are meant to be used on deployments. There is a list of implicit module dependencies.
If you look at the module.xml file for some of these you'll probably see a property <property name="jboss.api" value="private"/>. This essentially just means that the dependency can change at any time. It may be upgraded to a different version or even removed. It's best to just include those dependencies in your deployment.

How to View Classpath While Debugging in Eclipse

I'm trying to troubleshoot a GWT-based app I'm writing in Eclipse. It currently uses Spring Framework 3.1.1 and Hibernate 4.1.6 on the back-end side. I'm currently having troubles with the dreaded "javax.validation.ValidationException: Unable to find a default provider" that seems to plague a lot of folks but is caused by different problems. I've tried the various solutions of using different versions of the JSR 303 implementation (e.g. diff. versions of Hibernate Validator) but it doesn't seem to make a difference.
And after debugging, I'm seeing why. Once execution gets to javax.validation.Validation.getValidationProviders():317 (in validation-api-1.0.0.GA), the app (running on an Eclipse internal Jetty server) attempts to read the META-INF/services/javax.validation.spi.ValidationProvider resource from the classpath and comes back empty. I am absolutely certain that the different validator implementations I've put (e.g. hibernate-validator-4.3.0.Final.jar) have that resource and it does contain a value (e.g. org.hibernate.validator.HibernateValidator), but is not appearing to the classloader in question. The way I've included the JAR in the classpath is by adding it to the project's Build Path which seems to add it to the Jetty runtime when I execute the applications.
My question is: Is there a way to view the classpath in Eclipse debug mode visible to a certain classloader? Secondly, does anyone know why the Hibernate Validator's resource is not first and foremost in the classloader that Validation is using?
The webapp classpath is composed by the directory WEB-INF/classes and by all the jars in WEB-INF/lib. If you want a jar to be available at runtime, you must NOT add it to the build path, but to WEB-INF/lib.
Dropping a jar in WebContent/WEB-INF/lib in Eclipse will make it automatically part of the buid path of your webapp, and available at runtime.

What's the difference between Eclipse Packages and Plug-ins?

In Dependencies tab, I have a choice between plug-ins and packages.
What's the difference between them? For org.eclipse.compare, I have it in imported package and also in plug-ins.
I find the jar file in plugins directory, but I don't know where the package file of org.eclipse.compare is located.
In the export menu, it seems like that there seems to be only exporting to jar, not exporting a plugin or packages. How can I export packages?
ADDED
Based on this post - How to import a package from Eclipse? and shiplu's answer. This is what I came to understand. Please correct me if I'm wrong.
In eclipse, when I use come external class, I can use Quick-Assistant or Organize imports (Ctrl-Shift-O) to resolve the reference. Eclipse adds the package that contains the class in Imported Packages for the project that I'm working on. A package can contain multiple classes (types). Eclipse understands what plugin contains the package, and resolve the reference issues.
A plug-in (jar file) can contain multiple packages. By specifying a required plug-ins in the dependencies tab, we can reference all the packages (and classes in the packages) for all the java projects in the eclipse IDE.
And from my experience, I had to add all the dependencies in order to make headless RCP standalone (http://prosseek.blogspot.com/2012/12/headless-rcp-standalone.html).
An Eclipse plug-in is basically an OSGi bundle with additional plugin.xml file which Eclipse IDE understands and interprets.
So the answer to your question lies in the OSGi specification and the OSGi programming model, since, very simply put, Eclipse is an Application running on implementation of OSGi called Equinox.
OSGi is all about having modular applications and so it defines several levels of modularity.
One such level is a bundle-level (module-level) modularity and more fine grained level is the package level modularity.
So you can have your OSGi application (a set of bundles; eclipse is just that) which consists of db-bundle (which provides data store services), app-domain-bundle (which provides your application domain services) and remote-bundle (which exposes to the web your application via REST for example).
And then you say remote-bundle depends on domain-bundle which depends on db-bundle.
Which is all good, but cripples the inherent modularity OSGi provides, because you are basically restricting your application to specific implementations of db-bundle and remote-bundle i.e. to specific implementations of the services they provide.
Instead, you can establish the above dependencies not between bundles but between packages i.e. establish a service-level dependencies.
Then you say domain-bundle requires dbstore.service package to run, it doesn't care which bundle provides it it just needs an instance of this service to be able to work. So you can have multiple bundles providing implementations of the dbstore.service, and the domain-bundle can pick and choose at runtime what service to use.
It is really hard to explain OSGi concepts in just a several sentences, I'd really suggest you dig around the web on this and maybe even have a look at the OSGi specification.
Another way to explain it is to say that bundle/plug-in is a jar file with specific structure and metadata descriptors (MANIFEST.MF and plugin.xml), which describe its contents in Java language concepts - which java packages and services this specific jar contains and will expose to the OSGi runtime so that they can be consumed by other bundles. I.e. the bundle is the physical deployable entity while the descriptors are metadata about what actually is being deployed.
EDIT:
Package or Service-level dependencies also have some drawbacks, as Lii points out in the comments below, the main one being that it adds complexity and dynamics to the dependency model. Have a look at her or his comment below - it is worth reading!
You use Imported Packages when you want to use a specific package but do not care which plugin provides it. OSGI will choose one for you.
Eclipse plugins is something like extension to the IDE itself. But imported packages are actually packages that you'll use in your current project.
One is for development IDE another is for the project you are coding.

OSGi + Logback + slf4j - Eclipse Run Configuration

Here is my configuration:
We are developing an OSGi application and want to include logging. I decided to use slf4j + logback.
We are using Eclipse as an IDE and Tycho to benefit from the Eclipse IDE like Manifest Editor and so on.
So I have tried the following:
Created a new plugin with the following Manifest.mf:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Createcommand
Bundle-SymbolicName: de.hswt.oms.ws.wsr.createcommand
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: de.hswt.oms.ws.command.wsr,
de.hswt.oms.ws.ds.core.data.impl,
org.slf4j
Service-Component: OSGI-INF/component.xml
Now when i move to Run -> Run Configurations -> OSGi Framework and select my Bundle and click "Add Required plugins" more than 100 Bundles will be selected and I get a lot of errors and exceptions.
So I came up with a new plugin from existing Jars which include the following three jars:
logback-classic-1.0.7
logback-core-1.0.7
com.springsource.slf4j.api-1.6.1 (I dont believe this is a good idea, but hey...)
If I create a new run configuration manually (not clicking "add required bundles" it works as expected but as far as I click "add required bundles" I come back to the more then 100 Bundles with a lot of errors (some Jetty stuff for example...)
So my Question is: How can I enable logback and slf4j in my OSGi application and use it within eclipse and configure it properly?
If you need more information please feel free to ask.
AFAIK there are some issues in the bundle manifest header in the current official Logback/SLF4J jars. However, you only need the following three jars/bundles. No other are required for the basic functionality.
SLF4J API
Logback Core
Logback Classic
At Eclipse we put the bundles in Orbit for re-use across projects. We apply some modifications to the manifest header that we think are beneficial. For example, we deliver the actual SLF4J binding as a fragment to avoid the circular dependency of the original SLF4J API jar.
Here are the download links to the bundles:
org.slf4j.api
ch.qos.logback.core
ch.qos.logback.classic
ch.qos.logback.slf4j
You may also want:
org.slf4j.ext
org.slf4j.jcl (Commons Logging via SLF4J)
org.slf4j.jul (Java Logging Bridge)
org.slf4j.log4j (LOG4J via SLF4J)
Please note that "Add Required plugins" is not smart enough. It may select too many or too few plug-ins. Sometimes service API is delivered in one bundle but the actual service implementation is delivered in a second bundle. It may not select that bundle.
There is a checkbox saying something like 'Resolve optional imports'. It's on by default, but that pretty much always results in the behaviour you describe, that it wants to add everything.
Switching that off should help. also, PDE tends to add a lot of fragments that are not needed.
All in all, I rarely trust Eclipse with adding the 'right' bundles for runtime. I just use 'validate' and add whatever is needed manually, and check again. It might take a few minutes but figuring out what went wrong when you leave it to PDE can take hours.
Not sure about logback but you may also want to try pax logging. Just install pax logging api and pax logging service and it should work. There is also a documentation how to set it up in eclipse.
If you want it to use with Eclipse Equinox, you could try the Eclipse-BuddyPolicy. This enables one plugin to load all classes from another plugin without importing it explicitly.
This may solve your problem.
Add to your Manifest from the bundle with the jars:
Eclipse-BuddyPolicy: dependent
and to the bundle using the logging
Eclipse-RegisterBuddy: com.other.plugin
see http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fmisc%2Fbundle_manifest.html

eclipse, one classpath for compiling, another for launching

example:
For logging, my code uses log4j. but other jars my code is dependent upon, uses slf4j instead. So both jars must be in the build path. Unfortunately, its possible for my code to directly use (depend on) slf4j now, either by context-assist, or some other developers changes. I would like any use of slf4j to show up as an error, but my application (and tests) will still need it in the classpath when running.
explanation:
I'd like to find out if this is possible in eclipse. This scenario happens often for me. I'll have a large project, that uses alot of 3rd party libraries. And of course those 3rd party jars have their own dependencies as well. So I have to include all dependencies in the classpath ("build path" in eclipse) for the application and its tests to compile and run (from within eclipse).
But I don't want my code to use all of those jars, just the few direct dependencies I've decided upon myself. So if my code accidentally uses a dependency of a dependency, I want it to show up as a compilation error. Ideally, as class not found, but any error would do.
I know I can manually configure the classpath when running outside of eclipse, and even within eclipse I can modify the classpath for a specific class I'm running (in the run configurations), but thats not manageable if you run alot of individual test cases, or have alot of main() classes.
It sounds like your project has enough dependency relationships that you might consider structuring it with OSGi bundles (plug-ins). Each bundle gets its own classloader and gets to specify what bundles (and optionally what version ranges, etc.) it depends on, what packages it exports, whether it re-exports stuff from its dependencies, etc.
Eclipse itself is structured out of Eclipse plug-ins and fragments, which are just OSGi bundles with an optional tiny bit of additional Eclipse wiring (plugin.xml, which is used to declare Eclipse "extension points" and "extensions") attached. Eclipse thus has fairly good tooling for creating and managing bundles built-in (via the Plug-in Development Environment). Much of what you find out there may lead you to conflate "OSGi bundle" with "plug-in that extends the Eclipse IDE", but the two concepts are quite separable.
The Eclipse tooling does distinguish rather clearly (and sometimes annoyingly, but in the "helpful medicine" way) between the bundles in your build environment vs. the bundles that a particular run configuration includes.
After a few years of living in OSGi land, the default Java "flat classpath" feels weird and even kind of broken to me, largely because (as you've experienced) it throws all JARs into one giant arena and hopes they can sort of work things out. The OSGi environment gives me a lot more control over dependency relationships, and as a "side effect" also naturally demands clarification of those relationships. Between these clear declarations and the tooling's enforcement of them, the project's structure is more obvious to everyone on the team.
if my code accidentally uses a dependency of a dependency, I want it to show up as a compilation error. Ideally, as class not found, but any error would do.
Put your code in one plug-in, your direct dependencies in other plug-ins, their dependencies in other plug-ins, etc. and declare each plug-in's dependencies. Eclipse will immediately do exactly what you want. You won't be offered dependencies' dependencies' contents in autocompletes; you'll get red squiggles and build errors; etc.
Why not use access rules to keep your code clean?
It looks like it would better be managed with maven, integrated in eclipse with m2eclipse.
That way, you can only execute part of the maven build lifecycle, and you can manage separate set of dependencies per build steps.
In my experience it helps to be more resrictive, I made the team filling out (paper) forms why this jar is needed and what license...
and they did rather type in a few lines of code instead of drag along 20 jars to open a file using only one line of code, or another fancy 'feature'.
Using maven could help for a while, but when you first spot jars having names like nightly-build or snapshot, you will know you're in jar-hell.
conclusion: Choose dependencies well
Would using the slf4j-over-log4j jar be useful? That allows using slf4j with actual logging going to log4j.