Troubleshooting

October 8, 2024

This section aims to offer a few troubleshooting tips, mostly based on Jahia’s own experience of migrating or creating OSGi projects.

Java Profiling

As the OSGi framework consists of many class loaders interacting with each other, the usage of a profiling tool, especially one that uses instrumentation such as YourKit, often requires some custom framework settings.

Here is an example on how to configure YourKit for profiling Jahia. In the digital-factory-data/karaf/etc/custom.properties, make sure you have the YourKit packages declared in the bootdelegation property:

org.osgi.framework.bootdelegation=sun.*,com.sun.*,com.sun.jndi.ldap,com.yourkit.*,__redirected

If using another profiler, you might have to also add the profiler packages to the boot delegation property. By default, Jahia comes pre-configured for profiling with YourKit. You can find an interesting blog entry that gives example for different profilers here: http://blog.knowhowlab.org/2010/03/osgi-tips-osgi-profiling-yourkit.html

Common OSGi-related errors and their solutions

Missing dependencies when deploying OSGi module

Missing dependencies are one of the most common problem a newcomer to OSGi will face, especially when migrating an existing non-OSGi module. Here’s an example of a log entry that illustrates the problem of a missing dependency:

2014-04-11 16:33:23,324: ERROR [Activator] - Unresolved constraint in bundle filesync [118]: Unable to resolve 118.0: missing requirement [118.0] osgi.wiring.package; (osgi.wiring.package=com.ibm.uvm.tools)
org.osgi.framework.BundleException: Unresolved constraint in bundle filesync [118]: Unable to resolve 118.0: missing requirement [118.0] osgi.wiring.package; (osgi.wiring.package=com.ibm.uvm.tools)
    at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3974)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2037)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:942)
    at org.jahia.bundles.extender.jahiamodules.Activator$BundleStarter.startAllBundles(Activator.java:870)
    at org.jahia.bundles.extender.jahiamodules.Activator$BundleStarter.frameworkEvent(Activator.java:851)
    at org.apache.felix.framework.util.EventDispatcher.invokeFrameworkListenerCallback(EventDispatcher.java:835)
    at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:785)
    at org.apache.felix.framework.util.EventDispatcher.run(EventDispatcher.java:1088)
    at org.apache.felix.framework.util.EventDispatcher.access$000(EventDispatcher.java:54)
    at org.apache.felix.framework.util.EventDispatcher$1.run(EventDispatcher.java:101)
    at java.lang.Thread.run(Thread.java:744)

If a module doesn’t start because of missing dependencies, the easiest way to diagnose this is to use the OSGi Web Console and look at the bundle dependencies detail view (by expanding the bundle details by clicking on the little arrow at the left of the bundle’s name). It should look something like this:

As you can see in the above screenshot, the missing dependencies are highlighted in red. This means that the highlighted packages could not be resolved from another other bundle exporting packages or from the system (framework) bundle.

One quick and dirty way to solve this would be to simply mark all the unresolved packages as optional. This way the module will start, but it might not work, as some of these dependencies might actually be required for proper operation of the deployed module. You could use this as a integration phase, but proper package-use analysis is required to make sure no functional regressions will occur when resolving dependencies.

Adding the package dependencies as optional would require changing the Import-Package instruction of the Felix Maven bundle plugin to something like this:

<Import-Package>
    com.ibm.uvm.tools;resolution:=optional,
    com.jayway.jsonpath;resolution:=optional,
    com.jcraft.jsch;resolution:=optional,
    com.sun.jdmk.comm;resolution:=optional,
    com.sun.tools.javac;resolution:=optional,
    javax.jmdns;resolution:=optional,
    javax.jms;resolution:=optional,
    joptsimple;resolution:=optional,
    junit.framework;resolution:=optional,
    kaffe.rmi.rmic;resolution:=optional,
    org.apache.avalon.framework.logger;resolution:=optional,
    org.apache.bsf;resolution:=optional,
    org.apache.env;resolution:=optional,
    ...
    ${jahia.plugin.projectPackageImport},
    *</Import-Package>

To help understand where a package is used, you can use the Jahia Maven find-package-uses goal as in the following example:

