Monday, March 9, 2020

Make Third Party non OSGi JAR as Liferay Portal Global Library


Liferay 7.2/DXP Portal environment is leveraging OSGi modularity framework.  Sometimes we may need java libraries which is required for all Liferay OSGi modules and these are common JARs to every module. Instead of adding these jars to every module and we can make it global jar.

If any use case which meets the following criteria then we can make specific non-OSGi jar as Global.

  • Any third party or project specific custom jars are non-OSGi libraries
  • JARs are common libraries and required for all Liferay OSGi modules.


Liferay 7.2/DXP Portal already made many of common libraries as global and these jars are available in portal server tomcat/lib/ext directory.

Example


The following are check list before you make any third-party jar as global library.

Verify that Liferay OSGi module required jar already part of portal global library(lib/ext).

Verify that module required specific package in the list of portal property “module.framework.system.packages.extra


Verify that module required specific package in the list of Portal Exported System package list of com.liferay.portal.bootstrap.jar “system.packages.extra.mf”.



Liferay Module Framework already exported many of common libraries as part of portal bootstrap module and these are available to all Liferay OSGi modules.


If the package or jar already not available as global then the following are the steps to add third party non-OSGi jar as global library.

  1. Add required jar in the Portal Tomcat lib/ext directory
  2. Override “module.framework.system.packages.extra” portal property and add required packages in list.
  3. Restart Portal Server


Add required jar in the Portal Tomcat “lib/ext” directory

Download or get required jar libraries and add in the portal tomcat lib/ext.

Take the example Liferay OSGi modules required some JSON libraries and wanted to use google gson library. Download required version of JAR from internet and place it in Tomcat lib/ext.


Override “module.framework.system.packages.extra” portal property and add required packages in list.

Now add jar base package or required packages in the list of “module.framework.system.packages.extraportal property.

Use “portal-ext.properties” file to override portal properties and it should be available in Liferay home directory.


Example portal property in portal-ext.properties

module.framework.system.packages.extra=\
        com.ibm.crypto.provider,\
        com.ibm.db2.jcc,\
       com.google.gson,\
        com.microsoft.sqlserver.jdbc,\
        com.mysql.cj.jdbc,\
        com.mysql.jdbc,\
        com.p6spy.engine.spy,\
        com.sun.security.auth.module,\
        com.sybase.jdbc4.jdbc,\
        oracle.jdbc,\
        org.postgresql,\
        org.hsqldb.jdbc,\
        org.mariadb.jdbc,\
        sun.misc,\
        sun.net.util,\
        sun.security.provider,\
        \
        #
        # WebSocket Support
        #
        \
        com.ibm.websphere.wsoc,\
        io.undertow.websockets.jsr,\
        javax.websocket,\
        javax.websocket.server,\
        org.apache.tomcat.websocket.server,\
        org.eclipse.jetty.websocket.server,\
        org.glassfish.tyrus.servlet,\
        weblogic.websocket.tyrus



Restart Portal Server

Finally restart portal server and now use gson packages anywhere in the Liferay OSGi modules.

Usage in the Liferay OSGi modules

Maven Liferay OSGi module

Add gson dependency in module pom.xml file with provided scope.

Example:

<dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>1.1</version>
   <scope>provided</scope>
</dependency>


Gradle Liferay OSGi module

Add dependency in module “build.gradlecompileOnly group


dependencies {
           
   compileOnly group: "com.google.code.gson", name: "gson", version: "1.1"
           
}




Note:

I just took old gson jar to demonstrate the process of making non-OSGi jars as global. The latest gson jars are OSGi compliance and we can simply deploy into Liferay Module Framework.

Important Points

If we really required or demanded then only, we should make non-OSGi jars as global. We have to avoid this as much possible.
When we make any non-OSGi jars as global then we should also make its transitive dependencies as global.
We cannot make use of multiple versions of implementations to consumer modules and we have to stick with only the version that we added as global.


Author

Saturday, March 7, 2020

Adding Third Party Non OSGi Jars to Liferay OSGi module


Liferay is using OSGi module framework and in real world we may not get all java libraries implementations as OSGi module. Sometimes we may need to add non OSGi jars to Liferay OSGi module. Liferay Module Framework provided a way to add external non OSGi jars in Liferay OSGi module. OSGi bnd tools will be taking care of internal configuration.
  1. The package that Liferay module is using was not available as OSGi module.
  2. The package that Liferay module is using was not exported by Liferay Portal Bootstrap Module.
  3. The package that Liferay module is using was not exported by Liferay Portal Global Class Loader.
  4. The package that Liferay module is using was not exported by any of your custom modules and that already deployed in Liferay Module Framework.

The package imported in Liferay module is satisfying the above criteria then we have to go for adding third party non OSGi jars to Liferay OSGi module.

Take the example that your module need to use apache poi libraries to provide xl sheet related functionality. These jars are non-OSGi and it’s not exported by any of Liferay OSGi framework.

Following are the steps to add Third Party non-OSGi jars

Gradle Liferay OSGi Module

Module Source


Case:1 Add Jar and Its all dependencies

Use “compileInclude” scope dependencies in “build.gradle”, rest of the things will be taken care by gradle build process.

Compile Include configuration is transitive. It will be embedded jar and its dependencies in module lib directory. It will refer all jar references in module MANIFEST.MF “Bundle-ClassPath” header and packages are specified in Private-Package header.

Compile Include will not consider the optional dependencies and if module required optional dependencies then follow the Case:2

Example “build.gradle”


dependencies {
            compileInclude  group: 'org.apache.poi', name: 'poi', version: '4.1.2'
            compileInclude  group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.2'
            }




Case:2 Explicitly specify JARs in  module bnd file

