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...

OSGI and Why Liferay Uses OSGi

 

Introduction to OSGi

OSGi (Open Services Gateway initiative), now maintained as the OSGi Alliance's core module framework, is a dynamic module system for Java. It defines how independent units of code, called bundles, are packaged, deployed, versioned, started, stopped, and wired to one another at runtime — all without restarting the JVM.

At its core, OSGi solves three problems that plain Java (and traditional WAR-based deployment) does not solve well:

  • Modularity — code is packaged into bundles with explicit imports/exports, so internal implementation details stay hidden (encapsulation at the JAR level, not just the class level).

  • Versioning — multiple versions of the same package or library can co-exist in the same JVM, each bundle wired to the version it actually needs.

  • Dynamism — bundles can be installed, updated, started, and stopped individually, at runtime, without redeploying or restarting the whole application.

1.1 Key Building Blocks

Concept

Description

Bundle

A JAR file with an OSGi manifest (MANIFEST.MF) describing its symbolic name, version, imported packages, and exported packages.

Module Layer

Manages class loading, package visibility, and versioned dependencies between bundles.

Lifecycle Layer

The API/state-machine that installs, resolves, starts, stops, updates, and uninstalls bundles.

Service Registry

A dynamic "lost and found" where bundles publish and discover services (plain Java objects) by interface, independent of which bundle implements them.

Framework

The OSGi runtime itself. Liferay DXP embeds Equinox by default (Apache Felix is also supported).

2. Why Liferay Uses OSGi

Since Liferay Portal/DXP 7.0, the entire platform was re-architected on top of OSGi. Every portlet, theme, layout template, Service Builder module, REST endpoint, and even core Liferay services (Asset, User, Journal, DDM, etc.) are themselves OSGi bundles. The reasons for this shift are practical, not just academic:

2.1 True Hot Deployment

Bundles can be installed or updated by dropping a JAR into the deploy folder (or via Gogo shell / Blade CLI) while the server keeps running. Only the affected module restarts — the rest of the portal, and every other unrelated module, is unaffected. This is a major operational win over the old plugin-SDK / "redeploy the whole WAR" model of Liferay 6.x.

2.2 Eliminating "JAR Hell"

Large enterprise portals commonly need two modules that depend on different versions of the same library. OSGi's versioned import/export model lets bundle A use Jackson 2.10 and bundle B use Jackson 2.15 side by side in the same JVM, something a flat classpath (like a single WAR's WEB-INF/lib) cannot do safely.

2.3 Strong Encapsulation

A bundle only exposes the Java packages it explicitly lists in Export-Package. Internal implementation packages stay private even though everything runs in one JVM. This enforces clean API boundaries between, for example, a Service Builder module's -api and -service JARs.

2.4 Service-Oriented Internals

Liferay's own subsystems talk to each other via the OSGi Service Registry rather than static singletons. This is why Liferay code is full of @Component and @Reference annotations — a class registers itself as an implementation of a service interface, and any other bundle can consume it dynamically, including hot-swapping the implementation at runtime (useful for SPI-style extension points such as custom SSO, custom search connectors, or custom asset renderers).

2.5 Extensibility for Client Projects

For consulting/implementation work , OSGi means client-specific modules — custom portlets, custom REST endpoints, client extensions, workflow listeners — are built, versioned, and deployed independently of Liferay's own codebase and of each other, which is essential when multiple teams work on the same DXP instance.

2.6 Foundation for Modern Liferay Features

  • Client Extensions (7.4) build on OSGi's dynamic wiring model.

  • Headless / REST Builder modules are separate OSGi bundles registered against JAX-RS Whiteboard.

  • Fragments, Instanceable widgets, and Workflow definitions are all backed by OSGi component metadata.

3. OSGi Bundle Lifecycle

Every bundle moves through a well-defined state machine managed by the framework's Lifecycle Layer. Understanding these states is essential for diagnosing why a Liferay module "is deployed but not working" (usually stuck in Installed or Resolved rather than Active).

State

Meaning

INSTALLED

The bundle JAR has been installed into the framework, but its dependencies (imported packages) have not yet been resolved. Its manifest has been read.

RESOLVED

All of the bundle's mandatory imports have been satisfied — matching exporters exist and are wired. The bundle is ready to start but its activator/components have not run yet.

STARTING

The bundle is transitioning to ACTIVE. Its BundleActivator.start() method (or, for Declarative Services, component activation) is executing.

ACTIVE

The bundle is fully running. Its services are registered in the Service Registry and available for other bundles to consume.

STOPPING

The bundle is transitioning out of ACTIVE. BundleActivator.stop() is executing, and its services are being unregistered.

UNINSTALLED

The bundle has been removed from the framework. Existing references to its classes may still work until the JVM garbage-collects them, but it can no longer be restarted — a fresh install() is required.



3.1 Typical Transition Flow

install() resolve start()

INSTALLED ─────────► RESOLVED ─────────► STARTING ─────────► ACTIVE

stop()

UNINSTALLED ◄─────────────── STOPPING

uninstall()



Two additional transitions matter in day-to-day Liferay work:

  • update() — installs new bytes for an existing bundle. It goes back through RESOLVED before returning to ACTIVE, re-wiring imports if needed.

  • refresh — when a bundle that others depend on is updated/uninstalled, dependent bundles are automatically stopped and restarted ("refreshed") by the framework so they re-resolve against the new version.

3.2 Observing the Lifecycle in Liferay (Gogo Shell)

Liferay exposes the Felix/Equinox Gogo shell over telnet (default localhost:11311) so you can inspect and control bundles directly:

$ telnet localhost 11311

g! lb -s -u | grep sender # list bundles, show state, filter by name

g! diag 1234 # show why bundle 1234 will not resolve

g! start 1234 # move a bundle from RESOLVED to ACTIVE

g! stop 1234 # move a bundle from ACTIVE to RESOLVED

g! update 1234 # reinstall bundle bytes, keep the same id

g! uninstall 1234 # remove the bundle entirely

g! scr:list | grep SenderPortlet # inspect Declarative Services components

Note: A module deployed via the OSGi deploy folder, Blade CLI (blade deploy), or Gradle (deploy task) that never reaches ACTIVE is almost always stuck at RESOLVED because of an unsatisfied Import-Package/Require-Capability — diag <bundle-id> is the fastest way to find the missing dependency.

4. Liferay OSGi Module Anatomy

A typical Liferay 7.4 module (built with Blade CLI / Gradle) is itself just an OSGi bundle with Liferay-specific conventions layered on top:

File / Folder

Purpose

bnd.bnd

Bnd tool configuration that generates the OSGi manifest (Bundle-SymbolicName, Bundle-Version, Export-Package) at build time.

@Component annotation

Declarative Services (DS) metadata — replaces manual BundleActivator code; registers the class as an OSGi component/service.

@Reference annotation

Injects another OSGi service (e.g., a Liferay UserLocalService) into the component, resolved dynamically from the Service Registry.

portlet.xml

Still used for descriptors the annotations don't fully cover, most notably <event-definition> blocks for portlet events (see Section 5).

-api / -service module pairs

Service Builder convention: the -api bundle exports interfaces only; the -service bundle exports the implementation as an OSGi service, keeping persistence internals encapsulated.



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...