extend war package imports in gemini container - java

if i deploy a war-file into a gemini container (e.g. virgo has one) it will be transformed on-the-fly into an osgi bundle by adding some package imports (besides other things).
Is it possible to somehow extend these default package imports using for example a bundle-listener or something like this?
regards

I would strongly recommend that you do the transformation yourself before deploying into the Gemini container, rather than forcing Gemini to do the transformation on-the-fly. First it is very easy to do; second it will be much faster to deploy; third you will be able to add the specific imports that you want.
In order to turn a standard WAR file into a WAB (Web Application Bundle) that remains compatible with traditional WAR deployment, you just need to add the following headers to the MANIFEST.MF of the WAR:
Web-ContextPath to define the context path under which the web application will be served
Set Bundle-ClassPath to WEB-INF/classes plus any JARs under WEB-INF/lib. You will have to name these explicitly e.g.: Bundle-ClassPath: WEB-INF/classes,WEB-INF/lib/a.jar,WEB-INF/lib/b.jar...
Import-Package: javax.servlet,javax.servlet.http plus anything else you want to import.

Related

Websphere: Shared libraries in common classloader earlier on classpath than application modules, even with parent last policy

Background:
I have the following problem: I have several WAR files I need to have deployed on same Websphere server. The WAR files use libraries that depend on having a specific version of XMLSec regisered as the XML Signature Provider (with the Java Security class). Currently I bundle this library with each WAR file (since the WAR files also need to work standalone and on Tomcat's without any special shared library configuration etc.). Each WAR files registers the provider with Security.addProvider() in a ServerContextListener. But this causes problems in the multi-WAR setup, because if one WAR file does the registration with Security.addProvider) and another WAR files tries to fetch it using the XMLSignatureFactory class (which is actually a javax.* class contained inside the XMLSec JAR itself, but which ultimately calls back to the global provider list configured with Security.addProvider), then it causes a ClassCastException inside XMLSignatureFactory, because this class does a cast of what it gets from Security into to its own version of the provider classes, which doesn't work. The exact stack trace is as follows:
Caused by: java.lang.ClassCastException:
org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory
incompatible with javax.xml.crypto.dsig.XMLSignatureFactory at
javax.xml.crypto.dsig.XMLSignatureFactory.findInstance(XMLSignatureFactory.java:202)
at
javax.xml.crypto.dsig.XMLSignatureFactory.getInstance(XMLSignatureFactory.java:292)
By the way this is not a case of conflict with different versions of XMLSec being in play or conflicts with Websphere's own version. There is only one version albeit it is loaded from different WAR's.
Of course the solution is to have the xmlsec library loaded with a common classloader so that there is only one version of the classes loaded that all WAR files see, which would avoid ClassCastExceptions etc.. But here is the rub: I also need to have each application loaded with the "parent last" policy - or rather, I need the JAR files inside each application to take precedence over Websphere's built-in version of the libraries (for instance Axis2 that I also include in the WAR filesetc.). Furter, I would prefer that I can keep the xmlsec library in each WAR files' WEB-INF/lib folder, so that the WAR files can still work stand-alone (i.e. in other environments which might not have the shared library configured etc.).
So basically I want to have a common class loader loading the XMLSec library, say, somewhere from disk. Let's denote that [SHARED XMLSEC]. Then I want each application classpath to ultimately appear like this:
App1: [SHARED XMLSEC][App1 WEB-inf/lib][Websphere libraries][JDK libraries]
App2: [SHARED XMLSEC][App2 WEB-inf/lib][Websphere libraries][JDK libraries]
etc.
In such a configuration it doesn't matter if App1+App2 themselves contain the XMLSec library since the shared one will take precedence so they will use the common one. At the same time, App1+App2 are still free to override other built-in Websphere libraries (Axis2).
Is it possible to realize this configuration and what options do I need to set? Do you see alternative ways to achieve the same objective?
Since you have a conflict between classes here, I would suggest going for isolated class loaders for each application. On the server side, setting the class loader policy to 'Multiple' should provide isolation between applications.
Once you have this set, configure class loading at the application level to the 'Parent last' configuration for both the applications.
The following Knowledge Center link has the relevant instructions [Steps 2,3 & 4 under the 'Procedure' section] :
http://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/trun_classload.html
[Note: The version of WAS in use is not specified in the question. The Knowledge Center link refers to version 8.5.5.]

JAXB package-info.java declarations are ignored in separate maven modul

I use package-info.java to specify #XmlAccessorType(XmlAccessType.NONE) and some xml java adapters using #XmlJavaTypeAdapters. Model objects (with JAXB annotations) are placed in separate maven module shared by other modules. The configuration in package-info.java is not discovered if model objects are in separate maven module. If I move for testing purposes model objects to same maven module everything is OK. I think separate maven module can be considered equivalent to 3rd party lib from JAXBContext point of view. I use JDK1.7 JAXB reference implementation. Any ideas how configuration may differ?
I also encounter this problem, in my case qualified/unqualified property from package-info.java was ignored. I managed to find two way to workaround this:
like Pavla wrote, copy all JAXB classes with package-info.java locally
include module as a dependency with compile scope (which gives similar result that classes are in module. In my case I created separate jar lib with JAXB classes)
I also spotted that it do not work only in case of creating WebServices (creating object and sending to WS works fine in different modules).
I am using Jbossas7.1.1 and cxf 2.4.6. In the time of registering service Jboss created wsdl from JAXB (in my case path /opt/jboss/jboss-as-7.1.1.Final/standalone/data/wsdl/module.war/SubmitMessage.wsdl). In local setting file is generated properly.
Any ideas why creating WS behaves like this?
I hit this issue recently and the actual problem (with Java 8, i.e. no Java modules involved) was that I had on the classpath two *.jar files which both contained the same package - in one JAR, there was package-info.class with JAXB annotations and in the other one, there wasn't.
In that case, I guess that if package-info.class file is discovered depends on the classpath ordering (which is very brittle and only semi-deterministic).

Apache Felix Host expose dependencies OSGi

I am using Apache Felix to create an embedded OSGi host application. I am using the following code to expose the packages I want to expose:
List<String> extra = new ArrayList<>();
extra.add("some.example.packag.to.expose.1");
extra.add("some.example.packag.to.expose.2");
extra.add("some.example.packag.to.expose.3");
config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, extra.toString().replace("[","").replace("]", ""));
Everything works great and these packages are exposed. However, I need the bundles to have access to ALL the host project declared dependencies. So for example the parent application has Jackson, Apache (various), etc. declared and I need the bundles to have access to these.
I tried adding the packages explicitly but that does not seem to do the trick when they are dependencies. So for example in the bundle I want to use Jacksons com.fasterxml.jackson.core.type.TypeReference; so I added com.fasterxml.jackson.core.type to the above EXTRA list but it does not appear to solve the problem, the package still doesn't get exposed.
In a perfect work I just want to make ALL the host dependencies available without having to explicitly state each one.
You will have to configure each package. In OSGi you would normally install the dependencies as bundles. So the settings do not suppot to mass export system packages.

