Grzegorz Grzybek created CAMEL-11810:
----------------------------------------

             Summary: Lifecycle problems for services retrieved from Blueprint 
container
                 Key: CAMEL-11810
                 URL: https://issues.apache.org/jira/browse/CAMEL-11810
             Project: Camel
          Issue Type: Bug
          Components: camel-blueprint
            Reporter: Grzegorz Grzybek
            Assignee: Grzegorz Grzybek


I have a case where one bundle/blueprint-container defines:
{code:xml}
    <bean id="messageIdRepositoryImpl" 
class="org.apache.camel.processor.idempotent.MemoryIdempotentRepository"/>

    <service id="messageIdRepository" 
interface="org.apache.camel.spi.IdempotentRepository" 
ref="messageIdRepositoryImpl" />
{code}

and another one defines Camel context with:
{code:xml}
    <reference id="messageIdRepository" 
interface="org.apache.camel.spi.IdempotentRepository"/>
    <camelContext xmlns="http://camel.apache.org/schema/blueprint";>

        <route id="xx">

            <from 
uri="file://xxx?y=z&amp;readLock=idempotent&amp;idempotent=true&amp;idempotentRepository=#messageIdRepository&amp;other.properties[...]"
 />
{code}

The problem is that when bundle defining {{messageIdRepositoryImpl}} is 
stopped, stopping bundle/blueprint-container leads to wait on 
Proxy/ReferenceRecipe:
{noformat}
org.osgi.service.blueprint.container.ServiceUnavailableException: Timeout 
expired when waiting for mandatory OSGi service reference: 
(objectClass=org.apache.camel.spi.IdempotentRepository)
        at 
org.apache.aries.blueprint.container.ReferenceRecipe.getService(ReferenceRecipe.java:234)
        at 
org.apache.aries.blueprint.container.ReferenceRecipe.access$000(ReferenceRecipe.java:56)
        at 
org.apache.aries.blueprint.container.ReferenceRecipe$ServiceDispatcher.call(ReferenceRecipe.java:306)
        at Proxy28f0d520_9465_4682_9ec1_02ae44e9fa4a.toString(Unknown Source)
        at java.lang.String.valueOf(String.java:2994)[:1.8.0_144]
        at java.lang.StringBuilder.append(StringBuilder.java:131)[:1.8.0_144]
        at 
org.apache.camel.impl.DefaultCamelContext.shutdownServices(DefaultCamelContext.java:3214)
        at 
org.apache.camel.impl.DefaultCamelContext.shutdownServices(DefaultCamelContext.java:3234)
        at 
org.apache.camel.impl.DefaultCamelContext.shutdownServices(DefaultCamelContext.java:3222)
        at 
org.apache.camel.impl.DefaultCamelContext.doStop(DefaultCamelContext.java:3101)
        at org.apache.camel.support.ServiceSupport.stop(ServiceSupport.java:102)
        at 
org.apache.camel.blueprint.BlueprintCamelContext.destroy(BlueprintCamelContext.java:129)
...
{noformat}

There are few problems here. First - {{GenericFileEndpoint.doStart()}} does 
this:
{code:java}
if (idempotentRepository != null) {
    getCamelContext().addService(idempotentRepository, true);
}
{code}

which adds the blueprint recipe (proxy) to 
{{org.apache.camel.impl.DefaultCamelContext#servicesToStop}} without a way to 
specify {{stopOnShutdown=false}}.

IMO services obtained from OSGi registry should not be tied to lifecycle of 
single context with route having {{#referenceToOsgiOrBlueprintService}} in 
endpoint URI.

Also - the above stack trace is not retrieved when stopping an osgi service, 
but when log.warning an exception!:
{code:xml}
log.warn("Error occurred while shutting down service: " + service + ". This 
exception will be ignored.", e);
{code}
In the above code we have implicit {{toString()}} call on service which leads 
to another proxy call which calls 
{{org.apache.aries.blueprint.container.ReferenceRecipe.ServiceDispatcher#call()}}
 → {{org.apache.aries.blueprint.container.ReferenceRecipe#getService()}} → 
{{org.apache.aries.blueprint.container.ReferenceRecipe#monitor.wait(metadata.getTimeout()}}.

The most obvious fix is to move idempotent repository to a blueprint file where 
file endpoint is used.

But as OSGi devil's advocate, I suggest more generic solution: when looking up 
objects inside {{org.apache.camel.blueprint.BlueprintContainerRegistry}}, in 
addition to calling 
{{org.osgi.service.blueprint.container.BlueprintContainer#getComponentInstance()}}
 we may check if {{blueprintContainer.getComponentMetadata(name) instanceof 
ReferenceMetadata}} and in such case return a proxied proxy that would prevent 
waiting for blueprint reference when we're stopping the context - we'd have to 
check if the target service is available anyway (why ReferenceRecipe doesn't 
have a method like "tryGetService()"?)...

Less generic fix could be to add a flag used instead of default:
{code:java}
// idempotent repository may be used by others, so add it as a service so its 
stopped when CamelContext stops
if (idempotentRepository != null) {
    getCamelContext().addService(idempotentRepository, true);
}
{code}

so user could decide whether idempotent repository is or isn't "external" 
("shared").



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Reply via email to