liferayosgiliferay-7gogo-shell

Gogo Shell command disappears if I reference service


Source code

In my module, I wrote this Liferay service:

package jp.co.my.module;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.module.framework.service.IdentifiableOSGiService;
import com.liferay.portal.kernel.service.BaseLocalServiceImpl;

public class TestService extends BaseLocalServiceImpl
                         implements IdentifiableOSGiService {

    public void test() throws PortalException {
        System.out.println("In the future I will do stuff here");
    }

    @Override
    public String getOSGiServiceIdentifier() {
        return TestService.class.getName();
    }
}

In the same module, I wrote a command that uses that service:

package jp.co.my.module;
import com.liferay.portal.kernel.exception.PortalException;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(
        property = {
                "osgi.command.function=test",
                "osgi.command.scope=liferay"
        },
        service = Object.class)
public class TestCommand {

    public void test() throws PortalException {
        System.out.println("In the future I will call the service here");
    }

    @Reference private volatile TestService _testService;
}

Problem

The module deploys correctly, but in Gogo Shell the command is not usable:

g! test
gogo: CommandNotFoundException: Command not found: test
g! b 1001
jp.co.my.module_1.0.0 [1001]
  Id=1001, Status=ACTIVE      Data Root=/home/nico/liferay/osgi/state/org.eclipse.osgi/1001/data                                               
  "No registered services."
  Services in use:
    {org.osgi.service.log.LogService, org.eclipse.equinox.log.ExtendedLogService}={service.id=2, service.bundleid=0, service.scope=bundle}             
  No exported packages
  Imported packages
    com.liferay.portal.kernel.exception; version="7.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>                                                
    com.liferay.portal.kernel.module.framework.service; version="1.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>                                 
    com.liferay.portal.kernel.service; version="1.27.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>                                                 
  No fragment bundles
  No required bundles

But! If I remove @Reference private volatile TestService _testService; from TestCommand.java, it works perfectly:

g! test
In the future I will call the service here
g! b 1005
jp.co.my.module_1.0.0 [1005]
  Id=1005, Status=ACTIVE      Data Root=/home/nico/liferay/osgi/state/org.eclipse.osgi/1005/data
  "Registered Services"
    {java.lang.Object}={osgi.command.function=test, component.name=jp.co.my.module.TestCommand, component.id=2740, osgi.command.scope=liferay, service.id=7652, service.bundleid=1005, service.scope=bundle}
  Services in use:
    {org.osgi.service.log.LogService, org.eclipse.equinox.log.ExtendedLogService}={service.id=2, service.bundleid=0, service.scope=bundle}
  No exported packages
  Imported packages
    com.liferay.portal.kernel.exception; version="7.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.module.framework.service; version="1.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.service; version="1.27.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
  No fragment bundles
  No required bundles

Question: Why is that? How to reference the service correctly?


Solution

  • I haven't used liferay but it seems to follow OSGI concepts pretty closely. Your TestCommand is a component that depends on TestService because you have used @Reference. That implies TestService is also a component. But you haven't defined TestService as a component anywhere.

    My educated guess is that TestService must use @Component as well, so liferay will know it's a component, create it, and inject it into TestCommand:

    @Component
    public class TestService extends BaseLocalServiceImpl
                         implements IdentifiableOSGiService {
    

    There might be additional issues with trying to create and reference a Component without a defined java interface, i don't know.

    EDIT: my answer mirrors some info here. https://portal.liferay.dev/docs/7-0/tutorials/-/knowledge_base/t/osgi-and-modularity-for-liferay-6-developers#osgi-services-and-dependency-injection-with-declarative-services

    EDIT2: the reason it works perfectly without the line is that removing @Reference removes the broken dependency link between TestCommand and TestService. With the line, the dependency chain is there but not resolved, so your TestCommand won't start

    EDIT3:

    @Component(
        configurationPid = "jp.co.my.module",
        immediate = true,
        property = {}, 
        service = TestService.class
        )