package org.camunda.demo.liferay.tasklist;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.portlet.ActionResponse;
import javax.portlet.PortletSession;
import javax.xml.namespace.QName;

import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.application.ProcessApplicationInfo;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.task.Task;

import com.liferay.faces.portal.context.LiferayFacesContext;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.model.Layout;
import com.liferay.portal.model.LayoutTypePortlet;
import com.liferay.portal.model.Portlet;
import com.liferay.portal.model.PortletConstants;
import com.liferay.portal.model.User;
import com.liferay.portal.service.LayoutLocalServiceUtil;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portal.util.PortalUtil;

@Named("tasklist")
//@SessionScoped
// TODO: check redeployment session handling with liferay
public class TasklistBean implements Serializable {

  private static final long serialVersionUID = 1L;

  public static String ADDED_PORTLETS = "camunda.portlets.added";
  public static final String BRIDGE_TASK_ID = "camunda.bridge.selected.task.id";
  public static final String BRIDGE_PROCESS_DEFINITION_ID = "camunda.bridge.selected.processdefinition.id";

  @Inject
  private transient TaskService taskService;

  @Inject
  private transient ProcessEngine processEngine;

  /**
   * okay - should not be static - I know ;-) Should be SessionScoped
   */
  public static HashMap<String, String> formKeys = new HashMap<String, String>();
  public static Set<String> businessVariables;

  public ProcessDefinition getProcessDefinitionForTask(Task task) {
    // TODO: Add cache
    return processEngine.getRepositoryService().getProcessDefinition(task.getProcessDefinitionId());
  }

  public List<Task> getPersonalTasks() {
    // TODO: add logic to query only user tasks
    User user = LiferayFacesContext.getInstance().getUser();

    // at the moment return all tasks
    List<Task> tasks = taskService.createTaskQuery().orderByTaskCreateTime().desc().list();
    // TODO: cache tasks! Otherwise we may load this multiple times

    // lazy load the form keys, TODO: Think about if this should be really limited to active tasks?
    for (Task task : tasks) {
      String key = task.getProcessDefinitionId() + "#" + task.getTaskDefinitionKey();
      if (!formKeys.containsKey(key)) {
        addFormKey(key, processEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey()));
      }
    }

    return tasks;
  }

  private void addFormKey(String key, String taskFormKey) {
    StringTokenizer tokenizer = new StringTokenizer(taskFormKey, ",");
    formKeys.put(key, tokenizer.nextToken());

    while (tokenizer.hasMoreElements()) {
      String variableName = tokenizer.nextToken();
      if (variableName!=null) {
        businessVariables.add(variableName.trim());
      }
    }
  }

  public List<ProcessDefinition> getStartableProcessDefinitions() {
    List<ProcessDefinition> processDefinitionList = processEngine.getRepositoryService().createProcessDefinitionQuery().latestVersion().active().list();
    return processDefinitionList;
  }

  public Object getVariable(Task task, String variableName) {
    // TODO: better load in custom query
    return processEngine.getTaskService().getVariable(task.getId(), variableName);
  }

  public void startProcessInstance(ProcessDefinition pd) {
    if (pd.hasStartFormKey()) {
      String formKey = processEngine.getFormService().getStartFormKey(pd.getId());
      String portletId = constructPortletId(pd.getId(), formKey);
      setSharedAttribute(pd);
      showPortlet(portletId);
    } else {
      processEngine.getRuntimeService().startProcessInstanceById(pd.getId());
    }
  }

  public void selectTask(Task task) {
    String key = task.getProcessDefinitionId() + "#" + task.getTaskDefinitionKey();
    String formKey = formKeys.get(key); //processEngine.getFormService().getTaskFormKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
    String portletId = constructPortletId(task.getProcessDefinitionId(), formKey);

    setSharedAttribute(task);
    showPortlet(portletId);
    // now send the event (to everybody interested - including the new portlet)
    // sendIpcEvent(task);
  }

  private void showPortlet(String portletId) {
    // this is hard coded at the moment - put it in the bigger column (make
    // configurable?)
    String columnId = "column-2";

    try {
      FacesContext facesContext = FacesContext.getCurrentInstance();
      ThemeDisplay themeDisplay = (ThemeDisplay) facesContext.getExternalContext().getRequestMap().get(WebKeys.THEME_DISPLAY);
      Layout layout = (Layout) facesContext.getExternalContext().getRequestMap().get(WebKeys.LAYOUT);
      LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet) layout.getLayoutType();
      long userId = themeDisplay.getUserId();

      removeAllOfSameTaskFormPortlets(portletId, userId, layoutTypePortlet);

      List<String> addedPortlets = (List<String>) getSharedAttribute(ADDED_PORTLETS);
      if (addedPortlets == null) {
        addedPortlets = new ArrayList<String>();
      } else {
        for (String portletIdToRemove : addedPortlets) {
          layoutTypePortlet.removePortletId(userId, portletIdToRemove);
        }
        addedPortlets.clear();
      }

      // add the new one
      // TODO: add message if task form portlet cannot be found
      String lastTaskPortletId = layoutTypePortlet.addPortletId(themeDisplay.getUserId(), portletId, columnId, -1);
      // http://www.liferay.com/de/community/forums/-/message_boards/message/3575947
      addedPortlets.add(lastTaskPortletId);
      setSharedAttribute(ADDED_PORTLETS, addedPortlets);

      LayoutLocalServiceUtil.updateLayout(layout);
    } catch (Exception ex) {
      throw new RuntimeException("Could not add portlet from tasklist. Root error: " + ex.getMessage(), ex);
    }
  }

  private String constructPortletId(String processDefinitionId, String formKey) {
    // now context path
    ProcessDefinition processDefinition = processEngine.getRepositoryService().getProcessDefinition(processDefinitionId);
    String processApplicationName = processEngine.getManagementService().getProcessApplicationForDeployment(processDefinition.getDeploymentId());
    String contextPath = BpmPlatform.getProcessApplicationService().getProcessApplicationInfo(processApplicationName).getProperties()
        .get(ProcessApplicationInfo.PROP_SERVLET_CONTEXT_PATH);

    // this gives us the PortletId
    String portletId = getPortletId(formKey, contextPath);
    return portletId;
  }

  private void removeAllOfSameTaskFormPortlets(String portletId, long userId, LayoutTypePortlet layoutTypePortlet) throws PortalException, SystemException {
    for (Portlet p : layoutTypePortlet.getAllPortlets()) {
      // an instance ID is added at the end - so only check startsWith
      if (p.getPortletId().startsWith(portletId)) {
        layoutTypePortlet.removePortletId(userId, p.getPortletId());
      }
    }
  }

  /**
   * Do this as a workaround till IPC works correctly see
   * http://www.liferay.com/
   * de/community/forums/-/message_boards/message/27295776
   */
  private void setSharedAttribute(Task task) {
    setSharedAttribute(BRIDGE_TASK_ID, task.getId());
    setSharedAttribute(BRIDGE_PROCESS_DEFINITION_ID, null);
  }

  private void sendIpcEvent(Task task) {
    QName qName = new QName("http://camunda.org/events", "ipc.taskSelected");
    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    ActionResponse actionResponse = (ActionResponse) externalContext.getResponse();
    actionResponse.setEvent(qName, task.getId());
  }

  private void setSharedAttribute(ProcessDefinition pd) {
    setSharedAttribute(BRIDGE_PROCESS_DEFINITION_ID, pd.getId());
    setSharedAttribute(BRIDGE_TASK_ID, null);
  }

  public static void setSharedAttribute(String key, Object value) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    PortletSession portletSession = (PortletSession) externalContext.getSession(false);
    // make sure you have
    // <private-session-attributes>false</private-session-attributes> in
    // liferay-portal.xml
    portletSession.setAttribute(key, value, PortletSession.APPLICATION_SCOPE);
  }

  public static Object getSharedAttribute(String key) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    PortletSession portletSession = (PortletSession) externalContext.getSession(false);
    // make sure you have
    // <private-session-attributes>false</private-session-attributes> in
    // liferay-portal.xml
    return portletSession.getAttribute(key, PortletSession.APPLICATION_SCOPE);
  }

  /**
   * copied from
   * https://github.com/liferay/liferay-portal/blob/master/portal-impl
   * /src/com/liferay/portal/service/impl/PortletLocalServiceImpl.java
   *
   * see
   * http://stackoverflow.com/questions/11151001/how-to-get-portlet-id-using-
   * the-portlet-name-in-liferay
   */
  public String getPortletId(String portletName, String servletContextName) {
    String portletId = portletName;

    if (Validator.isNotNull(servletContextName)) {
      if (servletContextName.startsWith("/")) {
        servletContextName = servletContextName.substring(1);
      }
      portletId = portletId.concat(PortletConstants.WAR_SEPARATOR).concat(servletContextName);
    }

    portletId = PortalUtil.getJsSafePortletId(portletId);
    return portletId;
  }

  public Set<String> getBusinessVariables() {
    if (businessVariables==null) {
      // not yet initialized - this is called too early (JSTL before JSF).
      businessVariables = new HashSet<String>();
      // TODO: cache tasks! Otherwise we load this multiple times
      getPersonalTasks();
    }
    return businessVariables;
  }
}


