/** {@inheritDoc} */
  @Override
  public void explicitUndeploy(UUID nodeId, String rsrcName) {
    Collection<SharedDeployment> undeployed = new LinkedList<SharedDeployment>();

    synchronized (mux) {
      for (Iterator<List<SharedDeployment>> i1 = cache.values().iterator(); i1.hasNext(); ) {
        List<SharedDeployment> deps = i1.next();

        for (Iterator<SharedDeployment> i2 = deps.iterator(); i2.hasNext(); ) {
          SharedDeployment dep = i2.next();

          if (dep.hasName(rsrcName)) {
            if (!dep.isUndeployed()) {
              dep.undeploy();

              dep.onRemoved();

              // Undeploy.
              i2.remove();

              undeployed.add(dep);

              if (log.isInfoEnabled()) log.info("Undeployed per-version class loader: " + dep);
            }

            break;
          }
        }

        if (deps.isEmpty()) i1.remove();
      }
    }

    recordUndeployed(null, undeployed);
  }
  /** {@inheritDoc} */
  @Override
  public void onKernalStart() throws GridException {
    discoLsnr =
        new GridLocalEventListener() {
          @Override
          public void onEvent(GridEvent evt) {
            assert evt instanceof GridDiscoveryEvent;

            assert evt.type() == EVT_NODE_LEFT || evt.type() == EVT_NODE_FAILED;

            GridDiscoveryEvent discoEvt = (GridDiscoveryEvent) evt;

            Collection<SharedDeployment> undeployed = new LinkedList<SharedDeployment>();

            if (log.isDebugEnabled()) log.debug("Processing node departure event: " + evt);

            synchronized (mux) {
              for (Iterator<List<SharedDeployment>> i1 = cache.values().iterator();
                  i1.hasNext(); ) {
                List<SharedDeployment> deps = i1.next();

                for (Iterator<SharedDeployment> i2 = deps.iterator(); i2.hasNext(); ) {
                  SharedDeployment dep = i2.next();

                  dep.removeParticipant(discoEvt.eventNodeId());

                  if (!dep.hasParticipants()) {
                    if (dep.deployMode() == SHARED) {
                      if (!dep.isUndeployed()) {
                        dep.undeploy();

                        // Undeploy.
                        i2.remove();

                        assert !dep.isRemoved();

                        dep.onRemoved();

                        undeployed.add(dep);

                        if (log.isDebugEnabled())
                          log.debug(
                              "Undeployed class loader as there are no participating "
                                  + "nodes: "
                                  + dep);
                      }
                    } else if (log.isDebugEnabled())
                      log.debug("Preserving deployment without node participants: " + dep);
                  } else if (log.isDebugEnabled())
                    log.debug("Keeping deployment as it still has participants: " + dep);
                }

                if (deps.isEmpty()) i1.remove();
              }
            }

            recordUndeployed(discoEvt.eventNodeId(), undeployed);
          }
        };

    ctx.event().addLocalEventListener(discoLsnr, EVT_NODE_FAILED, EVT_NODE_LEFT);

    Collection<SharedDeployment> undeployed = new LinkedList<SharedDeployment>();

    synchronized (mux) {
      for (Iterator<List<SharedDeployment>> i1 = cache.values().iterator(); i1.hasNext(); ) {
        List<SharedDeployment> deps = i1.next();

        for (Iterator<SharedDeployment> i2 = deps.iterator(); i2.hasNext(); ) {
          SharedDeployment dep = i2.next();

          for (UUID nodeId : dep.getParticipantNodeIds())
            if (ctx.discovery().node(nodeId) == null) dep.removeParticipant(nodeId);

          if (!dep.hasParticipants()) {
            if (dep.deployMode() == SHARED) {
              if (!dep.isUndeployed()) {
                dep.undeploy();

                // Undeploy.
                i2.remove();

                dep.onRemoved();

                undeployed.add(dep);

                if (log.isDebugEnabled())
                  log.debug("Undeployed class loader as there are no participating nodes: " + dep);
              }
            } else if (log.isDebugEnabled())
              log.debug("Preserving deployment without node participants: " + dep);
          } else if (log.isDebugEnabled())
            log.debug("Keeping deployment as it still has participants: " + dep);
        }

        if (deps.isEmpty()) i1.remove();
      }
    }

    recordUndeployed(null, undeployed);

    if (log.isDebugEnabled()) log.debug("Registered deployment discovery listener: " + discoLsnr);
  }