oo

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.

The example modules provide a greeter command for Gogo Shell.

You can use OSGi services in any Java class.

Liferay service Javadoc is available here.

Note

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

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:

  1. 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
    
  2. Deploy the example modules.

    cd liferay-j1h1
    
    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    
  3. 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
    
  4. Open the Gogo Shell.

  5. In the Gogo Shell command field, enter a j1h1:greet command to generate a greeting.

    j1h1:greet "Captain Kirk"
    
  6. 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.

  1. Import the service.
import com.acme.j1h1.Greeter;
  1. 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.

Feature: