APIs as OSGi Services
After you’ve learned what a module is and how to deploy one, you can use modules to define APIs and implement them. Liferay APIs are OSGi services, defined by Java interfaces and implemented by concrete Java classes.
Liferay exposes APIs, implementations, and clients as components. OSGi Declarative Services (DS) annotations define components and their relationships.
@ProviderType
defines an interface that components can provide (implement) or consume.@Component
declares the class a component, providing a particular capability.@Reference
wires another component to a class member (typically a field).
You can separate API and implementation concerns into different modules.
- API modules define capabilities using Java interfaces. The modules export the interface packages.
- Implementation modules provide capabilities using concrete Java classes.
Here you’ll deploy API and implementation modules that create a simple greeter OSGi service. You’ll also examine the implementation module and its JAR to learn how the implementation provides the greeter service capability. In the next tutorial, you’ll create the client—the part that you can invoke in the UI.
Deploy a Simple API and Implementation
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.120-ga120
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps to start the example modules:
-
Download and unzip
liferay-p9g2.zip
.curl https://resources.learn.liferay.com/dxp/latest/en/liferay-internals/fundamentals/liferay-p9g2.zip -O
unzip liferay-p9g2.zip
-
From the project root folder, deploy the modules.
cd liferay-p9g2
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
-
Confirm module startup in the Docker container console.
STARTED com.acme.p9g2.api_1.0.0 STARTED com.acme.p9g2.impl_1.0.0
-
Go to
http://localhost:8080
and sign in. -
Go to the Gogo Shell.
-
Get the module IDs using the
lb
Gogo Shell command.g! lb | grep -i "Acme P9G2"
Output:
1150|Active | 15|Acme P9G2 API (1.0.0)|1.0.0 1151|Active | 15|Acme P9G2 Implementation (1.0.0)|1.0.0
-
List the implementation module service capabilities by executing the following command, replacing the number with your module’s ID.
g! inspect capability service 1195
Output:
com.acme.p9g2.impl_1.0.0 [1151] provides: ----------------------------------------- service; com.acme.p9g2.Greeter with properties: service.id = 22933 service.bundleid = 1151 service.scope = bundle component.name = com.acme.p9g2.internal.P9G2Greeter component.id = 8462
The Acme P9G2 Implementation module provides one service: com.acme.p9g2.Greeter
. The component.name
property indicates that the module’s com.acme.p9g2.internal.P9G2Greeter
component implements the service.
You verified that the P9G2Greeter
component provides the Greeter
service.
Next you’ll learn how the API module defines the greeter capability and the implementation module provides the greeter capability as an OSGi service. Start with creating the API.
Create the API
An API is created in just two steps:
Define the Capability
The example API module Greeter
class is a Java interface.
@ProviderType
public interface Greeter {
The @ProviderType
annotation registers Greeter
as a type that a component can implement or consume.
The greet
method takes a name String
as input.
public void greet(String name);
The Greeter
capability is defined.
Export the Interface Package
The API module bnd.bnd
file describes the module and exports the com.acme.p9g2
interface package.
Bundle-Name: Acme P9G2 API
Bundle-SymbolicName: com.acme.p9g2.api
Bundle-Version: 1.0.0
Export-Package: com.acme.p9g2
The package export shares the Greeter
interface with other modules.
The Greeter
service type is available to implement and use.
Create the Implementation
The example implementation module contains a concrete Java class that provides the Greeter
capability. Here are the implementation steps.
- Add the Component Annotion Class
- Implement the Interface
- Add a Dependency on the API
- Examine the Module JAR
Add the Component Annotation
The P9G2Greeter
class implements the Greeter
interface:
@Component(service = Greeter.class)
public class P9G2Greeter implements Greeter {
The @Component
annotation and its service = Greeter.class
attribute make the P9G2Greeter
class a Greeter
service provider.
Implement the Interface
The Greeter
interface defines a method greet(String)
with a void
return value.
@Override
public void greet(String name) {
System.out.println("Hello " + name + "!");
}
The example greet
method prints an enthusiastic greeting using the given name.
Add a Dependency on the API
Here is the implementation module build.gradle
file.
dependencies {
compileOnly group: "com.liferay.portal", name: "release.portal.api"
compileOnly project(":p9g2-api")
}
It includes a compile-time dependency on the p9g2-api
module project because it requires the module’s Greeter
class.
Examine the Module JAR
When you built the p9g2-impl/build/libs/com.acme.p9g2.impl-1.0.0.jar
implementation module JAR, Bnd generated the JAR’s /META-INF/MANIFEST.MF
file.
Here are key service-related headers that Bnd generates in the manifest:
Import-Package: com.acme.p9g2;version="[1.0,2)"
The Import-Package
header imports the API module’s public package that contains the Greeter
service definition.
Provide-Capability: osgi.service;objectClass:List<String>="com.acme.p9
g2.Greeter";uses:="com.acme.p9g2"
The Provide-Capability
header configures the P9G2Greeter
component service.
Service-Component: OSGI-INF/com.acme.p9g2.internal.P9G2Greeter.xml
The Service-Component
header lists a configuration file (.xml
) for each of the module’s service components.
When you deployed the module, the Service Component Runtime registered the P9G2Greeter
service component as providing the Greeter
service.
Conclusion
You have defined a service capability called Greeter
and provided it in a service component called P9G2Greeter
. The Greeter
service is in place. How do clients access the service and use it? That’s demonstrated in Using an OSGi Service.