package com.camunda.potsdam.UserAndTenantCreator;

import java.util.HashMap;
import java.util.Map;

import static org.camunda.bpm.engine.authorization.Authorization.ANY;
import static org.camunda.bpm.engine.authorization.Authorization.AUTH_TYPE_GRANT;
import static org.camunda.bpm.engine.authorization.Permissions.ALL;

import org.camunda.bpm.application.PostDeploy;
import org.camunda.bpm.application.ProcessApplication;
import org.camunda.bpm.application.impl.ServletProcessApplication;
import org.camunda.bpm.engine.AuthorizationService;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.authorization.Groups;
import org.camunda.bpm.engine.authorization.Resource;
import org.camunda.bpm.engine.authorization.Resources;
import org.camunda.bpm.engine.identity.Group;
import org.camunda.bpm.engine.identity.Tenant;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.persistence.entity.AuthorizationEntity;

/**
 * Process Application exposing this application's resources the process engine.
 */
@ProcessApplication
public class CamundaBpmProcessApplication extends ServletProcessApplication {

  private static final String PROCESS_DEFINITION_KEY = "UserAndTenantCreator";

  /**
   * In a @PostDeploy Hook you can interact with the process engine and access
   * the processes the application has deployed.
   */
  @PostDeploy
  public void onDeploymentFinished(ProcessEngine processEngine) {

	  User user = processEngine.getIdentityService().createUserQuery().userId("niall").singleResult();
	  if(user != null) {
		  return;
	  }

	  // Create admin user....
	  createInitialUserInternal(processEngine);
	  // create camunda admin group.
	  //ensureCamundaAdminGroupExists(processEngine);
	  // give admin all resources.
	  // example:
	  // https://github.com/camunda/camunda-bpm-webapp/blob/master/src/main/java/org/camunda/bpm/admin/impl/web/SetupResource.java

    // start an initial process instance
//    Map<String, Object> variables = new HashMap<String, Object>();
//    variables.put("name", "John");
//
//    processEngine.getRuntimeService().startProcessInstanceByKey(PROCESS_DEFINITION_KEY, variables);
  }
  protected void createInitialUserInternal(ProcessEngine processEngine) {

	  final IdentityService identityService = processEngine.getIdentityService();

	  String userName = "niall";
	    // make sure we can process this request at this time
	  User user = identityService.newUser(userName);
      user.setFirstName("Niall");
      user.setLastName("Deehan");
      user.setPassword("Tassilo");
      user.setEmail("nope");
      identityService.saveUser(user);

	    // crate the camunda admin group
	    ensureCamundaAdminGroupExists(processEngine);

	    // create group membership (add new user to admin group)
	    processEngine.getIdentityService()
	      .createMembership(user.getId(), Groups.CAMUNDA_ADMIN);
	}

  protected void ensureCamundaAdminGroupExists(ProcessEngine processEngine) {

    final IdentityService identityService = processEngine.getIdentityService();
    final AuthorizationService authorizationService = processEngine.getAuthorizationService();

    // create group
    if(identityService.createGroupQuery().groupId(Groups.CAMUNDA_ADMIN).count() == 0) {
      Group camundaAdminGroup = identityService.newGroup(Groups.CAMUNDA_ADMIN);
      camundaAdminGroup.setName("camunda BPM Administrators");
      camundaAdminGroup.setType(Groups.GROUP_TYPE_SYSTEM);
      identityService.saveGroup(camundaAdminGroup);
    }

    // create ADMIN authorizations on all built-in resources
    for (Resource resource : Resources.values()) {
      if(authorizationService.createAuthorizationQuery().groupIdIn(Groups.CAMUNDA_ADMIN).resourceType(resource).resourceId(ANY).count() == 0) {
        AuthorizationEntity userAdminAuth = new AuthorizationEntity(AUTH_TYPE_GRANT);
        userAdminAuth.setGroupId(Groups.CAMUNDA_ADMIN);
        userAdminAuth.setResource(resource);
        userAdminAuth.setResourceId(ANY);
        userAdminAuth.addPermission(ALL);
        authorizationService.saveAuthorization(userAdminAuth);
      }
    }

}

}


package com.camunda.demo.tenant.manager;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.application.ProcessApplicationReference;
import org.camunda.bpm.container.RuntimeContainerDelegate;
import org.camunda.bpm.container.impl.jmx.JmxRuntimeContainerDelegate;
import org.camunda.bpm.container.impl.jmx.JmxRuntimeContainerDelegate.ServiceTypes;
import org.camunda.bpm.container.impl.jmx.kernel.MBeanServiceContainer;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.impl.ProcessEngineImpl;
import org.camunda.bpm.engine.impl.application.ProcessApplicationManager;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
import org.camunda.bpm.engine.impl.bpmn.parser.FoxFailedJobParseListener;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.camunda.bpm.engine.impl.jobexecutor.FoxFailedJobCommandFactory;
import org.camunda.bpm.engine.impl.jobexecutor.JobExecutor;
import org.camunda.bpm.engine.impl.persistence.StrongUuidGenerator;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.repository.ProcessDefinition;

public class TenantManager {
  /**
   * This is configured in your Container (e.g. bpm-platform.xml in Tomcat)
   */
  private static final String jobAcquisitionName = "default";

  private static List<String> tenants = new ArrayList<String>();

  static {
    tenants.add("tenant1");
    tenants.add("tenant2");
    tenants.add("tenant3");
  }

  public List<String> getTenants() {
    return tenants;
  }

  public void startProcessEngines() {
    for (String tenant : tenants) {
      // startProcessEngineUsingStep(tenant);
      ProcessEngine processEngine = startProcessEngine(tenant);
      deployDefaultProcessesToEngine(processEngine);
    }

    System.out.println("\n\n\nStarted process engines for tenants - now running:\n" + BpmPlatform.getProcessEngineService().getProcessEngineNames() + "\n\n");
  }

  public void stopProcessEngines() {
    for (String tenant : tenants) {
      stopProcessEngine(tenant);
    }
  }

  private void stopProcessEngine(String tenant) {
    getServiceContainer().stopService(ServiceTypes.PROCESS_ENGINE, tenant);
  }

  public void addTenant(String name) {
    tenants.add(name);
    ProcessEngine processEngine = startProcessEngine(name);
    deployDefaultProcessesToEngine(processEngine);

    System.out.println("\n\n\nStarted new process engine for tenants - now running:\n" + BpmPlatform.getProcessEngineService().getProcessEngineNames() + "\n\n");
  }

  public static MBeanServiceContainer getServiceContainer() {
    return ((JmxRuntimeContainerDelegate) RuntimeContainerDelegate.INSTANCE.get()).getServiceContainer();
  }

