@Override
  public synchronized void fireUndeployEvent(HotDeployEvent hotDeployEvent) {
    for (int i = _hotDeployListeners.size() - 1; i >= 0; i--) {
      HotDeployListener hotDeployListener = _hotDeployListeners.get(i);

      PortletClassLoaderUtil.setServletContextName(hotDeployEvent.getServletContextName());

      try {
        hotDeployListener.invokeUndeploy(hotDeployEvent);
      } catch (HotDeployException hde) {
        _log.error(hde, hde);
      } finally {
        PortletClassLoaderUtil.setServletContextName(null);
      }
    }

    _deployedServletContextNames.remove(hotDeployEvent.getServletContextName());

    ClassLoader classLoader = hotDeployEvent.getContextClassLoader();

    TemplateManagerUtil.destroy(classLoader);

    _pacl.unregister(classLoader);

    RequiredPluginsUtil.startCheckingRequiredPlugins();
  }
  @Override
  public void invokeUndeploy(HotDeployEvent hotDeployEvent) throws HotDeployException {

    for (HotDeployListener hotDeployListener : _serviceTrackerList) {
      hotDeployListener.invokeUndeploy(hotDeployEvent);
    }
  }
  protected void doFireDeployEvent(HotDeployEvent hotDeployEvent) {
    String servletContextName = hotDeployEvent.getServletContextName();

    if (_deployedServletContextNames.contains(servletContextName)) {
      return;
    }

    boolean hasDependencies = true;

    for (String dependentServletContextName : hotDeployEvent.getDependentServletContextNames()) {

      if (!_deployedServletContextNames.contains(dependentServletContextName)) {

        hasDependencies = false;

        break;
      }
    }

    if (hasDependencies) {
      if (_log.isInfoEnabled()) {
        _log.info("Deploying " + servletContextName + " from queue");
      }

      for (int i = 0; i < _hotDeployListeners.size(); i++) {
        HotDeployListener hotDeployListener = _hotDeployListeners.get(i);

        PortletClassLoaderUtil.setServletContextName(hotDeployEvent.getServletContextName());

        try {
          hotDeployListener.invokeDeploy(hotDeployEvent);
        } catch (HotDeployException hde) {
          _log.error(hde, hde);
        } finally {
          PortletClassLoaderUtil.setServletContextName(null);
        }
      }

      _deployedServletContextNames.add(servletContextName);

      _dependentHotDeployEvents.remove(hotDeployEvent);

      ClassLoader contextClassLoader = getContextClassLoader();

      try {
        setContextClassLoader(ClassLoaderUtil.getPortalClassLoader());

        List<HotDeployEvent> dependentEvents = new ArrayList<>(_dependentHotDeployEvents);

        for (HotDeployEvent dependentEvent : dependentEvents) {
          setContextClassLoader(dependentEvent.getContextClassLoader());

          doFireDeployEvent(dependentEvent);

          dependentEvent.flushInits();
        }
      } finally {
        setContextClassLoader(contextClassLoader);
      }
    } else {
      if (!_dependentHotDeployEvents.contains(hotDeployEvent)) {
        if (_log.isInfoEnabled()) {
          StringBundler sb = new StringBundler(4);

          sb.append("Queueing ");
          sb.append(servletContextName);
          sb.append(" for deploy because it is missing ");
          sb.append(getRequiredServletContextNames(hotDeployEvent));

          _log.info(sb.toString());
        }

        _dependentHotDeployEvents.add(hotDeployEvent);
      } else {
        if (_log.isInfoEnabled()) {
          for (HotDeployEvent dependentHotDeployEvent : _dependentHotDeployEvents) {

            StringBundler sb = new StringBundler(3);

            sb.append(servletContextName);
            sb.append(" is still in queue because it is missing ");
            sb.append(getRequiredServletContextNames(dependentHotDeployEvent));

            _log.info(sb.toString());
          }
        }
      }
    }
  }