Archiv der Kategorie: Allgemein

Java 11, JAXB and osgi

Starting with Java 11, several packages have been “hard-removed” from the JRE itself (For Java 9 and 10 they were simply re-activateable by using a parameter) – one of those being the javax.xml.bind package, which used to provide (together with others) the JAXB implementation.

Updating our product to become Java 11 compatible, proved to be a major task, but finally it seems I managed to do it. So here are the effective steps resp. pitfalls that one will run into:

  • The JAXB packages are not available anymore – how to find them?
  • My bundles have to run on both Java 8 and Java >8 – how to achieve this?
  • Tycho is reluctant to build this, i miss packages
  • The concrete JAXB implementation seems not to be found, because OSGi – how to fix this?

The missing JAXB packages

In order to find replacements for the now missing bundles, we have to find the right set applicable for OSGi. I managed to identify the following maven bundles:

com.sun.activation:javax.activation:1.2.0
javax.xml.bind:jaxb-api:2.4.0-b180830.0359
com.sun.xml.bind:jaxb-osgi:2.4.0-b180830.04

You can use a maven tool like p2-maven-plugin to create a p2 repository with these requirements for later inclusion. Have a look at our own dependency repo for an example.

Run ’em on both Java 8 and Java >8

OSGi R7 introduced the support for multi-release jars. These are bundles, where, dependent on the java version you use, different manifest information is to be applied.

The following picture shows an example where for Java >=9 the Import-Package of the original manifest is replaced to import com.sun.xml.bind.v2. The resp. Import-Package will not be used for Java <=8. In order to activate this, the main manifest has to be extended with Multi-Release: true

The MANIFEST.MF in versions/9/OSGI-INF extends the original manifest for Java > 8

Tycho: com.sun.source where are you?

Caveat Building with Java 11 does not yet work – all builds are done using Java 8

While com.sun.xml.bind.jaxb-osgi 2.4.0.b180830_0438 works fine within the IDE, when building your product trouble is on the horizon.

com.sun.xml.bind.jaxb-osgi 2.4.0.b180830_0438 formally requires the packages com.sun.source.tree and com.sun.source.util which are not provided to OSGi as they are expected to be made available by the JRE. At runtime, org.eclipse.osgi_3.13.100.v20180827-1536 cares for this but at build and package time it is not satisfied.

This can be fixed by providing a special fragment with Fragment-Host: system.bundle; extension:=framework which may then be included to your feature.

See https://github.com/eclipse-ee4j/jaxb-api/issues/92 for the detailed problem description and http://blog.meschberger.ch/2008/10/osgi-bundles-require-classes-from.html for infos on its solution.

My own solution to this problem is shown in the following image:

Providing com.sun.source.tree and com.sun.source.util to the OSGi environment

Implementation of JAXB-API has not been found

At runtime javax.xml.bind.ContextFinder.newInstance is used to create a JAXB object that is actually performing the work. ContextFinder is part of the java-api bundle, and the actual JAXB implementation it tries to find is provided by com.sun.xml.bind.jaxb-osgi.

Now in OSGi we face the problem of the classloaders per bundle being separate. In https://github.com/eclipse-ee4j/jaxb-api/issues/78 the problem of jaxb-api not able to find the real jaxb api implementation is documented.

The exception that identifies this problem looks like this

[java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]


Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:269) ~[na:na]
… 93 common frames omitted

Caused by: java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583) ~[na:na]
… 97 common frames omitted

As far as I know, there are currently 2 solutions to this problem:

1. Add Import-Package for com.sun.xml.bind.v2 for each bundle and adapt JAXBContext.newInstance to use a bundle local classloader

2. Provide a fragment bundle for java-api that adds the dependency to the jaxb-api implementation package.

After trying the first approach, I though that I have to modify to much of the existing code – hence I moved to the second approach.

The first image in this blog post actually shows this fragment.

The pain of configuring JSP in Jetty OSGi