  // private void startProcessEngineUsingStep(String tenant) {
  // ProcessEngineXmlImpl processEngineXmlImpl = new ProcessEngineXmlImpl();
  // processEngineXmlImpl.setJobAcquisitionName("default");
  // processEngineXmlImpl.setName(tenant);
  // processEngineXmlImpl.setDefault(false);
  // processEngineXmlImpl.setConfigurationClass(StandaloneProcessEngineConfiguration.class.getName());
  // processEngineXmlImpl.setDatasource("jdbc/ProcessEngine-" + tenant);
  // /**
  // * Todo - add:
  // *
  // * <properties> <property name="history">full</property> <property
  // * name="databaseSchemaUpdate">true</property> <property
  // * name="authorizationEnabled">true</property> <property
  // * name="jobExecutorDeploymentAware">true</property> </properties>
  // *
  // *
  // * <plugins> <!-- plugin enabling Process Application event listener support
  // * --> <plugin> <class>org.camunda.bpm.application.impl.event.
  // * ProcessApplicationEventListenerPlugin</class> </plugin> </plugins>
  // */
  // processEngineXmlImpl.setProperties(new HashMap<String, String>());
  // processEngineXmlImpl.setPlugins(new ArrayList<ProcessEnginePluginXml>());
  //
  // ((JmxRuntimeContainerDelegate)
  // RuntimeContainerDelegate.INSTANCE.get()).getServiceContainer() //
  // .createDeploymentOperation("deploy tenant process engine into the container")
  // //
  // .addStep(new StartProcessEngineStep(processEngineXmlImpl)) //
  // .execute();
  // }

  private ProcessEngine startProcessEngine(String tenant) {
    ProcessEngineConfigurationImpl configuration = new StandaloneProcessEngineConfiguration();
    configuration.setIdGenerator(new StrongUuidGenerator());

    configureCustomRetryStrategy(configuration);

    configuration.setProcessEngineName(tenant);

    configuration.setJdbcDriver("org.h2.Driver");
    configuration.setJdbcUrl("jdbc:h2:./camunda-h2-dbs/process-engine-" + tenant + ";MVCC=TRUE;TRACE_LEVEL_FILE=0;DB_CLOSE_ON_EXIT=FALSE");
    configuration.setDatabaseSchemaUpdate(StandaloneProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    // configuration.setDataSourceJndiName("jdbc/ProcessEngine-"+tenant);
    configuration.setJobExecutorDeploymentAware(true);
    configuration.setHistory(StandaloneProcessEngineConfiguration.HISTORY_FULL);

    // instantiate plugins:
    // * <plugins> <!-- plugin enabling Process Application event listener
    // support
    // * --> <plugin> <class>org.camunda.bpm.application.impl.event.
    // * ProcessApplicationEventListenerPlugin</class> </plugin> </plugins>
    // */
    // configurePlugins(configuration, processEngineXml, classLoader);

    JobExecutor jobExecutor = getServiceContainer().getServiceValue(ServiceTypes.JOB_EXECUTOR, jobAcquisitionName);
    if (jobExecutor == null) {
      throw new ProcessEngineException("Cannot find referenced job executor with name '" + jobAcquisitionName + "'");
    }

    // set JobExecutor on process engine
    configuration.setJobExecutor(jobExecutor);

    ProcessEngine processEngine = configuration.buildProcessEngine();

    // start the process engine inside the container.
    RuntimeContainerDelegate.INSTANCE.get().registerProcessEngine(processEngine);

    return processEngine;
  }

  protected void configureCustomRetryStrategy(ProcessEngineConfigurationImpl configurationImpl) {
    List<BpmnParseListener> customPostBPMNParseListeners = configurationImpl.getCustomPostBPMNParseListeners();
    if (customPostBPMNParseListeners == null) {
      customPostBPMNParseListeners = new ArrayList<BpmnParseListener>();
      configurationImpl.setCustomPostBPMNParseListeners(customPostBPMNParseListeners);
    }
    customPostBPMNParseListeners.add(new FoxFailedJobParseListener());
    configurationImpl.setFailedJobCommandFactory(new FoxFailedJobCommandFactory());
  }

  public static void deployDefaultProcessesToEngine(ProcessEngine processEngine) {
    ProcessEngine defaultProcessEngine = BpmPlatform.getDefaultProcessEngine();
    ProcessEngineConfigurationImpl defaultProcessEngineConfiguration = ((ProcessEngineImpl) defaultProcessEngine).getProcessEngineConfiguration();
    ProcessApplicationManager defaultProcessApplicationManager = defaultProcessEngineConfiguration.getProcessApplicationManager();

    Map<String, DeploymentBuilder> deployments = new HashMap<String, DeploymentBuilder>();

    List<ProcessDefinition> processDefinitions = defaultProcessEngine.getRepositoryService().createProcessDefinitionQuery().list();
    for (ProcessDefinition processDefinition : processDefinitions) {
      String deploymentId = processDefinition.getDeploymentId();

      if (!deployments.containsKey(deploymentId)) {
        deployments.put(deploymentId, processEngine.getRepositoryService().createDeployment());
      }

      deployments.get(deploymentId).addInputStream(//
          processDefinition.getResourceName(), //
          defaultProcessEngine.getRepositoryService().getResourceAsStream(deploymentId, processDefinition.getResourceName()));
    }

    for (Entry<String, DeploymentBuilder> entry : deployments.entrySet()) {
      // do the deployment
      Deployment deployment = entry.getValue().enableDuplicateFiltering().deploy();

      // and registration
      String defaultExistingDeploymentId = entry.getKey();
      String newDeploymentId = deployment.getId();

      ProcessApplicationReference processApplication = defaultProcessApplicationManager.getProcessApplicationForDeployment(defaultExistingDeploymentId);
      if (processApplication != null) {
        processEngine.getManagementService().registerProcessApplication(newDeploymentId, processApplication);
      } else {
        // no Process Application is deployed - ignore
      }

      // TODO: Resume old versions!
    }

  }

}


package org.camunda.bpm.engine.cdi.impl.context;

import java.util.HashMap;
import java.util.Map;

import javax.enterprise.context.Conversation;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Specializes;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.portlet.PortletSession;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.cdi.ProcessEngineCdiException;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.runtime.Execution;
import org.camunda.bpm.engine.task.Task;

/**
 * {@link ContextAssociationManager} which stores the association in the
 * {@link PortletSession} as workaround to problems with CDI
 * {@link Conversation}s
 * (http://www.liferay.com/community/forums/-/message_boards/message/27323345).
 *
 * I experimented to use {@link SessionScoped} in order to store the association
 * - but this causes class loading problems on hot redeployment if objects are
 * still in the session with old classes.
 *
 * It can be influenced by an attribute in the {@link PortletSession} set by
 * another portlet as workaround to not use IPC because of problems
 * (http://www.liferay.com/community/forums/-/message_boards/message/27267640).
 *
 * @author ruecker
 */
@Specializes
public class PortalContextAssociationManager extends DefaultContextAssociationManager {

  private static final long serialVersionUID = 1L;

  public static final String BRIDGE_TASK_ID = "camunda.bridge.selected.task.id";
  public static final String BRIDGE_PROCESS_DEFINITION_ID = "camunda.bridge.selected.processdefinition.id";

  public static final String ASSOCIATED_TASK_ID = "camunda.business.process.associated.task.id";
  public static final String ASSOCIATED_EXECUTION_ID = "camunda.business.process.associated.execution.id";

  public static final String VARIABLE_CACHE = "camunda.business.process.variable.cache";

  @Inject
  private transient ProcessEngine processEngine;

  public static Object getSharedSessionAttribute(String key) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    PortletSession portletSession = (PortletSession) externalContext.getSession(false);
    return portletSession.getAttribute(key, PortletSession.APPLICATION_SCOPE);
  }

  public static void setSharedSessionAttribute(String key, Object value) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    PortletSession portletSession = (PortletSession) externalContext.getSession(false);
    portletSession.setAttribute(key, value, PortletSession.APPLICATION_SCOPE);
  }

  @Override
  public void setExecution(Execution execution) {
    if (isTriggeredWithinEngine()) {
      super.setExecution(execution);
      return;
    }
    setSharedSessionAttribute(ASSOCIATED_EXECUTION_ID, execution.getId());
  }

  @Override
  public void disAssociate() {
    if (isTriggeredWithinEngine()) {
      super.disAssociate();
      return;
    }

    setSharedSessionAttribute(ASSOCIATED_TASK_ID, null);
    setSharedSessionAttribute(ASSOCIATED_EXECUTION_ID, null);
    setSharedSessionAttribute(VARIABLE_CACHE, null);

    // TODO: really do this?
    setSharedSessionAttribute(BRIDGE_TASK_ID, null);
  }

  @Override
  public Execution getExecution() {
    if (isTriggeredWithinEngine()) {
      return super.getExecution();
    }
    checkTaskSelectedViaBridge();
    ExecutionEntity execution = getExecutionFromContext();
    if (execution != null) {
      return execution;
    } else {
      checkTaskSelectedViaBridge();
      return loadExecution();
    }
  }

  @Override
  public Object getVariable(String variableName) {
    if (isTriggeredWithinEngine()) {
      return super.getVariable(variableName);
    }

    checkTaskSelectedViaBridge();
    ExecutionEntity execution = getExecutionFromContext();
    if (execution != null) {
      return execution.getVariable(variableName);
    } else {
      // load from execution and store it in cache (if not yet there)
      Object value = getCachedVariables().get(variableName);
      if (value == null) {
        Execution e = getExecution();
        if (e != null) {
          value = processEngine.getRuntimeService().getVariable(e.getId(), variableName);
          getCachedVariables().put(variableName, value);
        }
      }
      return value;
    }
  }

  @Override
  public void setVariable(String variableName, Object value) {
    if (isTriggeredWithinEngine()) {
      super.setVariable(variableName, value);
      return;
    }

    checkTaskSelectedViaBridge();
    ExecutionEntity execution = getExecutionFromContext();
    if (execution != null) {
      execution.setVariable(variableName, value);
      execution.getVariable(variableName);
    } else {
      getCachedVariables().put(variableName, value);
    }
  }

  @Override
  public Task getTask() {
    if (isTriggeredWithinEngine()) {
      return super.getTask();
    }
    checkTaskSelectedViaBridge();
    return loadTask();
  }

  @Override
  public void setTask(Task task) {
    if (isTriggeredWithinEngine()) {
      super.setTask(task);
      return;
    }

    setSharedSessionAttribute(ASSOCIATED_TASK_ID, task.getId());
  }

  private boolean isTriggeredWithinEngine() {
    return (Context.getCommandContext() != null);
  }

  /**
   * "lazy" load task if bridge state has changed in the meantime
   */
  private void checkTaskSelectedViaBridge() {
    String bridgeTaskId = (String) getSharedSessionAttribute(BRIDGE_TASK_ID);
    String selectedTaskId = (String) getSharedSessionAttribute(ASSOCIATED_TASK_ID);

    if (selectedTaskId == null && bridgeTaskId != null) {
      switchTaskId(bridgeTaskId);
    }
    if (selectedTaskId != null && bridgeTaskId != null && !selectedTaskId.equals(bridgeTaskId)) {
      // task switched, TODO: think about if correct like this
      switchTaskId(bridgeTaskId);
    }
  }

  private Task loadTask() {
    String taskId = (String) getSharedSessionAttribute(ASSOCIATED_TASK_ID);
    if (taskId == null) {
      return null;
    }
    Task task = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
      throw new ProcessEngineCdiException("Task with id '" + taskId + "' does not exist.");
    }
    return task;
  }

  private Execution loadExecution() {
    String executionId = (String) getSharedSessionAttribute(ASSOCIATED_EXECUTION_ID);
    if (executionId == null) {
      return null;
    }
    Execution execution = processEngine.getRuntimeService().createExecutionQuery().executionId(executionId).singleResult();
    if (execution == null) {
      // we owe you a beer if this will ever happen!
      throw new ProcessEngineCdiException("Execution with id '" + executionId + "' does not exist.");
    }
    return execution;
  }

  private void switchTaskId(String taskId) {
    Task task = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
      throw new ProcessEngineCdiException("Task with id '" + taskId + "' does not exist.");
    }
    setSharedSessionAttribute(ASSOCIATED_TASK_ID, taskId);
    setSharedSessionAttribute(ASSOCIATED_EXECUTION_ID, task.getExecutionId());

    // evict cached variables
    setSharedSessionAttribute(VARIABLE_CACHE, null);

    // reset switch
    setSharedSessionAttribute(BRIDGE_TASK_ID, null);
  }

  @Override
  public Map<String, Object> getCachedVariables() {
    if (isTriggeredWithinEngine()) {
      return super.getCachedVariables();
    }

    Map<String, Object> cachedVariables = (Map<String, Object>) getSharedSessionAttribute(VARIABLE_CACHE);
    if (cachedVariables == null) {
      cachedVariables = new HashMap<String, Object>();
      setSharedSessionAttribute(VARIABLE_CACHE, cachedVariables);
    }
    return cachedVariables;
  }
}


package org.camunda.demo.interpocesscommunication.ws;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.jws.WebService;

import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.task.Task;

@WebService(name = "ProcessInvocationService")
public class ProcessInvocation {

  public static final String CALLBACK_URL = "callbackURL";
  public static final String CALLBACK_CORRELATION_ID = "callbackCorrelationId";
  public static final String PAYLOAD = "payload";

  @Inject
  private RuntimeService runtimeService;

  @Inject
  private TaskService taskService;

  public void invokeProcess(String processDefinitionKey, String callbackUrl, String correlationId, String payload) {
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put(CALLBACK_URL, callbackUrl);
    variables.put(CALLBACK_CORRELATION_ID, correlationId);
    variables.put(PAYLOAD, payload);

    runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
  }

  // TaskDto
  public List<String> getTaskList(List<String> correlationIds) {
    ArrayList<String> tasks = new ArrayList<String>();
    // Better than the loop would be to introduce an own query doing this in one SQL, see
    // https://app.camunda.com/confluence/display/foxUserGuide/Performance+Tuning+with+custom+Queries
    for (String id : correlationIds) {
      List<Task> tasksForCorrelationId = taskService.createTaskQuery().processVariableValueEquals(CALLBACK_CORRELATION_ID, id).list();
      for (Task task : tasksForCorrelationId) {
        tasks.add(task.getName());
                //new TaskDto(task.getName(), task.getDescription(), task.getAssignee(), task.getId(), task.getProcessInstanceId(), task.getExecutionId(), task.getProcessDefinitionId()));
      }
    }
    return tasks;
  }

}


package org.example.get_servlet_context_by_process_definition;

import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.ProcessApplicationService;
import org.camunda.bpm.ProcessEngineService;
import org.camunda.bpm.application.ProcessApplicationDeploymentInfo;
import org.camunda.bpm.application.ProcessApplicationInfo;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.repository.ProcessDefinition;

/**
 * Helper class for retrieving the servlet context path of a process application.
 *
 * @author Falko Menge (camunda)
 */
public class ProcessApplicationHelper {

	/**
	 * Retrieve the servlet context path of a process definition from a known process engine.
	 */
	public static String getServletContextPath(
			ProcessEngine processEngine, String processDefinitionId) {

		return getServletContextPath(getProcessApplicationInfo(processEngine, processDefinitionId));
	}

	/**
	 * Retrieve the servlet context path of a process definition from any process engine.
	 */
	public static String getServletContextPath(String processDefinitionId) {
		ProcessApplicationInfo processApplicationInfo = getProcessApplicationInfo(processDefinitionId);
		if (processApplicationInfo == null) {
			return null;
		}
		return processApplicationInfo.getProperties().get(
				ProcessApplicationInfo.PROP_SERVLET_CONTEXT_PATH);
	}

	/**
	 * Retrieve the servlet context path of a given process application.
	 */
	public static String getServletContextPath(ProcessApplicationInfo processApplicationInfo) {
		if (processApplicationInfo == null) {
			return null;
		}
		return processApplicationInfo.getProperties().get(ProcessApplicationInfo.PROP_SERVLET_CONTEXT_PATH);
	}

