Thanks for the feedback Stephan - you explained a behavior I was seeing when I 
was putting this together (item 2 in the list below).

I tried doing this with the Blueprint DSL to see what happens, and the route 
behaves as I’d expect.  When I stop the bundle providing the service, I get a 
ServiceUnavailableException (after the timeout).  When I start the bundle 
providing the service back up, the route will continue to process normally - 
with a new instance of the service.  The only odd part here is the output of 
the Karaf “list” command - it shows the bundle is in a “Waiting” state 
(https://issues.apache.org/jira/browse/KARAF-4283 
<https://issues.apache.org/jira/browse/KARAF-4283>).

So as near as I can tell, this is a bug.  The Blueprint proxies are not being 
used somehow when they are injected into the RouteBuilder (and ultimately the 
route).  Unless someone has some other idea, I’ll get a sample put together on 
GitHub and open a JIRA issue for this.

 
Here’s the Blueprint that works:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0";
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
           xsi:schemaLocation="
       http://www.osgi.org/xmlns/blueprint/v1.0.0 
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
       http://camel.apache.org/schema/blueprint 
http://camel.apache.org/schema/blueprint/camel-blueprint.xsd";
>

    <bean id="shutdown" class="org.apache.camel.impl.DefaultShutdownStrategy">
        <property name="timeout" value="30"/>
    </bean>

    <reference id="echo-service" interface="com.pronoia.test.osgi.service.Echo" 
filter="instance=one" timeout="2000" />

    <camelContext id="blueprint-context" 
xmlns="http://camel.apache.org/schema/blueprint";>
        <route id="blueprint-route">
            <from uri="timer://blueprint-route?period=5000"/>
            <setBody>
                <exchangeProperty>CamelTimerFiredTime</exchangeProperty>
            </setBody>
            <log message="Calling Service via Reference: ${body}" />
            <bean ref="echo-service" />
            <log message="Finished"/>
            <to uri="mock://result"/>
        </route>
    </camelContext>

</blueprint>



> On Jan 26, 2016, at 11:52 PM, Siano, Stephan <stephan.si...@sap.com> wrote:
> 
> Hi,
> 
> Sorry for the confusion I may have caused. In your example you are using 
> option 3, which should actually work as you expected.
> 
> Best regards
> Stephan
> 
> -----Original Message-----
> From: Siano, Stephan [mailto:stephan.si...@sap.com] 
> Sent: Mittwoch, 27. Januar 2016 07:40
> To: users@camel.apache.org
> Subject: RE: Invoking Dynamic OSGi Blueprint services from a Java RouteBuilder
> 
> Hi,
> 
> You have actually two issues. The first Is accessing an OSGi service from a 
> route using Java DSL. Camel lookups are done in a Camel registry. The kind of 
> registry depends on the way you start your camel context, if you are using 
> blueprint to do that, you have a blueprint registry, if you are using Spring 
> you have a spring registry and (AFAIK) if you are using Java DSL you are 
> normally using a JNDI registry. The special thing about the blueprint 
> registry is that it forwards lookups that cannot be resolved from the 
> blueprint context to the OSGi service registry (so you can do lookups with 
> the Camel registry that are doing OSGi service lookups). I don't think that 
> is possible with Java DSL. However these OSGi lookups via the Camel registry 
> are not very dynamic: The service object is retrieved via OSGi API and is 
> pinned in memory (which is not exactly OSGi-like).
> 
> The other issue is when you are referencing services with blueprint. The user 
> of this blueprint service reference will not get the service object itself, 
> but a dynamic proxy object, that will remain the same even if you restart the 
> service (it will even delay any calls to the service while it is gone to the 
> time till it is back (or times out)). That way references injected during 
> bundle startup will remain valid even if the underlying service is restarted. 
> 
> Therefore you can encounter three different behaviours when referencing an 
> OSGi service (however this is registered) in a Camel route:
> 1. trying to reference it via the camel registry with a registry 
> implementation different from the blueprint one doesn't work
> 2. referencing it via the camel registry with the blueprint implementation 
> will work but only unless you restart the service
> 3. referencing the service via blueprint service reference and then 
> referencing the service from the camel route will create a dynamic proxy 
> object (that remains the same over the whole lifecycle but can cope with 
> service restarts just all right).
> 
> Best regards
> Stephan
> 
> -----Original Message-----
> From: Quinn Stevenson [mailto:qu...@pronoia-solutions.com] 
> Sent: Dienstag, 26. Januar 2016 23:11
> To: users@camel.apache.org
> Subject: Invoking Dynamic OSGi Blueprint services from a Java RouteBuilder
> 
> When I use an OSGi Service registered using Blueprint from a Java route 
> (built using a Java RouteBuilder), the Camel route isn’t detecting the when 
> the service is not available, and it isn’t updating when the service 
> implementation changes.
> 
> The simple setup I’m using has a Java interface for the OSGi service in one 
> bundle, and implementation of that interface which uses Blueprint to register 
> the service in another bundle, and simple RouteBuilder that uses the service 
> in a third bundle.  The implementation of the service is injected into the 
> RouteBuilder using Blueprint, and the Camel context is configured in 
> Blueprint in a fourth bundle.
> 
> After all these bundles are installed and started in Karaf, the run and the 
> hashCode of service is logged every time the Camel timer fires and triggers 
> an exchange.  If I stop the bundle that registers the service using 
> Blueprint, the route continues to log the same hashCode when it calls the 
> OSGi service.  I would expect a ServiceUnavailableException after a timeout.  
> 
> Additionally, when I restart the bundle that registers the service object, I 
> continue to get the same hashCode.  I would expect to get a new hashCode 
> value.
> 
> Am I doing something wrong?  Do I need to do something different do get the 
> dynamic behavior I’m looking for?
> 
> 
> The code looks like this:
> 
> Java Interface (service-interface bundle):
> public interface Echo {
>    String execute(String body);
> }
> 
> Java Implementation:
> public class EchoServiceOne implements Echo {
>    Logger log = LoggerFactory.getLogger(this.getClass());
> 
>    @Override
>    public String execute(String body) {
>        log.info( "{}:{} -> execute", this.getClass().getSimpleName(), 
> this.hashCode() );
>        return body;
>    }
> }
> 
> 
> Blueprint Registering the service (service-one bundle):
> <?xml version="1.0" encoding="UTF-8"?>
> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0";
>           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 
> http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd";>
> 
>    <service interface="com.pronoia.test.osgi.service.Echo" >
>        <service-properties>
>            <entry key="instance" value="one" />
>        </service-properties>
>        <bean class="com.pronoia.test.osgi.service.impl.EchoServiceOne" />
>    </service>
> 
> </blueprint>
> 
> Java RouteBuilder (route-builder bundle):
> public class VerySimpleBuilder extends RouteBuilder {
>    Echo blueprintServiceReference;
> 
>    @Override
>    public void configure() throws Exception {
>        from("timer://very-simple-builder?period=5000").routeId( 
> "very-simple-route" )
>                .setBody( simple( "${exchangeProperty[" + 
> Exchange.TIMER_FIRED_TIME + "]}") )
>                .log("Calling Service via Reference: ${body}" )
>                .bean(blueprintServiceReference,false)
>                .to( "mock://result")
>                .log("Finished" );
>    }
> 
>    public Echo getBlueprintServiceReference() {
>        return blueprintServiceReference;
>    }
> 
>    public void setBlueprintServiceReference(Echo blueprintServiceReference) {
>        this.blueprintServiceReference = blueprintServiceReference;
>    }
> }
> 
> Blueprint constructing the Camel context (camel-context bundle):
> <?xml version="1.0" encoding="UTF-8"?>
> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0";
>           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>           
> xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0";
>           xsi:schemaLocation="
>       http://www.osgi.org/xmlns/blueprint/v1.0.0 
> http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
>       http://camel.apache.org/schema/blueprint 
> http://camel.apache.org/schema/blueprint/camel-blueprint.xsd";
>> 
> 
>    <reference id="echo-service" 
> interface="com.pronoia.test.osgi.service.Echo" filter="instance=one" 
> timeout="2000" />
> 
>    <bean id="very-simple-route-builder" 
> class="com.pronoia.test.camel.builder.VerySimpleBuilder">
>        <property name="blueprintServiceReference" ref="echo-service" />
>    </bean>
> 
>    <camelContext id="very-simple-context" 
> xmlns="http://camel.apache.org/schema/blueprint";>
>        <routeBuilder ref="very-simple-route-builder" />
>    </camelContext>
> 
> </blueprint>
> 
> 

Reply via email to