In this case we will use gradle compile scope and bndincluderesource” header to specify jar and its dependencies (if required).

Option: 1

This option will add specified third-party jars in specific directory in the module(in the jar package) and jar references are specified in MANIFEST.MF “Bundle-ClassPath” header.

Example “build.gradle”


dependencies {
           
            compile  group: 'org.apache.poi', name: 'poi', version: '4.1.2'
            compile  group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.2'
}


 Add Jars in “includeresource” header in bnd.bnd file


-includeresource: \
META-INF/lib/poi-4.1.2.jar=poi-4.1.2.jar;lib:=true,\
META-INF/lib/poi-ooxml-4.1.2.jar=poi-ooxml-4.1.2.jar;lib:=true


META-INF/lib/poi-4.1.2.jar : will specify that jar will be copied to module META-INF/lib in the jar file.

poi-4.1.2.jar : It is actual jar file required by module. Name and version should match the dependency specified in “build.gradle” file.

we can also specify jar version regex pattern as follows


-includeresource: \
META-INF/lib/poi-4.1.2.jar=poi-[0-9]*.jar;lib:=true,\
META-INF/lib/poi-ooxml-4.1.2.jar=poi-ooxml-[0-9]*.jar;lib:=true


lib:=true : Will specify that jar references will be added to MANIFEST.MF “Bundle-ClassPath” header.


Option: 2

This option will directly add all jars as distributed packages in module and packages are specified in “Private-Package” header.

Example “build.gradle”


dependencies {
           
            compile  group: 'org.apache.poi', name: 'poi', version: '4.1.2'
            compile  group: 'org.apache.poi', name: 'poi-ooxml', version: '4.1.2'
}


Add Jars in include resources header in bnd.bnd file as follows


-includeresource: \
@poi-4.1.2.jar,\
@poi-ooxml-4.1.2.jar



Maven Liferay OSGi Module

Module Source


If you are developing Liferay OSGi Modules with MAVEN build tool, use pom.xml and bnd file to specify third party jars.

  1. Specify JAR as Maven dependency with provided scope
  2. Specify JAR information in “includeresource” header in bnd file.

Specify JAR as Maven dependency with provided scope

Example in pom.xml


<dependency>
       <groupId>org.apache.poi</groupId>
       <artifactId>poi</artifactId>
       <version>4.1.2</version>
       <scope>provided</scope>
</dependency>
<dependency>
       <groupId>org.apache.poi</groupId>
       <artifactId>poi-ooxml</artifactId>
       <version>4.1.2</version>
       <scope>provided</scope>
</dependency>


Specify JAR information in “includeresource” header in bnd file.

Option: 1

Add Jars in include resources header in module bnd.bnd file


-includeresource: \
META-INF/lib/poi-4.1.2.jar=poi-4.1.2.jar;lib:=true,\
META-INF/lib/poi-ooxml-4.1.2.jar=poi-ooxml-4.1.2.jar;lib:=true


META-INF/lib/poi-4.1.2.jar : will specify that jar will be copied to module META-INF/lib in the jar file package.

poi-4.1.2.jar : It is actual jar file required by module and name and version should match the dependency in specified in build.gradle file.

we can also specify jar version regex pattern as follows


-includeresource: \
META-INF/lib/poi-4.1.2.jar=poi-[0-9]*.jar;lib:=true,\
META-INF/lib/poi-ooxml-4.1.2.jar=poi-ooxml-[0-9]*.jar;lib:=true


lib:=true : Will specify that jar references will be added to MANIFEST.MF “Bundle-ClassPath” header.

Option: 2

This option will directly add all jars as distributed packages in module and packages are specified in “Private-Package” header.

Add Jars in include resources header in bnd.bnd file


-includeresource: \
@poi-4.1.2.jar,\
@poi-ooxml-4.1.2.jar


Important Note

When we add non OSGi third party jars we can expect “Unresolved requirement: Import-Package” error for specific packages and module might not deployed. These packages may not be used directly in the current Liferay OSGi module but we can see these errors.

Example


org.osgi.framework.BundleException: Could not resolve module: com.liferaysavvy.employee.portlet [1080]
  Unresolved requirement: Import-Package: com.graphbuilder.curve


Solution:

We can ignore packages using Import-Package header or we can add specified missing package jar as third party non OSGi jar.

Ignore Packages as follows.

Example


Import-Package: \
!com.graphbuilder.*,\
!com.github.luben.zstd.*,\
!com.github.luben.zstd.*,\
!com.microsoft.schemas.*,\
!net.sf.saxon.*,\
!org.apache.batik.*,\
!org.apache.jcp.xml.dsig.internal.*,\
!org.bouncycastle.asn1.*,\
!org.bouncycastle.*,\
!org.bouncycastle.cms.*,\
!org.brotli.dec.*,\
!org.etsi.uri.*,\
!org.openxmlformats.schemas.*,\
!org.tukaani.xz.*,\
!com.zaxxer.sparsebits.*,\
!org.apache.commons.codec.*,\
!org.apache.commons.collections4.*,\
!org.apache.commons.compress.*,\
!org.apache.commons.math3.*,\
!org.apache.xmlbeans.*,\
!org.w3.x2000.*,\
\
*


Don’t forget to add \ * end of configuration otherwise all Liferay default packages will be ignored in the “Import-Package” header in the jar file. It will lead to so many unresolved requirement errors.

Once modules deployed in Liferay OSGi module framework then you can add widget to the page.


Once portlet added in the console you can see that apache poi related code being executed.


Note:

The objective of code example is to understand the adding third party jars to OSGi module and its not real example to explain about apache poi.
Author

Recent Posts

Recent Posts Widget

Popular Posts