@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"}) public Object getInstance(ScopedComponent component) { Object instance = instances.get(component); if (instance != EMPTY && instance != null) { return instance; } CountDownLatch latch; // Avoid race condition where two or more threads attempt to initialize the component instance // concurrently. // Pending component instantiations are tracked and threads block on a latch until they are // complete. synchronized (component) { latch = pending.get(component); if (latch != null) { try { // wait on the instantiation latch.await(5, TimeUnit.MINUTES); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new Fabric3Exception("Error creating instance for: " + component.getUri(), e); } // an instance wrapper is now available as the instantiation has completed return instances.get(component); } else { latch = new CountDownLatch(1); pending.put(component, latch); } } try { instance = component.createInstance(); // some component instances such as system singletons may already be started // if (!component.isInstanceStarted()) { component.startInstance(instance); List<Pair> queue; URI uri = component.getContributionUri(); synchronized (destroyQueues) { queue = destroyQueues.get(uri); if (queue == null) { // The context has not been initialized. This can happen if two deployable composites are // deployed simultaneously and a // component in the first composite to be deployed references a component in the second // composite. In this case, // create the destroy queue prior to the context being started. queue = new ArrayList<>(); destroyQueues.put(uri, queue); } } queue.add(new Pair(component, instance)); // } instances.put(component, instance); latch.countDown(); return instance; } finally { pending.remove(component); } }
/** * Initialize an ordered list of components. The list is traversed in order and the getWrapper() * method called for each to associate an instance with the supplied context. * * @param components the components to be initialized * @throws GroupInitializationException if one or more components threw an exception during * initialization */ private void initializeComponents(List<ScopedComponent> components) throws GroupInitializationException { Set<URI> causes = null; for (ScopedComponent component : components) { try { getInstance(component); } catch (Exception e) { if (causes == null) { causes = new LinkedHashSet<>(); } URI uri = component.getUri(); monitor.initializationError(uri, component.getContributionUri(), e); causes.add(uri); } } if (causes != null) { throw new GroupInitializationException(causes); } }
/** * Shut down an ordered list of instances. The list passed to this method is treated as a live, * mutable list so any instances added to this list as shutdown is occurring will also be shut * down. * * @param instances the list of instances to shutdown */ @SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"}) private void destroyInstances(List<Pair> instances) { while (true) { Pair toDestroy; synchronized (instances) { if (instances.size() == 0) { return; } toDestroy = instances.remove(instances.size() - 1); } ScopedComponent component = toDestroy.component; try { Object instance = toDestroy.instance; component.stopInstance(instance); } catch (Fabric3Exception e) { // log the error from destroy but continue monitor.destructionError(component.getUri(), component.getContributionUri(), e); } } }