@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);
     }
   }
 }