[ 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)