/**
   * Records deploy event.
   *
   * @param cls Deployed class.
   * @param clsLdr Class loader.
   * @param recordEvt Flag indicating whether to record events.
   */
  @SuppressWarnings({"unchecked"})
  private void recordDeployFailed(Class<?> cls, ClassLoader clsLdr, boolean recordEvt) {
    assert cls != null;
    assert clsLdr != null;

    boolean isTask = isTask(cls);

    String msg =
        "Failed to deploy "
            + (isTask ? "task" : "class")
            + " [cls="
            + cls
            + ", clsLdr="
            + clsLdr
            + ']';

    if (recordEvt
        && ctx.event().isRecordable(isTask ? EVT_CLASS_DEPLOY_FAILED : EVT_TASK_DEPLOY_FAILED)) {
      String taskName = isTask ? U.getTaskName((Class<? extends GridTask<?, ?>>) cls) : null;

      GridDeploymentEvent evt = new GridDeploymentEvent();

      evt.message(msg);
      evt.nodeId(ctx.localNodeId());
      evt.type(isTask(cls) ? EVT_CLASS_DEPLOY_FAILED : EVT_TASK_DEPLOY_FAILED);
      evt.alias(taskName);

      ctx.event().record(evt);
    }

    if (log.isInfoEnabled()) {
      log.info(msg);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void start() throws GridException {
    ctxLdr = U.detectClassLoader(getClass());

    spi.setListener(new LocalDeploymentListener());

    if (log.isDebugEnabled()) {
      log.debug(startInfo());
    }
  }
  /**
   * Records deploy event.
   *
   * @param cls Deployed class.
   * @param alias Class alias.
   * @param recordEvt Flag indicating whether to record events.
   */
  private void recordDeploy(Class<?> cls, String alias, boolean recordEvt) {
    assert cls != null;

    boolean isTask = isTask(cls);

    String msg = (isTask ? "Task" : "Class") + " locally deployed: " + cls;

    if (recordEvt && ctx.event().isRecordable(isTask ? EVT_TASK_DEPLOYED : EVT_CLASS_DEPLOYED)) {
      GridDeploymentEvent evt = new GridDeploymentEvent();

      evt.message(msg);
      evt.nodeId(ctx.localNodeId());
      evt.type(isTask ? EVT_TASK_DEPLOYED : EVT_CLASS_DEPLOYED);
      evt.alias(alias);

      ctx.event().record(evt);
    }

    // Don't record JDK or Grid classes.
    if (U.isGrid(cls) || U.isJdk(cls)) return;

    if (log.isInfoEnabled()) log.info(msg);
  }
  /**
   * @param depMode Deployment mode.
   * @param ldr Class loader to deploy.
   * @param cls Class.
   * @param alias Class alias.
   * @return Deployment.
   */
  @SuppressWarnings({"ConstantConditions"})
  private GridDeployment deploy(
      GridDeploymentMode depMode, ClassLoader ldr, Class<?> cls, String alias) {
    assert Thread.holdsLock(mux);

    LinkedList<GridDeployment> cachedDeps = null;

    GridDeployment dep = null;

    // Find existing class loader info.
    for (LinkedList<GridDeployment> deps : cache.values()) {
      for (GridDeployment d : deps) {
        if (d.classLoader() == ldr) {
          // Cache class and alias.
          d.addDeployedClass(cls, alias);

          cachedDeps = deps;

          dep = d;

          break;
        }
      }

      if (cachedDeps != null) {
        break;
      }
    }

    if (cachedDeps != null) {
      assert dep != null;

      cache.put(alias, cachedDeps);

      if (!cls.getName().equals(alias)) {
        // Cache by class name as well.
        cache.put(cls.getName(), cachedDeps);
      }

      return dep;
    }

    GridUuid ldrId = GridUuid.randomUuid();

    long seqNum = seq.incrementAndGet();

    String userVer = getUserVersion(ldr);

    dep = new GridDeployment(depMode, ldr, ldrId, seqNum, userVer, cls.getName(), true);

    dep.addDeployedClass(cls, alias);

    LinkedList<GridDeployment> deps =
        F.addIfAbsent(cache, alias, F.<GridDeployment>newLinkedList());

    if (!deps.isEmpty()) {
      for (GridDeployment d : deps) {
        if (!d.isUndeployed()) {
          U.error(
              log,
              "Found more than one active deployment for the same resource "
                  + "[cls="
                  + cls
                  + ", depMode="
                  + depMode
                  + ", dep="
                  + d
                  + ']');

          return null;
        }
      }
    }

    // Add at the beginning of the list for future fast access.
    deps.addFirst(dep);

    if (!cls.getName().equals(alias)) {
      // Cache by class name as well.
      cache.put(cls.getName(), deps);
    }

    if (log.isDebugEnabled()) {
      log.debug("Created new deployment: " + dep);
    }

    return dep;
  }
  /** {@inheritDoc} */
  @Nullable
  @SuppressWarnings({"UnusedCatchParameter"})
  @Override
  public GridDeployment getDeployment(GridDeploymentMetadata meta) {
    GridDeployment dep;

    Class<?> cls = null;

    String alias = meta.alias();

    synchronized (mux) {
      // Validate metadata.
      assert meta.alias() != null;

      dep = getDeployment(meta.alias());

      if (dep != null) {
        if (log.isDebugEnabled()) {
          log.debug("Acquired deployment class from local cache: " + dep);
        }

        return dep;
      }

      GridDeploymentResource rsrc = spi.findResource(meta.alias());

      if (rsrc != null) {
        dep =
            deploy(
                ctx.config().getDeploymentMode(),
                rsrc.getClassLoader(),
                rsrc.getResourceClass(),
                alias);

        if (dep == null) {
          return null;
        }

        if (log.isDebugEnabled()) {
          log.debug("Acquired deployment class from SPI: " + dep);
        }
      }
      // Auto-deploy.
      else {
        ClassLoader ldr = meta.classLoader();

        if (ldr == null) {
          ldr = Thread.currentThread().getContextClassLoader();

          // Safety.
          if (ldr == null) {
            ldr = ctxLdr;
          }
        }

        // Don't auto-deploy locally in case of nested execution.
        if (ldr instanceof GridDeploymentClassLoader) {
          return null;
        }

        try {
          // Check that class can be loaded.
          cls = ldr.loadClass(meta.alias());

          spi.register(ldr, cls);

          rsrc = spi.findResource(alias);

          if (rsrc != null && rsrc.getResourceClass().equals(cls)) {
            if (log.isDebugEnabled()) {
              log.debug("Retrieved auto-loaded resource from spi: " + rsrc);
            }

            dep = deploy(ctx.config().getDeploymentMode(), ldr, cls, alias);

            if (dep == null) {
              return null;
            }
          } else {
            U.warn(
                log,
                "Failed to find resource from deployment SPI even after registering it: "
                    + meta.alias());

            return null;
          }
        } catch (ClassNotFoundException e) {
          if (log.isDebugEnabled()) {
            log.debug(
                "Failed to load class for local auto-deployment [ldr="
                    + ldr
                    + ", meta="
                    + meta
                    + ']');
          }

          return null;
        } catch (GridSpiException e) {
          U.error(log, "Failed to deploy local class: " + meta.alias(), e);

          return null;
        }
      }
    }

    if (cls != null) {
      recordDeploy(cls, alias, meta.isRecord());

      dep.addDeployedClass(cls, meta.className(), meta.alias());
    }

    if (log.isDebugEnabled()) {
      log.debug("Acquired deployment class: " + dep);
    }

    return dep;
  }