Ventsislav Marinov
Ventsislav Marinov

Reputation: 604

Declarative OSGi Services

I have a question about declarative OSGi Services. I have the following interface :

  public interface PrintService {
    public void print();
  }

and its implementation:

    public class PrintServiceImpl implements PrintService {

      @Override
      public void print() {
        System.out.println("Hello from PrintServiceImpl!");
      }
    }

OSGI-INF/component.xml :

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="service">
   <implementation class="service.PrintServiceImpl"/>
   <service>
      <provide interface="print.PrintService"/>
   </service>
</scr:component>

MANIFEST.MF :

Service-Component: OSGI-INF/component.xml

After I install the service and start it nothing happend. How can I activate it and print "Hello from PrintServiceImpl!" to console.

Upvotes: 1

Views: 4277

Answers (6)

burak isik
burak isik

Reputation: 581

When you are use annotations, XML file will be generated automatically under OSGI-INF/... folder.

  public interface PrintService {
    public void print();
  }

  implementation with annotations: 

  @Component(service = PrintService.class)
  public class PrintServiceImpl implements PrintService {

      @Activate
      public void activate() {
         print();
      }

      @Override
      public void print() {
        System.out.println("Hello from PrintServiceImpl!");
      }
    }

As i said before, XML file created automatically. With @Component(service = PrintService.class) annotations, we register PrintService to OSGi framework(like registerService method in ServiceTracker). When service is registered, Activate method will be called. Method name can be anything. Just add @Activate annotations to say "when service is registered, call the method which is under @Activate annotations" to OSGi Framework.

Upvotes: 0

Raoul
Raoul

Reputation: 132

Did you ever get this working? For me it was that the Eclipse .ds bundle just hadn't started yet, and as such the service wasn't registered (yet). When I started it manually my service was registered correctly.

Upvotes: 0

christian.vogel
christian.vogel

Reputation: 2147

All the answers above are correct. Now to have something like printing something on the shell you could write something like:

public interface PrintService {
    public void print();
}

Implentation:

public class PrintServiceImpl implements PrintService {

      @Override
      public void print() {
        System.out.println("Hello from PrintServiceImpl!");
      }
}

component.xml:

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="service">
   <implementation class="service.PrintServiceImpl"/>
   <service>
      <provide interface="print.PrintService"/>
   </service>
</scr:component>

And now you could use a Command to call your print method:

public class PrintCommand implements Command {

    private PrintService printer;

    public void setPrinter(PrintService printer) {
        this.printer = printer; 
    }

    public void unsetPrinter(PrintService printer) {
        this.printer = null;
    }

    @Override
    public void execute(String line, PrintStream arg1, PrintStream arg2) {    
        printer.print();
    }

    @Override
    public String getName() {
        return "print";
    }

    @Override
    public String getShortDescription() {
        return "just a printer";
    }

    @Override
    public String getUsage() {
        return "print";
    }

}

And your component.xml should have a new entry:

<component name="PrintCommand">
    <implementation class="PrintCommand"/>
    <service>
        <provide interface="org.apache.felix.shell.Command"/>
    </service>
    <reference
        name="printer"
        interface="PrintService"
        bind="setPrinter"
        unbind="unsetPrinter"
        cardinality="1..1"
        policy="static"
    />
</component>

The Command Interface is part of Apache Felix Shell and if you now run Felix and type help in your console you will see all registered commands and there is the PrintCommand as well print. If you now type print in the shell you will see the text.

Upvotes: 1

maasg
maasg

Reputation: 37435

You should make explicit that you want you service to start when the bundle is started. Otherwise, it will be instantiated lazily, and give that no other service requires the PrintService, it will not be instantiated at all.

You can control your service lifecycle (with regard to the bundle lifecycle) using the attributes enabled and immediate. enabled is trivial: indicates whether your service is enabled or not when the bundle is started. immediate indicates whether this service is lazy ot not. immediate="true" will start your service immediatly, immediate="false" will apply lazy instantiation (i.e. wait until some other service requests this service as a dependency)

e.g.

<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="PrintService"
activate="activate" 
deactivate="deactivate"
modified="modified"
enabled="true" 
immediate="true">

As Chris mentioned, if you want your service to do something when it's activated, you should add some code to the activate lifecycle method (note that the name of the method can be specified in the component descriptor like it was done explicitly above)

protected final void activate() {
    print();
}

Upvotes: 3

Chris Dolan
Chris Dolan

Reputation: 8973

Perhaps you want to do the print from your activate method?

public class PrintServiceImpl implements PrintService {
    protected final void activate() {
        System.out.println("Hello from PrintServiceImpl!");
    }
    protected final void deactivate() {
        System.out.println("Goodbye from PrintServiceImpl!");
    }
    ...
}

Otherwise, Neil's answer is the right one: you want a client that uses the service via ServiceTracker or <reference> and explicitly invokes the print() method.

Upvotes: 1

Neil Bartlett
Neil Bartlett

Reputation: 23958

Why do you expect your print method to be invoked? It is part of the interface of the service, so it will not be invoked until you can a client that binds to it and calls it.

If you type the services command in the console you should see that your bundle is publishing the print.PrintService service; this means that your component is working. If you don't see this then you may be missing something like the SCR bundle as suggested by Tom Seidel in the comments above.

Upvotes: 2

Related Questions