	/**
	 * Retrieve the application info of a process definition from a known process engine.
	 */
	public static ProcessApplicationInfo getProcessApplicationInfo(
			ProcessEngine processEngine, String processDefinitionId) {
		ProcessDefinition processDefinition = processEngine.getRepositoryService().getProcessDefinition(processDefinitionId);

		// get the name of the process application that made the deployment
		String processApplicationName = processEngine.getManagementService()
				.getProcessApplicationForDeployment(processDefinition.getDeploymentId());

		if (processApplicationName == null) {
			// not a process application deployment
			return null;
		} else {
			ProcessApplicationService processApplicationService = BpmPlatform.getProcessApplicationService();
			return processApplicationService.getProcessApplicationInfo(processApplicationName);
		}
	}

	/**
	 * Retrieve the application info path of a process definition from any process engine.
	 */
	public static ProcessApplicationInfo getProcessApplicationInfo(String processDefinitionId) {
		ProcessEngineService processEngineService = BpmPlatform.getProcessEngineService();
		ProcessApplicationService processAppService = BpmPlatform.getProcessApplicationService();
		// iterate over all process applications
		for (String appName : processAppService.getProcessApplicationNames()) {
			ProcessApplicationInfo appInfo = processAppService
					.getProcessApplicationInfo(appName);
			// iterate over all deployments of a process application
			for (ProcessApplicationDeploymentInfo deploymentInfo : appInfo
					.getDeploymentInfo()) {
				long count = processEngineService
						.getProcessEngine(deploymentInfo.getProcessEngineName())
						.getRepositoryService().createProcessDefinitionQuery()
						.deploymentId(deploymentInfo.getDeploymentId())
						.processDefinitionId(processDefinitionId).count();
				if (count > 0) {
					return appInfo;
				}
			}
		}
		return null;
	}

}


package org.camunda.bpm.demo.orderconfirmation.config;

import org.camunda.bpm.demo.orderconfirmation.bean.RuleEntryDAO;
import org.camunda.bpm.demo.orderconfirmation.model.DiscountRuleEntry;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;
import java.util.List;
import java.util.logging.Logger;

/*
 * Helper class to create an initial set of discount rules
 */
@Singleton
@Startup
public class DiscountRuleEntryConfig {

  private final static Logger log = Logger.getLogger(DiscountRuleEntryConfig.class.getCanonicalName());

  @Inject
  private RuleEntryDAO rulesDAO;

  /*
   * If no discount rules are present in the database, we create some initial ones
   */
  @PostConstruct
  public void initializeDiscountRules() {
    List<DiscountRuleEntry> rules = rulesDAO.findAllDiscountRuleEntries();
    if ((rules == null) || (rules.size() == 0)) {
      log.info("Creating initial sample discount rules: ...");
      rulesDAO.save(new DiscountRuleEntry("Small orders", 0, 500, 5));
      rulesDAO.save(new DiscountRuleEntry("Medium orders", 500, 1000, 7));
      rulesDAO.save(new DiscountRuleEntry("Big orders", 1000, 5000, 10));
    }
  }
}


/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.camunda.bpm.example.invoice;

import static org.camunda.bpm.engine.variable.Variables.createVariables;
import static org.camunda.bpm.engine.variable.Variables.fileValue;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Calendar;

import org.camunda.bpm.BpmPlatform;
import org.camunda.bpm.application.PostDeploy;
import org.camunda.bpm.application.ProcessApplication;
import org.camunda.bpm.application.impl.ServletProcessApplication;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.authorization.Groups;
import org.camunda.bpm.engine.impl.util.ClockUtil;
import org.camunda.bpm.engine.impl.util.IoUtil;
import org.camunda.bpm.engine.repository.DeploymentBuilder;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinitionQuery;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;

/**
 * Process Application exposing this application's resources the process engine.
 */
@ProcessApplication
public class InvoiceProcessApplication extends ServletProcessApplication {

  /**
   * In a @PostDeploy Hook you can interact with the process engine and access
   * the processes the application has deployed.
   */
  @PostDeploy
  public void startFirstProcess(ProcessEngine processEngine) {
	processEngine = BpmPlatform.getProcessEngineService().getProcessEngine("anders");

    createUsers(processEngine);
    startProcessInstances(processEngine, "invoice", 1);
    startProcessInstances(processEngine, "invoice", null);
    for (int i=0; i<1000; i++) {
    	startProcessInstances(processEngine, "invoice", null);
    }
  }

  @Override
  public void createDeployment(String processArchiveName, DeploymentBuilder deploymentBuilder) {
    ProcessEngine processEngine = BpmPlatform.getProcessEngineService().getProcessEngine("anders");

    // Hack: deploy the first version of the invoice process once before the process application
    //   is deployed the first time
    if (processEngine != null) {

      RepositoryService repositoryService = processEngine.getRepositoryService();

      if (!isProcessDeployed(repositoryService, "invoice")) {
        ClassLoader classLoader = getProcessApplicationClassloader();

        repositoryService.createDeployment(this.getReference())
          .addInputStream("invoice.v1.bpmn", classLoader.getResourceAsStream("invoice.v1.bpmn"))
          .addInputStream("assign-approver-groups.dmn", classLoader.getResourceAsStream("assign-approver-groups.dmn"))
          .deploy();
      }
    }
  }

  protected boolean isProcessDeployed(RepositoryService repositoryService, String key) {
    return repositoryService.createProcessDefinitionQuery().processDefinitionKey("invoice").count() > 0;
  }

  private void startProcessInstances(ProcessEngine processEngine, String processDefinitionKey, Integer version) {

    ProcessDefinitionQuery processDefinitionQuery = processEngine
      .getRepositoryService()
      .createProcessDefinitionQuery()
      .processDefinitionKey(processDefinitionKey);

    if (version != null) {
      processDefinitionQuery.processDefinitionVersion(version);
    }
    else {
      processDefinitionQuery.latestVersion();
    }

    ProcessDefinition processDefinition = processDefinitionQuery.singleResult();

    InputStream invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

    // process instance 1
    processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
        .putValue("creditor", "Great Pizza for Everyone Inc.")
        .putValue("amount", 30.00d)
        .putValue("invoiceCategory", "Travel Expenses")
        .putValue("invoiceNumber", "GPFE-23232323")
        .putValue("invoiceDocument", fileValue("invoice.pdf")
            .file(invoiceInputStream)
            .mimeType("application/pdf")
            .create()));

    IoUtil.closeSilently(invoiceInputStream);
    invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

    // process instance 2
    try {
      Calendar calendar = Calendar.getInstance();
      calendar.add(Calendar.DAY_OF_MONTH, -14);
      ClockUtil.setCurrentTime(calendar.getTime());

      ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
          .putValue("creditor", "Bobby's Office Supplies")
          .putValue("amount", 900.00d)
          .putValue("invoiceCategory", "Misc")
          .putValue("invoiceNumber", "BOS-43934")
          .putValue("invoiceDocument", fileValue("invoice.pdf")
              .file(invoiceInputStream)
              .mimeType("application/pdf")
              .create()));

      calendar.add(Calendar.DAY_OF_MONTH, 14);
      ClockUtil.setCurrentTime(calendar.getTime());

