public synchronized ProcessEngine installProcessArchive(ProcessArchive processArchive) {
    final String paName = processArchive.getName();

    if (!isActive) {
      throw new FoxPlatformException(
          "Cannot install process archive with name "
              + paName
              + ": ProcessEngineService is not active.");
    }

    if (installedProcessArchivesByName.containsKey(paName)) {
      throw new FoxPlatformException(
          "Cannot install process archive with name '"
              + paName
              + "': process archive with same name already installed.");
    }

    log.info("Installing process archive '" + paName + "'");
    Deployment deployment = performEngineDeployment(processArchive);

    ProcessArchiveContext processArchiveContext =
        new ProcessArchiveContext(deployment, processArchive);
    processArchiveContext.setActive(true);
    installedProcessArchivesByName.put(processArchive.getName(), processArchiveContext);

    ArrayList<ProcessArchive> processArchives =
        new ArrayList<ProcessArchive>(cachedProcessArchives);
    processArchives.add(processArchive);
    cachedProcessArchives = Collections.unmodifiableList(processArchives);

    if (deployment != null) {
      List<ProcessDefinition> processDefinitionsForThisDeployment =
          activitiProcessEngine
              .getRepositoryService()
              .createProcessDefinitionQuery()
              .deploymentId(deployment.getId())
              .list();
      for (ProcessDefinition processDefinition : processDefinitionsForThisDeployment) {
        installedProcessArchivesByProcessDefinitionKey.put(
            processDefinition.getKey(), processArchiveContext);
      }
      log.info(
          "Installed process archive '"
              + paName
              + "' to process engine '"
              + processEngineName
              + "'.");
      return activitiProcessEngine;
    } else {
      log.info(
          "Installed empty process archive '"
              + paName
              + "'. Process archive will have access to process engine with name '"
              + processEngineName
              + "'.");
      return activitiProcessEngine;
    }
  }
 public synchronized void unInstallProcessArchive(ProcessArchive processArchive) {
   final String paName = processArchive.getName();
   if (!isActive) {
     log.fine(
         "Ignoring uninstall operation of process archive '"
             + paName
             + "' on non-active ProcessEngineService.");
   } else {
     performUndeployment(processArchive);
     log.info("Uninstalled process archive '" + paName + "'");
   }
 }
  protected void performUndeployment(ProcessArchive processArchive) {
    final String paName = processArchive.getName();

    ProcessArchiveContext processArchiveContext = installedProcessArchivesByName.get(paName);
    if (processArchiveContext == null) {
      return;
    }

    try {
      processArchiveContext.setUndelploying(true);
      performEngineUndeployment(processArchive);
    } catch (Exception e) {
      log.log(Level.SEVERE, "Exception while performing process engine undeployment: ", e);
    } finally {
      processArchiveContext.setUndelploying(false);
      processArchiveContext.setActive(false);

      installedProcessArchivesByName.remove(paName);

      ArrayList<ProcessArchive> processArchives =
          new ArrayList<ProcessArchive>(cachedProcessArchives);
      processArchives.remove(processArchive);
      cachedProcessArchives = Collections.unmodifiableList(processArchives);

      if (processArchiveContext.getActivitiDeployment() != null) {
        String activitiDeploymentId = processArchiveContext.getActivitiDeployment().getId();
        List<ProcessDefinition> processDefinitions =
            activitiProcessEngine
                .getRepositoryService()
                .createProcessDefinitionQuery()
                .deploymentId(activitiDeploymentId)
                .list();
        for (ProcessDefinition processDefinition : processDefinitions) {
          installedProcessArchivesByProcessDefinitionKey.remove(processDefinition.getKey());
        }
      }
    }
  }