/**
   * Records undeploy event.
   *
   * @param dep Undeployed class loader.
   * @param recordEvt Flag indicating whether to record events.
   */
  private void recordUndeploy(GridDeployment dep, boolean recordEvt) {
    assert dep.isUndeployed();

    if (ctx.event().isRecordable(EVT_TASK_UNDEPLOYED)
        || ctx.event().isRecordable(EVT_CLASS_UNDEPLOYED)) {
      for (Class<?> cls : dep.deployedClasses()) {
        boolean isTask = isTask(cls);

        String msg =
            isTask ? "Task locally undeployed: " + cls : "Class locally undeployed: " + cls;

        if (ctx.event().isRecordable(isTask ? EVT_TASK_UNDEPLOYED : EVT_CLASS_UNDEPLOYED)) {
          if (recordEvt) {
            GridDeploymentEvent evt = new GridDeploymentEvent();

            evt.message(msg);
            evt.nodeId(ctx.localNodeId());
            evt.type(isTask ? EVT_TASK_UNDEPLOYED : EVT_CLASS_UNDEPLOYED);
            evt.alias(getAlias(dep, cls));

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

        if (log.isInfoEnabled()) {
          log.info(msg);
        }
      }
    }
  }
  /**
   * 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);
    }
  }
  /**
   * 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);
  }
    /**
     * Called to record all undeployed classes..
     *
     * @param leftNodeId Left node ID.
     */
    void recordUndeployed(@Nullable UUID leftNodeId) {
      assert !Thread.holdsLock(mux);

      for (Map.Entry<String, Class<?>> depCls : deployedClassMap().entrySet()) {
        boolean isTask = isTask(depCls.getValue());

        String msg =
            (isTask ? "Task" : "Class")
                + " was undeployed in SHARED or CONTINUOUS mode: "
                + depCls.getValue();

        int type = isTask ? EVT_TASK_UNDEPLOYED : EVT_CLASS_UNDEPLOYED;

        if (ctx.event().isRecordable(type)) {
          GridDeploymentEvent evt = new GridDeploymentEvent();

          evt.nodeId(ctx.localNodeId());
          evt.message(msg);
          evt.type(type);
          evt.alias(depCls.getKey());

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

        if (log.isInfoEnabled()) log.info(msg);
      }

      if (isObsolete()) {
        // Resource cleanup.
        ctx.resource().onUndeployed(this);

        ctx.cache().onUndeployed(leftNodeId, loader());

        clearSerializationCaches();
      }
    }
    /** {@inheritDoc} */
    @Override
    public void onDeployed(Class<?> cls) {
      assert !Thread.holdsLock(mux);

      boolean isTask = isTask(cls);

      String msg =
          (isTask ? "Task" : "Class") + " was deployed in SHARED or CONTINUOUS mode: " + cls;

      int type = isTask ? EVT_TASK_DEPLOYED : EVT_CLASS_DEPLOYED;

      if (ctx.event().isRecordable(type)) {
        GridDeploymentEvent evt = new GridDeploymentEvent();

        evt.nodeId(ctx.localNodeId());
        evt.message(msg);
        evt.type(type);
        evt.alias(cls.getName());

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

      if (log.isInfoEnabled()) log.info(msg);
    }