As part of a recent project I want to run mitreid connect server embedded within the Elexis-Server Neon.3 based Jetty instance (that is version 9.3.9.v20160517).

Despite the excellent Jetty documentation on this version, I faced major trouble on getting to run this right.

My status / approach was this: First of, I want to run the plain war file provided within a WebAppContext of the Jetty container. This did not prove to be much of a problem, a simple Activator like this achieved this:

@Override
public void start(BundleContext context) throws Exception {
	WebAppContext webapp = new WebAppContext();
	Dictionary props = new Hashtable();
	props.put("war", "lib/openid-connect-server-webapp.war");
	props.put("contextPath", "/openid");
	props.put("managedServerName", "defaultJettyServer");
	context.registerService(ContextHandler.class.getName(), webapp, props);
}

But now the real trouble started – J S P !

The trouble can be broken down into three steps

  1. Configuring the JSP implementation
  2. Setting up the JSTL (Standard Tag Library)
  3. Configuring the WebAppContext to use all of this

Configuring JSP (Apache Jasper implementation)

This is pretty much straightforward, as documented in Using JSPs.
Just one thing is a little hidden – you additionally need apache aries.

Here goes a (hopefully) complete list

      id="javax.servlet.jsp.jstl"
      id="org.apache.aries.spifly.dynamic.bundle"
      id="org.apache.aries.util"
      id="org.eclipse.core.commands"
      id="org.eclipse.core.expressions"
      id="org.eclipse.core.filesystem"
      id="org.eclipse.core.resources"
      id="org.eclipse.jdt.core"
      id="org.eclipse.jetty.apache-jsp"
      id="org.eclipse.jetty.osgi.boot.jsp"
      id="org.eclipse.text"
      id="org.glassfish.web.javax.servlet.jsp.jstl"
      id="org.mortbay.jasper.apache-el"
      id="org.mortbay.jasper.apache-jsp"
      id="org.objectweb.asm"
      id="org.objectweb.asm.commons"
      id="org.objectweb.asm.tree"

Setting up the JSTL (Glassfish approach)

This is where I started to have problems. Documentation says to include org.glassfish.web:javax.servlet.jsp.jstl-1.2.2.jar which did not work out using Java 8. Eclipse complained with

I could track this down and reverted to org.glassfish.web:javax.servlet.jsp.jstl-1.5.0-b03.jar to solve this.

Configuring the WebAppContext to use all of this

At least the dependencies seemed to be satifisied by now – but did it start? No – but
a new Exception occured


2018-01-18 15:21:13,280 WARN  o.e.jetty.servlet.ServletHandler - 
org.apache.jasper.JasperException: Unable to compile class for JSP
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:600) ~[org.mortbay.jasper.apache-jsp_8.0.33.jar:2.3]
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:363) ~[org.mortbay.jasper.apache-jsp_8.0.33.jar:2.3]
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396) ~[org.mortbay.jasper.apache-jsp_8.0.33.jar:2.3]
...
Caused by: java.lang.NullPointerException: null
	at org.apache.jasper.JspCompilationContext.getTldResourcePath(JspCompilationContext.java:551) ~[org.mortbay.jasper.apache-jsp_8.0.33.jar:2.3]
	at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:420) ~[org.mortbay.jasper.apache-jsp_8.0.33.jar:2.3]

This post left me with some
hints on what could be the problem. It breaks down to the JettyJasperInitializer#onStartup not being called and some configurations missing.

Some more searches brought me to the embedded-jetty-jsp sample project where this was initialized. (I had to use the non-jetty-annotations approach, as I also use org.eclipse.gemini.naming in the container, already providing a JNDI implementation).

I extracted the JspStarter from the mentioned project, and modified the Activator

webapp.addBean(new JspStarter(webapp.getServletContext().getContextHandler()));

and now it works – the journey continues! Hope this blog spares somebody else some trouble!

