Skip to main content

Creating OSGi Modules and Sharing Packages

  Overview This guide walks through creating two OSGi modules in Liferay 7.4 and sharing a Java package between them using the standard API + Implementation pattern. This is the most common and correct approach for exposing reusable services in a Liferay-based architecture. In OSGi, a bundle (module) does not expose its internal packages by default — everything is private unless explicitly exported. To share code between modules, the standard practice is to split functionality into: · An API module — contains interfaces/DTOs and exports the package · A Service (Implementation) module — implements the interface, imports the package, and registers the implementation as an OSGi component/service The consuming module then simply imports the API package and looks up the service using @Reference injection. Step 1: Create the API Module Using Liferay Workspace + Blade CLI, generate a new API module: blade create -t api -p com.sgc.greeting greeting-api This generates a Gradle module unde...

How to Share Packages Between OSGI Bundle-liferay-7.4

         How to create OSGi Modules and how they share         packages

Overview

This guide walks through creating two OSGi modules in Liferay 7.4 and sharing a Java package between them using the standard API + Implementation pattern. This is the most common and correct approach for exposing reusable services in a Liferay-based architecture.

In OSGi, a bundle (module) does not expose its internal packages by default — everything is private unless explicitly exported. To share code between modules, the standard practice is to split functionality into:

  • An API module — contains interfaces/DTOs and exports the package

  • A Service (Implementation) module — implements the interface, imports the package, and registers the implementation as an OSGi component/service

The consuming module then simply imports the API package and looks up the service using @Reference injection.

Step 1: Create the API Module

Using Liferay Workspace + Blade CLI, generate a new API module:

blade create -t api -p com.sgc.greeting greeting-api

This generates a Gradle module under modules/greeting-api with the following structure:

greeting-api/
└─ src/main/java/com/sgc/greeting/api/GreetingService.java

GreetingService.java

package com.sgc.greeting.api;

public interface GreetingService {
String sayHello(String name);
}

Export the Package in bnd.bnd

Liferay/OSGi uses the bnd.bnd file (bnd tool) to control exports. Open greeting-api/bnd.bnd and add:

Bundle-Name: Greeting API
Bundle-SymbolicName: com.sgc.greeting.api
Bundle-Version: 1.0.0
Export-Package: com.sgc.greeting.api

The Export-Package line is what makes this package visible to other bundles — this is the core of “sharing” a package in OSGi.

Step 2: Create the Service / Implementation Module

blade create -t service-builder -p com.sgc.greeting greeting-service





Update your service.xml file

<?xml version="1.0"?>

<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 7.4.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_7_4_0.dtd">


<service-builder package-path="com.sgc.greeting">

<author>Arman</author>

<namespace>GREETING</namespace>


<entity name="Greeting" local-service="true" remote-service="false">


<!-- PK fields -->


<column name="greetingId" type="long" primary="true" />


<!-- Group instance -->


<column name="groupId" type="long" />

<column name="companyId" type="long" />


<!-- Audit fields -->


<column name="userId" type="long" />

<column name="userName" type="String" />

<column name="createDate" type="Date" />

<column name="modifiedDate" type="Date" />


<!-- Other fields -->


<column name="name" type="String" />

<column name="message" type="String" />


<order by="asc">

<order-column name="name" />

</order>


<finder name="Name" return-type="Collection">

<finder-column name="name" />

</finder>


</entity>


</service-builder>

Add a Dependency on the API Module

In greeting-service/build.gradle:

dependencies {
compileOnly project(":modules:greeting-api")
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "default"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
}

Implement the Interface as an OSGi Component

package com.sgc.greeting.service.impl;

import com.sgc.greeting.api.GreetingService;
import org.osgi.service.component.annotations.Component;

@Component(
immediate = true,
service = GreetingService.class
)
public class GreetingServiceImpl implements GreetingService {

@Override
public String sayHello(String name) {
return "Hello, " + name + "! Welcome to Liferay 7.4 OSGi modules.";
}
}

service = GreetingService.class registers this implementation in the OSGi Service Registry under that interface — this is how Liferay's Declarative Services (DS) model publishes the service.

Step 3: Consume the Shared Package in a Third Module

Create a consumer module, for example an MVC portlet:

blade create -t mvc-portlet -p com.sgc.greeting.web greeting-web

Add the API Dependency in build.gradle

dependencies {
compileOnly project(":modules:greeting-api")
}

Inject the Shared Service via @Reference

package com.sgc.greeting.web.portlet;