mvn jahia:find-package-uses -DpackageNames=com.ibm.uvm.tools

You will get a result similar to this:

[INFO] =================================================================================
[INFO] SEARCH RESULTS SUMMARY
[INFO] ---------------------------------------------------------------------------------
[INFO] Package com.ibm.uvm.tools used in classes :
[INFO] org.apache.log4j.spi.LocationInfo ( /Users/loom/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar)
[INFO] ------------------------------------------------------------------------

We can therefore understand that the com.ibm.uvm.tools package is used inside a Log4J class. If we really wanted to dig deep, we could look at the source code for the Log4J project since we now have the proper information for the library dependency as well as the version of the code. We have found the source file in the public SVN repository here: http://svn.apache.org/viewvc/logging/log4j/tags/v1_2_17/src/main/java/org/apache/log4j/spi/LocationInfo.java?view=markup

// Check if we are running in IBM's visual age.
static boolean inVisualAge = false;
static {
    try {
        inVisualAge = Class.forName("com.ibm.uvm.tools.DebugSupport") != null;
        LogLog.debug("Detected IBM VisualAge environment.");
    } catch(Throwable e) {
        // nothing to do
    }

As we can see this package is accessed to check the existence of a class, so it is probably safe to mark it as optional in our dependencies. This concludes the dependency analysis for the first package, and it should be repeated for each unresolved dependency. If a dependency is resolved to be required, we should then add a bundle that provides the dependency (see Using libraries in an OSGi module for more information).

JSP compilation error due to missing MANIFEST dependencies

PWC6197: An error occurred at line: 222 in the jsp file: /jnt_petition/html/petition.full.jsp
PWC6199: Generated servlet error:
ServicesRegistry cannot be resolved
org.apache.jasper.JasperException: PWC6033: Unable to compile class for JSP
PWC6199: Generated servlet error:
Only a type can be imported. org.jahia.registries.ServicesRegistry resolves to a package
PWC6197: An error occurred at line: 222 in the jsp file: /jnt_petition/html/petition.full.jsp
PWC6199: Generated servlet error:
ServicesRegistry cannot be resolved

This may happen if no entry in the MANIFEST.MF was added for the org.jahia.registries package. The cause may either be:

  • The Jahia Maven Plugin was not configured with the jahia:dependencies goal
  • The module is a legacy WAR format and automatic transformation is missing the dependency

Possible solutions

  • Modify the project to become an OSGi module if possible (meaning that it will only work on DX 7.0 and above)
  • Add the package to the global list of imports for all the transformed modules. This list can be added the WEB-INF/etc/config/felix-framework.properties. The default value comes from the applicationcontext-felix.xml file.

LinkageError

This happens when the same class is loaded twice from different bundles. For example, two bundles working together that both use different versions of SLF4j and one embeds it.

Solution

Externalize the classes into separate bundles and use import package statements with precise versions to make sure you reduce the possibilities for conflicts

Large amount of imports generated by the Maven plugins

If you have a large amount of imports being generated by the Maven plugins, this might not always be a good thing, since having many dependencies will make your module difficult to deploy

Solution

There are two possibilities:

  • Manually edit the Import-Package instructions for the Maven Bundle plugin
  • Embed dependencies that are pulling too many transitive dependencies

In the first solution, you will have complete control over the Import-Package instructions so you shouldn’t have any problems. The main downside of this solution is that it is a bit tedious to first setup since it mostly a trial and error loop of building, deploying over and over until the bundle properly starts. This can take some time initially but the dependencies should rapidly stabilize and then they will usually not need to be modified until another dependency is introduced or modified. Also, using this technique you can also properly specify package dependency version ranges, which is also a good thing for the flexibility of an OSGi bundle deployment.

The second solution usually takes less time to setup, but it will also require some trial and error before it will work properly, although it should be much shorter than the first solution. However, the generated imports might not be minimal and you might still be importing packages that are referenced for example in dead code. Also, it is not a good OSGi practice to embed too many dependencies since it will make the bundles much larger and potentially cause conflicts if the dependencies are ever exported.