JCE security provider in OSGi

We have a problem using a custom JCA implementation in our OSGi bundle. The JCA implementation that we are forced to use by our customer leads to a class loader memory leak. This prevents the deployment and usage of it in our bundle, because we quickly run into a perm gen space problem.
The proposed solution from the JCA provider is to put the JAR in the jre/lib/ext folder, but it is not loaded from there. This is due, as far as I know, to the OSGi (Eclipse equinox) class loader policy to have the bootstrap classloader as the parent of each bundle classloader, which excludes the extension class loader that loads from the jre/lib/ext folder. I.e. no bundle ever sees anything in the jre/lib/ext folder.
Is there a way to get Eclipse equinox to load a jar that is registered as a security provider, only once, such that all bundles or a specific bundle can see that provider? The fact that the JCA library is not unloaded via OSGi could be tolerated in this instance.
You should edit the system packages and add the packages from the JCA-custom.jar.
You can define which packages should be included in several ways.
You create a profile for equinox and define the packages. You can find examples for each jdk versions in the eclipse.osgi jar. For example, look for JavaSE-1.6.profile and try finding the entry org.osgi.framework.system.packages
You can define it as a system variable when you start your OSGi container. The system variable is the same: -Dorg.osgi.framework.system.packages=package names separated by comma

OSGI bundle .bnd file and conflicting import-package statements

I inherited a .bnd file that has the import !javax., and my program produces runtime errors if I take out that statement. I currently need to add JavaHelp to my application, which is under javax.help.. When I have both of those imports in my .bnd and I use a class from JavaHelp, it produces a ClassNotFoundException for the specific class, like javax.help.JHelp. Is there a way to handle this situation, I feel stuck.
Bundles generally need to import all the package that do not start with "java.". This includes "javax." packages. If your bnd file explicitly does not import javax. package, then it must rely upon non-standard boot delegation configuration for the framework. That is, the boot delegation provides "free" access to javax. packages from the bundles parent classloader (likely the bootclassloader). So when you remove !javax. from the bnd file, your bundle starts to import those packages from some provider which may not be the same as whatever bootdelegation is providing.

Categories