[
https://issues.apache.org/jira/browse/CAMEL-11810?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Grzegorz Grzybek updated CAMEL-11810:
-------------------------------------
Description:
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&readLock=idempotent&idempotent=true&idempotentRepository=#messageIdRepository&other.properties[...]"
/>
{code}
The problem is that when bundle defining {{messageIdRepositoryImpl}} is
stopped, stopping bundle/blueprint-container with camel context that references
{{messageIdRepositoryImpl}} 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").
was:
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&readLock=idempotent&idempotent=true&idempotentRepository=#messageIdRepository&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").
> 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&readLock=idempotent&idempotent=true&idempotentRepository=#messageIdRepository&other.properties[...]"
> />
> {code}
> The problem is that when bundle defining {{messageIdRepositoryImpl}} is
> stopped, stopping bundle/blueprint-container with camel context that
> references {{messageIdRepositoryImpl}} 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)