Peter Jaloveczki
Peter Jaloveczki

Reputation: 2089

How to use OSGI Embed-Dependency for common 3rd party JAR-s

I have a Liferay system with several portlets. Most of these portlets have redundant JSF related JAR-s in them so I would like to remove the redundancy, and create an OSGI bundle for the commonly used JAR-s.

The idea would be that all of my portlets would use this common bundle as a dependency.

After some reading about I ended up with something similar in my maven pom:

<plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <version>2.3.4</version>
            <extensions>true</extensions>
            <configuration>
                <remoteOBR>true</remoteOBR>
                <instructions>
                    <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                    <Bundle-Name>${project.name}</Bundle-Name>
                    <Bundle-Vendor>${project.organization.name}</Bundle-Vendor>
                    <Import-Package>
                        !sun.reflect,......,*
                    </Import-Package>
                    <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                    <Embed-Transitive>true</Embed-Transitive>
                </instructions>
            </configuration>
        </plugin>

And I ended up with the following bundle jar:

My Manifest:

Manifest-Version: 1.0
Bundle-SymbolicName: my-common-bundle
Built-By: pjaloveczki
Bundle-ManifestVersion: 2
Bnd-LastModified: 1537882770915
Embed-Dependency: *;scope=compile|runtime
Import-Package: com.liferay.portal.kernel.exception,com.liferay.portal
 .kernel.language,com.liferay.portal.kernel.model,......,org.w3c.dom.styleshe
 ets,sun.misc
Tool: Bnd-1.15.0
Bundle-Name: my-common-bundle
Bundle-Version: 1.0.0
Bundle-ClassPath: .,sac-1.3.jar,...all..my..dependecies...,com.liferay.faces.bridge.api-4.1.0.jar
Ignore-Package: net.sf.cglib.proxy,..all..ignored..packages...javax.ejb
Embed-Transitive: true
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_171

Content:

enter image description here From what I can see, this is exactly what I needed, at least this is how I pictured it.

In my consuming portlet I added the following to my manifest:

Require-Bundle: my-common-bundle;bundle-version="1.0.0"

I figured something like this should work, however I am obviously wrong as when I try to deploy my portlet one of the classes is not being found provided by the common bundle:

java.lang.ClassNotFoundException: org.richfaces.webapp.ResourceServlet cannot be found by MyPortlet

On the other hand if I add the following to my common bundle:

<Export-Package>org.richfaces.webapp</Export-Package>

The class is found, but I am ended up with this:

enter image description here

So essentially I have the class twice once in the JAR and once flattened out, even though it's kind of starting to work.

There are several reason I don't like this approach:

  1. I would prefer using structured jars because I consider it cleaner
  2. Most of these jars contain configuration files that could overlap if I flatten everything out
  3. There must be a way to use embedded jars properly since otherwise this feature would not exist

Can anyone help, what it the proper way to use these embedded jars in an OSGI without having to flatten them out?

Thank! Peter

EDIT:

It seems that classes are being deployed fine and are resolved after I've added <_exportcontents>!org.apache.commons.logging,*</_exportcontents>

however I am getting different types of errors which I am not getting when I put my JARs in my portlets.

Previously I was getting ClassNotFoundErrors and such, now I am getting:

java.lang.NullPointerException
    at javax.faces.CurrentThreadToServletContext.getFallbackFactory(CurrentThreadToServletContext.java:79)
    at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:551)
    at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:283)
    at javax.faces.webapp.FacesServlet.init(FacesServlet.java:358)


java.lang.NullPointerException
        at javax.portlet.faces.GenericFacesPortlet.getBridgeClassName(GenericFacesPortlet.java:193)
        at javax.portlet.faces.GenericFacesPortlet.getBridge(GenericFacesPortlet.java:762)
        at javax.portlet.faces.GenericFacesPortlet.init(GenericFacesPortlet.java:448)
        at com.liferay.portlet.InvokerPortletImpl.init(InvokerPortletImpl.java:297)

It seems to me classes are loaded, but the JAR manifests are not being processed or something similar. Any ideas?

Upvotes: 2

Views: 709

Answers (1)

awd
awd

Reputation: 2322

you can use <_exportcontents> instruction to export the content without duplication, more about it here

I would like to point out that creating fat jars is against the very idea of OSGi, also, this is going to be a nightmare to maintain when your code evolves.

Ideally you would want to have a separate bundle for each dependency. They should be deployed and maintained separately.

Upvotes: 2

Related Questions