      processEngine.getIdentityService().setAuthentication("demo", Arrays.asList(Groups.CAMUNDA_ADMIN));
      Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).singleResult();
      processEngine.getTaskService().claim(task.getId(), "demo");
      processEngine.getTaskService().complete(task.getId(), createVariables().putValue("approved", true));
    }
    finally{
      ClockUtil.reset();
      processEngine.getIdentityService().clearAuthentication();
    }

    IoUtil.closeSilently(invoiceInputStream);
    invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

    // process instance 3
    try {
      Calendar calendar = Calendar.getInstance();
      calendar.add(Calendar.DAY_OF_MONTH, -5);
      ClockUtil.setCurrentTime(calendar.getTime());

      ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
          .putValue("creditor", "Papa Steve's all you can eat")
          .putValue("amount", 10.99d)
          .putValue("invoiceCategory", "Travel Expenses")
          .putValue("invoiceNumber", "PSACE-5342")
          .putValue("invoiceDocument", fileValue("invoice.pdf")
              .file(invoiceInputStream)
              .mimeType("application/pdf")
              .create()));

      calendar.add(Calendar.DAY_OF_MONTH, 5);
      ClockUtil.setCurrentTime(calendar.getTime());

      processEngine.getIdentityService().setAuthenticatedUserId("mary");
      Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(pi.getId()).singleResult();
      processEngine.getTaskService().createComment(null, pi.getId(), "I cannot approve this invoice: the amount is missing.\n\n Could you please provide the amount?");
      processEngine.getTaskService().complete(task.getId(), createVariables().putValue("approved", false));
    }
    finally{
      ClockUtil.reset();
      processEngine.getIdentityService().clearAuthentication();
    }

    try {
    	invoiceInputStream = InvoiceProcessApplication.class.getClassLoader().getResourceAsStream("invoice.pdf");

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -5);
        ClockUtil.setCurrentTime(calendar.getTime());

        ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceById(processDefinition.getId(), createVariables()
            .putValue("creditor", "Food at the dinner")
            .putValue("amount", 55.99d)
            .putValue("invoiceCategory", "Travel Expenses")
            .putValue("invoiceNumber", "PSACE-9876")
            .putValue("invoiceDocument", fileValue("invoice.pdf")
                .file(invoiceInputStream)
                .mimeType("application/pdf")
                .create()));

        calendar.add(Calendar.DAY_OF_MONTH, 5);
        ClockUtil.setCurrentTime(calendar.getTime());

        processEngine.getIdentityService().setAuthenticatedUserId("mary");
    } finally {
    	ClockUtil.reset();
        processEngine.getIdentityService().clearAuthentication();
    }
  }

  private void createUsers(ProcessEngine processEngine) {

    // create demo users
    new DemoDataGenerator().createUsers(processEngine);
  }
}


package com.camunda.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig {

    // This is just a very simple Identity Management solution for demo purposes.
    // In real world scenarios, this would be replaced by the actual IAM solution
    @SuppressWarnings("deprecation")
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withDefaultPasswordEncoder().username("demo").password("demo").roles("ACTUATOR", "camunda-admin").build());
        manager.createUser(User.withDefaultPasswordEncoder().username("john").password("john").roles("camunda-user").build());
        return manager;
    }

}


package org.camunda.consulting.patterns.data.adapter;

import java.io.Serializable;
import java.util.Map;

/**
 * Adapter interface for get/set Variables. Use to hide concrete implementation.
 *
 * @author Jan Galinski, Holisticon AG
 */
public abstract class AbstractProcessVariableAdapter {

  /**
   * Type- and null-safe cast of variable-value.
   */
  @SuppressWarnings("unchecked")
  public static final <T extends Serializable> T castValue(final Object value) {
    return value != null ? (T) value : null;
  }

  /**
   * Retrieve variable value from adapter.
   */
  public abstract <T extends Serializable> T getVariable(String name);

  /**
   * Sets value for variable on adapter.
   */
  public abstract <T extends Serializable> void setVariable(String name, T value);

  public abstract Map<String, Object> getVariablesMap();

}


package org.camunda.demo.camel;

import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.inject.Inject;

import org.apache.camel.cdi.CdiCamelContext;
import org.apache.camel.component.seda.SedaComponent;
import org.camunda.bpm.camel.component.CamundaBpmComponent;
import org.camunda.bpm.engine.ProcessEngine;

/**
 * This class takes care of bootstrapping the camel context in a CDI
 * environment. For documentation of the camel-cdi component check out the
 * project page at http://camel.apache.org/cdi.html and the Camel CDI BootStrap
 * project at https://github.com/cmoulliard/cdi-camel-example/
 *
 */
@Singleton
@Startup
public class CamelBootStrap {

	private final static Logger log = Logger.getLogger(CamelBootStrap.class.getCanonicalName());

	@Inject
	private CdiCamelContext cdiCamelContext;

  @Inject
  private ProcessEngine processEngine;

	@Inject
	private OpenAccountRouteBuilder openAccountRoute;

	// For simplicity JMS was removed from the example - but you can easily re-add it
//	@Resource(mappedName = "java:/JmsXA")
//	private QueueConnectionFactory queueConnectionFactory;

	@PostConstruct
	public void init() throws Exception {
    log.info("=======================");
    log.info("Adding camunda BPM Component to Camel");
    log.info("=======================");

	  CamundaBpmComponent component = new CamundaBpmComponent(processEngine);
    component.setCamelContext(cdiCamelContext);
    cdiCamelContext.addComponent("camunda-bpm", component); // TODO: could be done by META-INF/service as well- maybe switch?

    // For simplicity JMS was removed from the example - but you can easily re-add it:
		// inject the JMS connection factory into camel's JMS component
//		JmsComponent jmsComponent = cdiCamelContext.getComponent("jms", JmsComponent.class);
//		jmsComponent.setConnectionFactory(queueConnectionFactory);

    // Instead we exchanged the JMS component by replacing it with Camel seda component for in memory queues
    cdiCamelContext.addComponent("jms", cdiCamelContext.getComponent("seda", SedaComponent.class));

		// add routes to camel context
		log.info("=======================");
		log.info("adding OpenAccountRoute to camel context");
		log.info("=======================");
		cdiCamelContext.addRoutes(openAccountRoute);
		log.info("=======================");
		log.info("Camel Components: " + cdiCamelContext.getComponentNames());
		log.info("=======================");
		log.info("=======================");
		log.info("starting camel context");
		log.info("=======================");
		// cdiCamelContext.setTracing(true);
		cdiCamelContext.start();
		log.info("=======================");
		log.info("successfully created camel context and started open account route!");
		log.info("=======================");
	}

	@PreDestroy
	public void shutDown() throws Exception {
		log.info("=======================");
		log.info("Shutting down camel context");
		log.info("=======================");
		cdiCamelContext.stop();
		log.info("=======================");
		log.info("Successfully shut down camel context");
		log.info("=======================");
	}

}


package com.camunda.consulting;

import org.camunda.bpm.dmn.engine.DmnDecision;
import org.camunda.bpm.dmn.engine.DmnDecisionTableResult;
import org.camunda.bpm.dmn.engine.DmnEngine;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.impl.persistence.deploy.DeploymentCache;
import org.camunda.bpm.engine.variable.context.VariableContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DecisionTableEvaluator {

	private final static Logger LOG = LoggerFactory.getLogger(DecisionTableEvaluator.class);

	public static Object singleResult(String decisionKey, VariableContext variables) {
		return evaluate(decisionKey, variables).getFirstResult().getSingleEntry();
	}

	/**
	 * ${evaluateDecision(decisionKey, variableContext).getFirstResult().get(resultVariableName)}
	 */
	public static DmnDecisionTableResult evaluate(String decisionKey, VariableContext variables) {
//		ProcessEngineImpl processEngine = Context.getProcessEngineConfiguration().getProcessEngine();
		// Do it "the internal way" to be able to use VariableContext directly
		final DmnEngine dmnEngine = Context.getProcessEngineConfiguration().getDmnEngine();
		DeploymentCache deploymentCache = Context.getProcessEngineConfiguration().getDeploymentCache();
		DmnDecision decisionDefinition = (DmnDecision) deploymentCache.findDeployedLatestDecisionDefinitionByKey(decisionKey);
		LOG.info("Evaluate chained decision: {} ", decisionDefinition);
		return dmnEngine.evaluateDecisionTable(decisionDefinition, variables);
	}

}


package org.camunda.bpm.demo.orderconfirmation.bean;

import java.io.Serializable;
import java.util.List;

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;

/**
 * This is an abstract base class for building view-centric lists.
 *
 * It supports paging and sorting, the parameters for which are held as conversational state.
 *
 * @author meyerd
 */
// This is not an EJB, as no transactions are needed
@ConversationScoped
public abstract class AbstractEntityList<T> implements Serializable {

  private static final long serialVersionUID = 1L;

  @PersistenceContext
  private EntityManager entityManager;

  @Inject
  private Conversation conversation;