e4 RAP and trimless fullscreen windows

After starting to set up an e4 based RAP application, one of the thirst things that popped into my eyes was the Windows in Windows Problem. That is, you have your browser opening the e4 rap application and you see a window title (which effectively exists for both Window and TrimmedWindow) which does not make much of a sense. For RAP based on 3.x here is the solution. For e4 based RAP it required some investigation, so here goes the solution.

Add a TrimmedWindow or Window element, and provide the tag shellMaximized and the persistentState value styleOverride (thanks to Lars Vogel for pointing this out) where the value is determined like you would set it programmatically with


int val = SWT.NO_TRIM;
System.out.println(val);

thats just like in the following example:
fullscreenRAP

Dynamic menu contributions

Bug 389063 introduced dynamic menu items within the Eclipse 4 application model. Today Paul Webster pushed the commit to platform.ui so it is ready to show starting with tonights integration build or the upcoming Kepler M4.

But what is it, and how to use it? During development I started a sample project on called at.descher.eclipse.bug389063 that is the first to take usage of the new feature. It is accessible on my github repository.

Generally, dynamic menu contributions are added to a menu just like other elements of the form HandledMenuItem or DirectMenuItem. But instead of representing only one element they can be instantiated dynamically by anything your code wants it to show. This is similar to the dynamic menu contribution one could add in Eclipse 3.x using the org.eclipse.ui.menus extension point.

Corresponding to the Eclipse application model you now have to insert a respective menu:DynamicMenuContribution element, an example is shown in the following code snippet:

<children xsi:type="menu:DynamicMenuContribution"
       xmi:id="_JTeEkAp4EeK8ULSwuUCzow" elementId="at.descher.dmc.0"
       label="irrelevantLabelWillNotBeShown"
       contributionURI="bundleclass://at.descher.eclipse.bug389063/
        at.descher.eclipse.bug389063.dynamic.DynamicMainMenuContribution" />
 

Here one can see the reference to the contributionURI which is the class responsible to provide the Dynamic Menu Elements. There are two new annotations available which are evaluated within such contribution classes:

  • @AboutToShow the method carrying this annotation is called when the menu is about to open
  • @AboutToHide the method carrying this annotation is called when the menu is about to close

In order to provide an example I take an excerpt of the respective methods from the class DynamicMainMenuContribution class:

@AboutToShow
public void aboutToShow(List<MMenuElement> items) {
 MDirectMenuItem dynamicItem = MMenuFactory.INSTANCE
   .createDirectMenuItem();
  dynamicItem.setLabel("Dynamic Menu Item (" + new Date() + ")");
  dynamicItem
    .setContributorURI("platform:/plugin/at.descher.eclipse.bug389063");
  dynamicItem
    .setContributionURI("bundleclass://at.descher.eclipse.bug389063/
         at.descher.eclipse.bug389063.dynamic.DirectMenuItemAHandler");
items.add(dynamicItem);

In @AboutToShow an empty list, namely items gets injected. It is to be populated by the developer. The above example shows the addition of a simple MDirectMenuItem which is handled by the DirectMenuItemAHandler class.

Caution Do not put code with a long execution time within this method, as this directly blocks the opening process of the menu, and may look to the user as though the system crashed.

Providing an @AboutToHide method is optional, if one wants to say so, if however one has a reason to use it, the framework takes care about injecting the list populated during @AboutToShow into this method. So the following example shows that the list is not empty, and uses the @AboutToHide annotated method to simply increase a counter.

@AboutToHide
public void aboutToHide(List<MMenuElement> items) {
 System.out.println("aboutToHide() items-size: " + items.size());
 addSecond = !addSecond;
}

There does not yet exist support for the Application Model Editor, but I am working on it. As soon as there is news, I’ll present it here 🙂

Remark Recently I found out about two problems using this dynamic contribution, I already filed the respective Eclipse Bugs in 398866 and 398865.