[ https://issues.apache.org/jira/browse/FELIX-4847?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14487040#comment-14487040 ]
Tuomas Kiviaho commented on FELIX-4847: --------------------------------------- In my case the temporal service remained unavailable (used dm shell to verify this) until the actual service arrived. This is the behavior expected from {{required}} temporal service dependency and I see now that tampering with what {{isAvailable()}} returns - as per 1) proposal - would break the backwards compatibility. I did not understand that the intention was to actually wait until there is a service before dependency becomes available. Therefore my only working proposal is 2) that is allowing the temporal service to be optional as well. What I'd like to happen in this mode is for the dependency to be available immediately and for the proxy to block/wait for the services first appearance if user happens to access it prematurely. This is indeed what would happen if optionality would not have been explicitly forbidden in {{setRequired}} method. DefaultNullObject used by non-temporal service dependency instead would return null immediately causing NPE in my usecase. This is a snippet from my PDE JUnit test case (magic happens inside a rule below that understands DM 3.x annotations) that relies on optional temporal service. Otherwise I'd have to manually track/wait Foobar service after asynchronous CM update (with a custom default impl) {code} public class FoobarIT { @Rule public TestRule testRule = new DependencyManagerTestRule() { protected Object getWrapped() { return FoobarIT.this; }}; @Inject private BundleContext bundleContext; @ServiceDependency(name = Foobar.PID, timeout = 60000) private Foobar foobar; @ServiceDependency private ConfigurationAdmin configurationAdmin; @ResourceDependency(filter = "(" + ResourceHandler.PATH + "=/META-INF/" + Foobar.PID + ".cfg)") private URL url; @Init Map<String, ?> init() throws IOException { Bundle bundle = this.bundleContext.getBundle(); String location = bundle.getLocation(); Configuration configuration = this.configurationAdmin.getConfiguration(Foobar.PID, location); Properties properties = new Properties(); try (InputStream inputStream = this.url.openStream();) { properties.load(inputStream); } configuration.update((Dictionary) properties); return Collections.singletonMap(Foobar.PID + ".required", Boolean.FALSE); } @Test public void test() { this.foobar.blockUntilConfigured(); } } {code} The verification that JUnit test case is ready for evaluation (required->available) is done inside evaluate method. I got it working by patching {{TemporalServiceDependencyImpl}} just by removing the setRequired() method that would have been executed->failed when {{init()}} method of the test returned. ComponentProvider is still proprietary piece of code that functions in place of runtime bundle (reading annotations directly from the classes themselves), but I guess it's clear what it does. {code} public abstract class DependencyManagerTestRule implements TestRule { private DependencyManager dependencyManager; public DependencyManagerTestRule() { Object wrapped = this.getWrapped(); Bundle bundle = FrameworkUtil.getBundle(wrapped.getClass()); BundleContext bundleContext = bundle.getBundleContext(); this.dependencyManager = new DependencyManager(bundleContext); } protected abstract Object getWrapped(); @Override public Statement apply(final Statement wrapped, Description description) { Class<? extends Object> testClass = description.getTestClass(); ComponentProvider componentProvider = new ComponentProvider( this.dependencyManager, testClass); final Component component = componentProvider.get(); Object implementation = this.getWrapped(); component.setImplementation(implementation); Statement statement = new Statement() { @Override public void evaluate() throws Throwable { DependencyManagerTestRule.this.dependencyManager.add(component); @SuppressWarnings("unchecked") List<Dependency> dependencies = component.getDependencies(); for (Dependency dependency : dependencies) { boolean required = dependency.isRequired(); boolean available = dependency.isAvailable(); if (!available && required) { ComponentDependencyDeclaration componentDependencyDeclaration = (ComponentDependencyDeclaration) dependency; String type = componentDependencyDeclaration.getType(); String name = componentDependencyDeclaration.getName(); throw new IllegalStateException(type + ": " + name); } } try { wrapped.evaluate(); } finally { DependencyManagerTestRule.this.dependencyManager.remove(component); } } }; return statement; } } {code} > Make TemporalServiceDependency always available (and/or allow it to be > optional) > -------------------------------------------------------------------------------- > > Key: FELIX-4847 > URL: https://issues.apache.org/jira/browse/FELIX-4847 > Project: Felix > Issue Type: Wish > Components: Dependency Manager > Affects Versions: dependencymanager-3.2.0 > Reporter: Tuomas Kiviaho > > I wanted to use temporal service to wait for CM update thread to finish what > it's doing (because the spec doesn't have a non-parallel version). > Everything worked fine until JUnit test rule said that the component isn't > ready yet. I was merely checking that every required dependency was also > available and to my surprise the temporal service was marked unavailable > until the CM had completed what it was doing. > 1) Shouldn't temporal service be always available externally via available > property and keep track on the actual state only internally? This approach > might not be backwards compatible. > 2) Could temporal service be allowed to be marked as optional. This would > suit my use case, but it feels like a 'golden hammer' approach because it > alters component's state machine behavior a bit which in turn can be harmful > for other use cases. > As a workaround I'd have to differentiate the dependencies somehow from each > other, but I see that the 4.x has removed the dedicated interface that I was > thinking of relying upon to. -- This message was sent by Atlassian JIRA (v6.3.4#6332)