  // paging
  protected int pageNumber = 0;
  protected int pageSize = 10;
  // sorting
  protected String sortColumn;
  protected boolean sortAsc = true;

  protected List<T> list;

  public List<T> getList() {
    if(list==null) {
      loadList();
    }
    return list;
  }

  public void clearList() {
    list = null;
  }

  protected abstract Class<T> getEntityType();

  protected void loadList() {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> query = createQuery(cb);

    // retrieval of the list + paging
    list = entityManager.createQuery(query)
        .setMaxResults(pageSize)
        .setFirstResult(getFirstResult())
        .getResultList();

    // this begins a unit of work:
    if(conversation.isTransient()) {
      conversation.begin();
    }
  }

  // this can be subclassed to add custom restrictions to the query / replace the query
  protected CriteriaQuery<T> createQuery(CriteriaBuilder cb) {
    CriteriaQuery<T> query = cb.createQuery(getEntityType());
    // building the base query: "select e from EntityType e"
    Root<T> e = query.from(getEntityType());
    query.select(e);

    // adding sort restrictions
    if(sortColumn != null) {
      Path<Object> sortField = e.get(sortColumn);
      if (sortAsc) {
        query.orderBy(cb.asc(sortField));
      } else {
        query.orderBy(cb.desc(sortField));
      }
    }
    return query;
  }

  // paging ////////////////////////////////////////

  protected int getFirstResult() {
    return pageNumber*pageSize;
  }

  public void nextPage() {
    pageNumber += 1;
    clearList();
  }

  public void prevPage() {
    if(pageNumber == 0) {
      return;
    }
    pageNumber -= 1;
    clearList();
  }

  public boolean isHasMore(){
    return getMaxResults() > (pageNumber * pageSize) + pageSize;
  }

  public int getMaxResults() {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cb.createQuery(Long.class);
    cq.select(cb.count(cq.from(getEntityType())));
    return entityManager.createQuery(cq).getSingleResult().intValue();
  }

  public boolean isHasLess(){
    return pageNumber>0;
  }

  // Sorting ///////////////////////////////////////

  public void setSortColumn(String sortColumn) {
    this.sortColumn = sortColumn;
    pageNumber = 0;
    sortAsc = !sortAsc;
    clearList();
  }

  public String getSortColumn() {
    return sortColumn;
  }

  public String getSortOrder() {
    return (sortAsc ? "ASC" : "DESC");
  }

}


package com.camunda.demo.outerspace.wjax.controller;

import java.util.List;

import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;

import org.camunda.bpm.engine.ProcessEngines;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.cdi.BusinessProcess;
import org.camunda.bpm.engine.impl.ProcessEngineImpl;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.task.Task;

import com.camunda.demo.outerspace.wjax.controller.performance.MyBatisQueryCommandExecutor;
import com.camunda.demo.outerspace.wjax.controller.performance.OrderProcessDTO;

public class TaskListController {

  @Inject
  private TaskService taskService;

  @Produces
  @Named("tasks")
  public List<Task> getTaskList() {
    return taskService.createTaskQuery()
      .processDefinitionKey("wjax2012-bestellprozess")
      .list();
  }

//  @EJB(lookup = ProcessArchiveSupport.PROCESS_ENGINE_SERVICE_NAME)
//  private ProcessEngineService processEngineService;

  /**
   * See https://app.camunda.com/confluence/display/foxUserGuide/Performance+Tuning+with+custom+Queries
   */
  @Produces
  @Named("orderProcesses")
  public List<OrderProcessDTO> getOrders() {
    ProcessEngineImpl processEngine = (ProcessEngineImpl) ProcessEngines.getDefaultProcessEngine();
    ProcessEngineConfigurationImpl processEngineConfiguration = processEngine.getProcessEngineConfiguration();

    MyBatisQueryCommandExecutor commandExecutor = new MyBatisQueryCommandExecutor(processEngineConfiguration, "customMappings.xml");
    return commandExecutor.executeQueryCommand(new Command<List<OrderProcessDTO>>() {

      @SuppressWarnings("unchecked")
      public List<OrderProcessDTO> execute(CommandContext commandContext) {
        return (List<OrderProcessDTO>) commandContext.getDbSqlSession().selectList("selectOrdersWithProcessInformation", null);
      }
    });
  }

  @Inject
  private BusinessProcess bp;

  @Produces
  @Named("otherAssignee")
  public String getOtherAssignee() {
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(bp.getProcessInstanceId()).list();
    for (Task task : tasks) {
      if (!task.getId().equals(bp.getTask())) {
        return task.getAssignee();
      }
    }
    return null;
  }
}


package org.camunda.consulting.patterns.guard;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.or;
import static java.lang.String.format;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.BooleanUtils;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.camunda.bpm.engine.delegate.TaskListener;

import com.google.common.base.Predicate;

/**
 * Guard support methods.
 *
 * @author Simon Zambrovski, Holisticon AG
 * @author Jan Galinski, Holisticon AG
 */
public final class Guards {

  /**
   * Defines global boolean Process-variable to disable guards.
   */
  public static final String VARIABLE_SKIP_GUARDS = "runtimeSkipGuards";

  /**
   * Pre-filled Map with skip guards parameter.
   */
  @SuppressWarnings("serial")
  public static final Map<String, Object> MAP_SKIP_GUARDS = new HashMap<String, Object>() {

    {
      put(VARIABLE_SKIP_GUARDS, Boolean.TRUE);
    }
  };
  static final String VARIABLE_NAME_MUST_BE_NOT_NULL = "Variable name must be not null";
  static final String CONDITION_VIOLATED = "Condition of task '%s' is violated: ";
  private static final Predicate<String> isPrecondition = or(equalTo(ExecutionListener.EVENTNAME_START), equalTo(TaskListener.EVENTNAME_CREATE));
  private static final Predicate<String> isPostcondition = or(equalTo(ExecutionListener.EVENTNAME_END), equalTo(TaskListener.EVENTNAME_COMPLETE));

  /**
   * Hide.
   */
  private Guards() {
    // hide instance.
  }

  /**
   * Decides whether to call {@link #checkPreconditions(DelegateExecution)} or
   * {@link #checkPostconditions(DelegateExecution)}.
   *
   * @param guard
   *          guard implementation.
   * @param eventName
   *          name of the event listened
   * @param execution
   *          the current execution
   */
  public static void dispatch(final Guard guard, final String eventName, final DelegateExecution execution) {
    // do nothing when disabled
    if (skipGuards(execution)) {
      return;
    }

    if (isPrecondition.apply(eventName)) {
      guard.checkPreconditions(execution);
    } else if (isPostcondition.apply(eventName)) {
      guard.checkPostconditions(execution);
    }
  }

  /**
   * Checks if guards should be skipped or not.
   *
   * @param execution
   *          the current execution holding variables
   * @return true if VARIABLE_SKIP_GUARDS is set,
   *         false else
   */
  public static boolean skipGuards(final DelegateExecution execution) {
    return BooleanUtils.toBoolean((Boolean) execution.getVariable(VARIABLE_SKIP_GUARDS));
  }

  /**
   * Checks if a local variable is set.
   *
   * @param execution
   *          current process execution
   * @param variableName
   *          name of the variable.
   */
  public static void checkIsSetLocal(final DelegateExecution execution, final String variableName) {
    checkArgument(variableName != null, VARIABLE_NAME_MUST_BE_NOT_NULL);

    final Object variableLocal = execution.getVariableLocal(variableName);
    checkState(variableLocal != null, format(CONDITION_VIOLATED + "Local variable '%s' is not set.", execution.getCurrentActivityId(), variableName));
  }

  /**
   * Checks if a variable is set.
   *
   * @param execution
   *          current process execution
   * @param variableName
   *          name of the variable.
   */
  public static void checkIsSet(final DelegateExecution execution, final String variableName) {
    checkArgument(variableName != null, VARIABLE_NAME_MUST_BE_NOT_NULL);

    final Object variableLocal = execution.getVariableLocal(variableName);
    final Object variable = execution.getVariable(variableName);

    checkState(variableLocal != null || variable != null,
        format(CONDITION_VIOLATED + "Variable '%s' is not set.", execution.getCurrentActivityId(), variableName));
  }