import com.sgc.greeting.api.GreetingService;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import javax.portlet.*;
import java.io.IOException;

@Component(
immediate = true,
property = {
"javax.portlet.name=com_sgc_greeting_web",
"javax.portlet.display-name=Greeting Portlet"
},
service = Portlet.class
)
public class GreetingPortlet extends MVCPortlet {

@Reference
private GreetingService greetingService;

@Override
public void doView(RenderRequest request, RenderResponse response)
throws IOException, PortletException {

request.setAttribute("greetingMessage", greetingService.sayHello("Arman"));
super.doView(request, response);
}
}

@Reference tells the OSGi Declarative Services runtime to inject whatever component is registered for GreetingService — this is the actual “sharing” moment, resolved dynamically at runtime.

Step 4: Deploy in the Correct Order

Order matters because of dependency resolution:

blade gw :modules:greeting-api:deploy

blade gw :modules:greeting-service:greeting-service-service:buildService
blade gw :modules:greeting-service:greeting-service-api:deploy

blade gw :modules:greeting-service:greeting-service-service:deploy
blade gw :modules:greeting-web:deploy

Or deploy all modules at once from the workspace root:

blade gw deploy

Step 5: Verify in Gogo Shell

Connect to Liferay's OSGi console:

telnet localhost 11311

Check bundle states:

lb greeting

You should see all three bundles as Active. Then verify the exported package is visible:

package com.sgc.greeting.api

This lists which bundle exports the package and which bundles import it — confirming the sharing worked correctly.

Key Points to Remember

Concept

Purpose

Export-Package in bnd.bnd

Makes a package visible outside its own bundle

compileOnly project(":modules:x-api")

Gradle-level dependency so code compiles against the API

@Component(service = X.class)

Registers implementation in the OSGi Service Registry

@Reference

Injects a registered service from another bundle

Deployment order

API → Implementation → Consumer (OSGi resolves dynamically, but deploying API first avoids resolution errors)

Common Mistake to Flag

Forgetting Export-Package in the API module's bnd.bnd is a frequent error. The module deploys fine but stays in the Installed state instead of Active, and the Gogo shell will show an unresolved import in the consuming bundle.

Comments

Popular posts from this blog

service builder with crud operation in liferay

   Crud and Search opration in Liferay:      ->  Liferay use service builder techniq for Crud opration.    ->  Service builder purform by  Service.xml file.    ->  Service.xml file create table in database and also create class and diffrent method.   1)      Create service.xml file.             ->Create service.xml file in WEB-INF and write below code.             ->CODE:        < service-builder package-path = "com.test" >         < namespace > qr </ namespace >           < entity name = "Searchclass" local-service = "true"                     ...

How to create new site programmaticly in liferay with validation

Create site in liferay <%@page import="javax.portlet.PortletPreferences"%> <%@page import="com.liferay.portal.kernel.util.ParamUtil"%> <%@page import="com.liferay.portal.kernel.util.HtmlUtil"%> <%@page import="com.liferay.portal.kernel.util.StringPool"%> <%@page import="com.liferay.portal.kernel.util.UnicodeProperties"%> <%@page import="com.liferay.portal.service.LayoutSetPrototypeServiceUtil"%> <%@page import="com.liferay.portal.model.LayoutSetPrototype"%> <%@page import="com.liferay.portal.service.GroupLocalServiceUtil"%> <%@page import="java.util.List"%> <%@page import="com.liferay.portal.kernel.bean.BeanParamUtil"%> <%@page import="com.liferay.portal.theme.ThemeDisplay"%> <%@page import="com.liferay.portal.model.Group"%> <%@page import="com.liferay.portal.kernel.util.WebK...

The Ultimate Guide to Liferay DXP Performance Tuning: Speed Up Your Portal

The Ultimate Guide to Liferay DXP Performance Tuning: Speed Up Your Portal In the enterprise web space, milliseconds equal millions. Whether you are running a B2B commerce storefront, a customer support portal, or an employee intranet on Liferay DXP, slow load times will devastate your user experience and destroy your SEO rankings. Out of the box, Liferay is configured to run on almost any machine. This means its default settings are highly conservative to ensure compatibility, not maximum performance. If you are launching a production environment without tuning your server, you are leaving massive amounts of speed and scalability on the table. In this comprehensive, deep-dive guide, we are going to explore the critical layers of Liferay performance tuning. We will cover backend Java Virtual Machine (JVM) configuration, Database Connection Pooling, Elasticsearch optimization, and Frontend caching strategies. By the end of this guide, you will have a blazing-fast, enterprise-grade...