Wednesday, March 11, 2020

Unresolved requirement Import-Package Error in Liferay OSGi Module Framework


When we are developing Liferay OSGi modules, we can see “Unresolved requirement Import-Package Error” while deploying modules. This is very common error we can encounter in deployment of modules and finally module will not be in active state but it’s in installed state.


org.osgi.framework.BundleException: Could not resolve module: com.liferaysavvy.employee.portlet [3218]_  Unresolved requirement: Import-Package: org.apache.poi.ss.usermodel_ [Sanitized]
       at org.eclipse.osgi.container.Module.start(Module.java:444)
       at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:428)
       at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1264)
       at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1237)
       at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:520)
       at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:365)
       at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:316)



You can use following Gogo shell command to know the reason

diag [BUNDLE_ID]




Reason for the Error

The package that Liferay OSGi Module used in “Import-Package” list was not exported by any of the other module in the Liferay OSGi module framework.

The following are two fundamental things to understand above error.

  1. When you use any package in module “Import-Package” list, specified package must be Exported by other module in Liferay OSGi module framework.
  2. If the other module was not exported the package already then it should be in module “Private-Package” list.

When you use any package in module “Import-Package” list, specified package must be Exported by other module in Liferay OSGi module framework.

Usually we use “Import-Package” header in MANIFEST file list all packages that required by module. Liferay OSGi module uses the bnd.bnd file to specify the MANIFEST headers and bnd tools will finally update the configuration in module MANIFEST.MF file in the build process.

Even if we are not specifying any packages explicitly in the “Import-Package” list in bnd.bnd file, bnd tools will add packages for “Import-Package” header during the build time. Bnd tools are very smart enough to find all packages that module uses will be added in “Import-Package” header. You can notice it in jar file MANIFEST.MF

Usually exported packages will be defined in “Export-PackageMANIFEST.MF header. If its custom Liferay OSGi module, Export-Package header can be used in bnd.bnd file.

Usually Packages will be exported at different level in Liferay OSGi Module Framework.

  1. Global Packages exported by Liferay Module Framework
  2. Liferay Portal Bootstrap module exported system extra packages
  3. Developer Developed custom OSGi modules.

To understand Global Exported and Liferay Bootstrap Exported packages follow the below blog.


Developer Developed custom OSGi modules

If the package belongs to one of your custom Liferay OSGi module then use “Export-Package” header in module bnd.bnd file.

Example: bnd.bnd file


Export-Package: com.liferaysavvy.employee.portlet.constants


If any package the module is using or listed in “Import-Package” list was exported by any one of above procedure then package must be resolved.

If the other module was not exported that package already then it should be in module “Private-Package” list.

If the module required package was not exported already in the above procedure then we can see same error. When we use some third-party jars in the modules then we can expect the same error.

Solution: 1

If the module required package is from third party library then we need to find OSGi compliance version of same jar and deploy in Liferay Module Framework. Newer version of third-party libraries are OSGi compliance.

How to identify the JAR is OSGi compliance?

Check MANIFEST.MF file with OSGi headers.

Example: latest google gson-2.8.6.jar is OSGi compliance


How to deploy OSGi compliance third-party library into OSGi module framework?

Simply place the jar file in Liferay portal bundle “osgi/module directory. In the logs you can see Module STARTED statement.  

Solution: 2

If the jar was not found as OSGi compliance jar then use includeresource option. Includeresource option will add jar to module lib directory and add packages in the private package list.

Follow the below blog to add third party non-OSGi jars to Liferay OSGi module.


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

Recent Posts

Recent Posts Widget

Popular Posts