  /**
   * Checks if a global variable is set.
   *
   * @param execution
   *          current process execution
   * @param variableName
   *          name of the variable.
   */
  public static void checkIsSetGlobal(final DelegateExecution execution, final String variableName) {
    checkArgument(variableName != null, VARIABLE_NAME_MUST_BE_NOT_NULL);

    final Object variable = execution.getVariable(variableName);
    checkState(variable != null, format(CONDITION_VIOLATED + "Global variable '%s' is not set.", execution.getCurrentActivityId(), variableName));
  }

}


package com.camunda.demo.migration;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.delegate.Expression;
import org.camunda.bpm.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import org.camunda.bpm.engine.impl.bpmn.behavior.CallActivityBehavior;
import org.camunda.bpm.engine.impl.bpmn.parser.DataAssociation;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.pvm.PvmProcessInstance;
import org.camunda.bpm.engine.impl.pvm.delegate.ActivityExecution;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.impl.pvm.runtime.ProcessInstanceStartContext;

public class MigrationEnabledCallActivityBehavior extends CallActivityBehavior {

  // NEW
  private Expression migrationScenarioExpression;

  // copied (because of limited visibility)
  private List<DataAssociation> copy_dataInputAssociations = new ArrayList<DataAssociation>();
  private List<DataAssociation> copy_dataOutputAssociations = new ArrayList<DataAssociation>();
  private Expression copy_processDefinitionExpression;

  public MigrationEnabledCallActivityBehavior(CallActivityBehavior behavior) {
    // create a new behavior
    super((String) null);

    // now copy all existing attributes - due to limited visibility do it the
    // hard way:
    copyProperty("processDefinitionKey", CallActivityBehavior.class, behavior, this, false);
    copyProperty("binding", CallActivityBehavior.class, behavior,this, false);
    copyProperty("version", CallActivityBehavior.class, behavior,this, false);
    copyProperty("dataInputAssociations", CallActivityBehavior.class, behavior,this, true);
    copyProperty("dataOutputAssociations", CallActivityBehavior.class, behavior,this, true);
    copyProperty("processDefinitionExpression", CallActivityBehavior.class, behavior,this, true);
    copyProperty("multiInstanceActivityBehavior", AbstractBpmnActivityBehavior.class, behavior, this, false);
  }

  public void addMigrationScenarioExpression(Expression expression) {
    this.migrationScenarioExpression = expression;
  }

  /**
   * copied from CallActivityBehavior
   */
  @Override
  public void execute(ActivityExecution execution) throws Exception {
    String processDefinitionKey = this.processDefinitionKey;
    String binding = this.binding;
    Integer version = this.version;
    if (copy_processDefinitionExpression != null) {
      processDefinitionKey = (String) copy_processDefinitionExpression.getValue(execution);
    }

    ProcessDefinitionEntity processDefinition = null;
    if (binding == null || CalledElementBinding.LATEST.getValue().equals(binding)) {
      processDefinition = Context.getProcessEngineConfiguration().getDeploymentCache().findDeployedLatestProcessDefinitionByKey(processDefinitionKey);
    } else if (binding != null && CalledElementBinding.DEPLOYMENT.getValue().equals(binding)) {
      processDefinition = Context
          .getProcessEngineConfiguration()
          .getDeploymentCache()
          .findDeployedProcessDefinitionByDeploymentAndKey(Context.getExecutionContext().getExecution().getProcessDefinition().getDeploymentId(),
              processDefinitionKey);
    } else if (binding != null && CalledElementBinding.VERSION.getValue().equals(binding) && version != null) {
      processDefinition = Context.getProcessEngineConfiguration().getDeploymentCache()
          .findDeployedProcessDefinitionByKeyAndVersion(processDefinitionKey, version);
    }

    // copy process variables / businessKey
    String businessKey = null;
    Map<String, Object> callActivityVariables = new HashMap<String, Object>();

    for (DataAssociation dataInputAssociation : copy_dataInputAssociations) {
      Object value = null;

      if (dataInputAssociation.getBusinessKeyExpression() != null) {
        businessKey = (String) dataInputAssociation.getBusinessKeyExpression().getValue(execution);
      } else if (dataInputAssociation.getVariables() != null) {
        Map<String, Object> variables = execution.getVariables();
        if (variables != null && !variables.isEmpty()) {
          Set<String> variableKeys = variables.keySet();
          for (String variableKey : variableKeys) {
            callActivityVariables.put(variableKey, variables.get(variableKey));
          }
        }
      } else if (dataInputAssociation.getSourceExpression() != null) {
        value = dataInputAssociation.getSourceExpression().getValue(execution);
      } else {
        value = execution.getVariable(dataInputAssociation.getSource());
      }

      if (value != null) {
        callActivityVariables.put(dataInputAssociation.getTarget(), value);
      }
    }

    // UNCHANGED TILL HERE!

    // now we create the process instance on a different activity steered by the expression:
    String migrationScenario = null;
    try {
      migrationScenario = (String) migrationScenarioExpression.getValue(execution);
    }
    catch (ProcessEngineException ex) {
      // might be the case if the process run in "normal" mode and some variables have not be passed id
    }

    if (migrationScenario==null) {
      // normal behavior
      PvmProcessInstance subProcessInstance = execution.createSubProcessInstance(processDefinition, businessKey);
      subProcessInstance.start(callActivityVariables);
    }
    else {
      // now there are two possibilities:
      // 1. The process contains a matching Message Start Event
      // 2. The process contains a matching intermediate event
      ActivityImpl startActivity = processDefinition.findActivity(migrationScenario);

      ExecutionEntity subProcessInstance = (ExecutionEntity) processDefinition.createProcessInstance(businessKey, startActivity);

      // add hierarchy for the sub process instance
      subProcessInstance.setSuperExecution((ExecutionEntity)execution);
      ((ExecutionEntity)execution).setSubProcessInstance(subProcessInstance);

      if (subProcessInstance.getExecutions().size()==1) {
        healExecution(subProcessInstance, subProcessInstance.getExecutions().get(0), startActivity);
      }
      else if (subProcessInstance.getExecutions().size()>1) {
        throw new ProcessEngineException("starting a process instance in parallel pathes of execution is not possible at the moment");
      }

      // and start normally
      subProcessInstance.start(callActivityVariables);
    }
  }

  protected void healExecution(ExecutionEntity parentExecution, ExecutionEntity execution, ActivityImpl startActivity) throws Exception {
    // parent execution is not active if kids exist
    parentExecution.setActive(false);

    // add start context as the used element is not a StartEvent
    if (execution.getExecutions().size()==0) {
      // if root element
      Field processInstanceStartContextField = ExecutionEntity.class.getDeclaredField("processInstanceStartContext");
      processInstanceStartContextField.setAccessible(true);
      processInstanceStartContextField.set(execution, new ProcessInstanceStartContext(startActivity));
    }
    else {
      for (ExecutionEntity child : execution.getExecutions()) {
        // actually at the moment it is not possible to have multiple executions here!
        // we only jump into one specific hierarchy. But it would be able to extend this behavior.
        healExecution(execution, child, startActivity);
      }
    }
  }

  public static void copyProperty(String name, Class clazz, CallActivityBehavior from, MigrationEnabledCallActivityBehavior to, boolean addCopy) {
    try {
      // set normal field
      Field privateField = clazz.getDeclaredField(name);
      privateField.setAccessible(true);

      Object fieldValue = privateField.get(from);
      privateField.set(to, fieldValue);

      privateField.setAccessible(false);

      // set copy if applicable
      if (addCopy) {
        Field copyField = MigrationEnabledCallActivityBehavior.class.getDeclaredField("copy_" + name);
        copyField.setAccessible(true);
        copyField.set(to, fieldValue);
        copyField.setAccessible(false);
      }
    } catch (Exception ex) {
      throw new ProcessEngineException("Could not copy property '" + name + "' to CallActivityBehavior of migration extension due to: " + ex.getMessage(), ex);
    }
  }

}