Using an OSGi Service
Liferay APIs are readily available as OSGi services. You can access a service by creating a field of that service type and annotating the field with @Reference
, like this:
@Reference
BlogsEntryService _blogsEntryService;
The above _blogsEntryService
field accesses a BlogsEntryService
OSGi service.
All Declarative Services components (classes annotated with @Component
) can access OSGi services this way. The run time framework injects a component’s @Reference
-annotated fields with their service types.
The following example demonstrates using an OSGi service called Greeter
. Three modules demonstrate the API-Provider-Consumer pattern used in OSGi services.
- The API module defines the
Greeter
service type. - The implementation module provides the
Greeter
service. - The example module consumes the
Greeter
service.
The example module class creates a Gogo Shell command that uses the Greeter
service to return a personalized greeting. Consider this example to be a “Hello World” for OSGi services.
You can use OSGi services in any Java class.
Liferay service Javadoc is available here.
For instructions on how to create an OSGi service, please see APIs as OSGi Services.
Deploy the Gogo Shell Command Example
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:
-
Download and unzip
liferay-j1h1.zip
.curl https://resources.learn.liferay.com/dxp/latest/en/liferay-internals/fundamentals/liferay-j1h1.zip -O
unzip liferay-j1h1.zip
-
Deploy the example modules.
cd liferay-j1h1
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
-
Confirm the deployments in the Docker container console.
STARTED com.acme.j1h1.api_1.0.0 STARTED com.acme.j1h1.impl_1.0.0 STARTED com.acme.j1h1.osgi.commands_1.0.0
-
Open the Gogo Shell.
-
In the Gogo Shell command field, enter a
j1h1:greet
command to generate a greeting.j1h1:greet "Captain Kirk"
-
Confirm the output.
Hello Captain Kirk!
The example module leverages the API and implementation modules to produce the content returned from the j1h1:greet
Gogo Shell command.
How to Use an OSGi Service
Write Your Business Logic
In your class, implement business logic using the OSGi service you need.
- Import the service.
import com.acme.j1h1.Greeter;
- Use the service.
public void greet(String name) {
_greeter.greet(name);
}
private Greeter _greeter;
The method above invokes a Greeter
’s greet
method. com.acme.j1h1.Greeter
is the OSGi service type that the implementation module registers. Your class must get a Greeter
instance from the OSGi service registry.
Annotate External Service References
Getting an OSGi service from the registry requires adding an @Reference
annotation to a field of that service type. Add the @Reference
to your service field.
@Reference
private Greeter _greeter;
The J1H1OSGiCommands
class has the above private Greeter
field called _greeter
. The @Reference
annotation tells the OSGi runtime to inject the field with a Greeter
service from the registry. If J1H1Greeter
is the best matching Greeter
service component in the registry (it’s the only match in this example), the runtime injects _greeter
with a J1H1Greeter
.
Make Your Class a Component
Only Declarative Services components can use the @Reference
annotation. Add the @Component
annotation to your class and use a service
attribute to declare your component as implementing a particular service.
@Component(
property = {"osgi.command.function=greet", "osgi.command.scope=j1h1"},
service = J1H1OSGiCommands.class
)
public class J1H1OSGiCommands {
The J1H1OSGiCommands
class provides an OSGi service of its own type. The two properties define a Gogo shell command with a command function called greet
in a scope called j1h1
. The deployed J1H1OSGiCommands
component provides the Gogo Shell command j1h1:greet
that takes a String
as input.
Add a Dependency on the API
Your consumer module depends on the API. In your build.gradle
file, add the API to your dependencies. Here’s the j1h1-osgi-commands
module’s build.gradle
file:
dependencies {
compileOnly group: "com.liferay.portal", name: "release.portal.api"
compileOnly project(":j1h1-api")
}
The release.portal.api
artifact provides the Liferay, Bnd, and OSGi services that the module needs from current Liferay product release. The liferay.workspace.product
in the [project root]/gradle.properties
file specifies the release.
Since the local project j1h1-api
provides the Greeter
service, j1h1-osgi-commands
can depend on it as a project instead of an artifact. Specifying Dependencies on external artifacts is easy too.
Conclusion
The API and Impl modules defined and provided the Greeter
service, respectively. The example j1h1-osgi-commands
module uses the service to create a simple Gogo Shell command. The API-Provider-Consumer contract fosters loose coupling, making your software easy to manage, enhance, and support.
Now that you’re familiar with using OSGi services from neighboring projects, you can explore using OSGi services from external artifacts. Configuring Dependencies demonstrates finding modules and configuring them as dependencies.