Service reference in OSGi/blueprint not working properly

stuff22 picture stuff22 · Mar 17, 2011 · Viewed 9.6k times · Source

I currently have two OSGi bundles (bundle1 and bundle2) both both exposing services through a blueprint in an EBA. In bundle2's blueprint.xml i want to reference a service from bundle1 and Inject it into the BuildService (code below), as BuildService will be used to call TicketService. This however results in a Timeout exception (also below). It seems like the BuildService never gets registered with OSGi. How would I make something like this work?

blueprint.xml for bundle1:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:bptx="http://aries.apache.org/xmlns/transactions/v1.0.0">

    <bean id="TicketServiceBean" class="com.example.b2.impl.TicketServiceImpl">
        <bptx:transaction value="Required" method="*" />
    </bean>

        <service ranking="0" id="TicketService" interface="com.example.b2.service.TicketService" ref="TicketServiceBean">
        <service-properties>
            <entry key="service.exported.interfaces" value="*" />
        </service-properties>
    </service>  

</blueprint>

blueprint.xml for bundle2

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">

    <bean 
        id="BuildServiceImplBean"
        class="com.example.b1.impl.BuildServiceImpl" 
        activation="eager" >
        <property name="ticketService" ref="TicketServiceRef" />
    </bean>  


    <service    
        id="BuildService" 
        ref="BuildServiceImplBean"
        interface="com.example.b1.service.BuildService"
        activation="eager"> 

        <service-properties>
            <entry key="service.exported.interfaces" value="*" />
        </service-properties>

    </service>



    <reference 
        id="TicketServiceRef" 
        interface="com.example.b2.service.TicketService" 
        availability="mandatory"
        activation="eager" />


</blueprint>

Implementation of the BuildService:

public class BuildServiceImpl implements BuildService {

    private TicketService ticketService;

    @Override
    public TicketBuildResponse ticketBuild(TicketBuildRequest ticketBuildRequest) throws BuildServiceException {

        //do stuff here
    }



    public TicketService getTicketService() {
        return ticketService;
    }

    public void setTicketService(TicketService ticketService) {
        this.ticketService = ticketService;
    }


}

When starting up the application server (Websphere) I get the following exception:

  BlueprintCont E org.apache.aries.blueprint.container.BlueprintContainerImpl$1 run Unable to start blueprint container for bundle com.example.b1.module due to unresolved dependencies [(objectClass=com.example.b2.service.TicketService)]
                                     java.util.concurrent.TimeoutException
        at org.apache.aries.blueprint.container.BlueprintContainerImpl$1.run(BlueprintContainerImpl.java:273)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:453)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:315)
        at java.util.concurrent.FutureTask.run(FutureTask.java:150)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:736)

Answer

stuff22 picture stuff22 · Mar 18, 2011

Here is the solution: The OSGi applications runtime treats remote services differently from local ones, because of the different default invocation semantics (local pass-by-reference versus remote pass-by-value). To prevent an application accidentally calling an exported service that is only designed for pass-by-value calls, it is hidden from local lookups.

The solution to this is to export the same bean twice, once for remote calls, and the second for local. In other words, you would add another <service /> element with the same configuration, but without the service.exported.interfaces property.

<service ranking="0" id="TicketServiceExport" interface="com.example.b2.service.TicketService" ref="TicketServiceBean">
    <service-properties>
        <entry key="service.exported.interfaces" value="*" />
    </service-properties>
</service>  

<service ranking="0" id="TicketService" interface="com.example.b2.service.TicketService" ref="TicketServiceBean"/>

There is actually also an osgi console in websphere and it can be found under [local websphere installation]/profiles/[profileName]/bin/osgiApplicationConsole.bat. Once lauched, help() gives you a list of commands. To see your imported services from SCA, you first connect to your application (e.g. connect(2), where the number of the application is given in the results of the list() command). You can then do services("(service.imported=true)") to see the service proxies that have been added by SCA . The command services() will list all the services in the application.