/**
   * Validate if BusinessObjectQuery returns business objects which are defined in the models
   * MODEL_NAME2 and MODEL_NAME3. Note: If BusinessObjectsList is executed standalone than
   * bos.size() == expected.size(). But if it is executed after CheckFiltering2 then bos.size() >
   * expected.size() because CheckFiltering2 deployes MODEL_NAME3 as a new version. This means that
   * bos.size() == expected.size()+2 in this case.
   */
  @Test
  public void BusinessObjectsList() {
    BusinessObjectQuery query = BusinessObjectQuery.findAll();
    query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_DESCRIPTION));

    BusinessObjects bos = sf.getQueryService().getAllBusinessObjects(query);

    List<String> expected =
        CollectionUtils.newArrayListFromElements(
            Arrays.asList(
                new QName(MODEL_NAME2, "Account").toString(),
                new QName(MODEL_NAME2, "Customer").toString(),
                new QName(MODEL_NAME2, "Order").toString(),
                new QName(MODEL_NAME2, "Fund").toString(),
                new QName(MODEL_NAME2, "FundGroup").toString(),
                new QName(MODEL_NAME3, "Employee").toString(),
                new QName(MODEL_NAME3, "Fund").toString()));

    List<String> removedEntries = CollectionUtils.newArrayList(expected.size());

    for (BusinessObject bo : bos) {
      String qualifiedBOId = new QName(bo.getModelId(), bo.getId()).toString();
      if (expected.remove(qualifiedBOId)) {
        removedEntries.add(qualifiedBOId);
      } else {
        Assert.assertTrue(
            "Not expected entry: " + qualifiedBOId, removedEntries.contains(qualifiedBOId));
      }
    }
    Assert.assertTrue("Missing business objects: " + expected, expected.isEmpty());
  }
  public static List<TransitionTarget> getRelocateTargets(
      long activityInstanceOid, TransitionOptions options, ScanDirection direction) {
    IActivityInstance ai = ActivityInstanceBean.findByOID(activityInstanceOid);
    IActivity activity = ai.getActivity();

    if (!activity.getBooleanAttribute(PredefinedConstants.ACTIVITY_IS_RELOCATE_SOURCE_ATT)) {
      // activity is not a relocation source
      return Collections.emptyList();
    }

    Stack<TransitionStep> steps = new Stack();
    List<TransitionTarget> targets = CollectionUtils.newList();
    Set<TransitionTarget> visited = CollectionUtils.newSet();
    switch (direction) {
      case FORWARD:
        addActivities(
            visited,
            targets,
            ai,
            options == null ? TransitionOptions.DEFAULT : options,
            true,
            steps);
        break;
      case BACKWARD:
        addActivities(
            visited,
            targets,
            ai,
            options == null ? TransitionOptions.DEFAULT : options,
            false,
            steps);
        break;
      default:
        addActivities(
            visited,
            targets,
            ai,
            options == null ? TransitionOptions.DEFAULT : options,
            true,
            steps);
        addActivities(
            visited,
            targets,
            ai,
            options == null ? TransitionOptions.DEFAULT : options,
            false,
            steps);
    }
    return targets;
  }
 private void checkValue(
     List<BusinessObject.Value> boValues, boolean strict, String name, Object... values) {
   Set<Object> expected = CollectionUtils.newSetFromIterator(Arrays.asList(values).iterator());
   Set<Object> actual = CollectionUtils.newSet();
   for (BusinessObject.Value boValue : boValues) {
     Map<?, ?> data = (Map<?, ?>) boValue.getValue();
     actual.add(data.get(name));
   }
   if (strict) {
     Assert.assertEquals("Values: ", expected, actual);
   } else {
     expected.removeAll(actual);
     Assert.assertTrue("Missing values: " + expected, expected.isEmpty());
   }
 }
 private static LinkedList<ITransition> asList(ModelElementList<ITransition> transitions) {
   LinkedList<ITransition> unconsumed = CollectionUtils.newLinkedList();
   for (ITransition transition : transitions) {
     unconsumed.add(transition);
   }
   return unconsumed;
 }
 private static void addActivities(
     Set<TransitionTarget> visited,
     List<TransitionTarget> targets,
     IActivity activity,
     TransitionOptions options,
     boolean forward,
     Stack<TransitionStep> steps) {
   ModelElementList<ITransition> transitions =
       forward ? activity.getOutTransitions() : activity.getInTransitions();
   JoinSplitType jsType = forward ? activity.getSplitType() : activity.getJoinType();
   if (JoinSplitType.And == jsType && transitions.size() > 1) {
     IActivity target =
         consume(
             activity,
             asList(transitions),
             CollectionUtils.<ITransition>newHashSet(),
             forward,
             options.areLoopsAllowed());
     if (target != null) {
       addActivity(visited, targets, target, options, forward, steps);
     }
   } else {
     for (ITransition transition : transitions) {
       IActivity target = forward ? transition.getToActivity() : transition.getFromActivity();
       jsType = forward ? target.getJoinType() : target.getSplitType();
       if (JoinSplitType.And != jsType) {
         addActivity(visited, targets, target, options, forward, steps);
       }
     }
   }
 }
  /**
   * return just model and its participants
   *
   * @return
   * @throws Exception
   */
  public List<ModelDTO> getModelParticipants() {
    List<ModelDTO> modelList = CollectionUtils.newArrayList();
    Collection<DeployedModel> models = CollectionUtils.newArrayList();
    models = ModelCache.findModelCache().getActiveModels();

    for (DeployedModel model : models) {
      ModelDTO modelDTO = DTOBuilder.build(model, ModelDTO.class);
      modelList.add(modelDTO);
      // Add all top-level Organizations
      modelDTO.children = updateTopLevelOrganizations(model);
      // Add all top-level Roles
      modelDTO.children.addAll(updateTopLevelRoles(model));
    }

    return modelList;
  }
  @Override
  protected ModelType finalizeElement() {
    super.finalizeElement();

    element.setVendor(XMLConstants.VENDOR_NAME);
    element.setCarnotVersion(CurrentVersion.getVersionName());

    element.setScript(XpdlFactory.eINSTANCE.createScriptType());
    element.getScript().setType("text/ecmascript");
    element.setTypeDeclarations(XpdlFactory.eINSTANCE.createTypeDeclarationsType());

    element.setCreated(new Date().toString());

    element.setAuthor(System.getProperty("user.name"));

    element.setModelOID(0);

    // add default elements
    List<ModelInitializer> modelInitializers = CollectionUtils.newArrayList();
    modelInitializers.add(new DefaultTypesInitializer());
    modelInitializers.add(new DefaultElementsInitializer());
    // allow for third party extensions
    modelInitializers.addAll(ExtensionProviderUtils.getExtensionProviders(ModelInitializer.class));

    for (ModelInitializer initializer : modelInitializers) {
      initializer.initializeModel(element);
    }

    if (null != definition) {
      definition.build(element);
    }

    return element;
  }
  protected AbstractStructuredDataAccessPointAdapter wrapElement(TypedXPath xPath, Object value) {
    AbstractStructuredDataAccessPointAdapter adapter = null;

    if (null != adapters) {
      // was this value wrapped before?
      adapter = (AbstractStructuredDataAccessPointAdapter) adapters.get(xPath);
    }
    if (null == adapter) {
      if (xPath.isList()) {
        adapter = new StructuredDataListAccessor(xPath, null, isConstant());
      } else if (BigData.NULL == xPath.getType() || xPath.getChildXPaths().size() > 0) {
        adapter = new StructuredDataMapAccessor(xPath, null, isConstant());
      }
      if (null == adapters) {
        this.adapters = CollectionUtils.newMap();
      }
      adapters.put(xPath, adapter);
    }

    if (null != adapter) {
      if (adapter.getValue() != value) {
        adapter.bindValue(value);
      }
    }

    return adapter;
  }
  @Before
  public void setup() {
    for (int customerId = 1; customerId <= 5; customerId++) {
      ProcessInstance pi =
          sf.getWorkflowService()
              .startProcess(new QName(MODEL_NAME2, "OrderCreation").toString(), null, true);
      List<ActivityInstance> w = getWorklist();
      Assert.assertEquals("worklist", 1, w.size());
      ActivityInstance ai = w.get(0);
      Assert.assertEquals("process instance", pi.getOID(), ai.getProcessInstanceOID());
      Assert.assertEquals("activity instance", "EnterOrderData", ai.getActivity().getId());
      Map<String, Object> order = CollectionUtils.newMap();
      order.put("date", new Date());
      order.put("customerId", customerId);
      ai =
          complete(
              ai, PredefinedConstants.DEFAULT_CONTEXT, Collections.singletonMap("Order", order));

      try {
        ProcessInstanceStateBarrier.instance().await(pi.getOID(), ProcessInstanceState.Completed);
      } catch (Exception e) {
      }
      w = getWorklist();
    }
  }
  private BusinessObject createOrder(DeployedModelDescription model, int customerId) {
    final Map<String, Object> order = CollectionUtils.newMap();
    order.put("date", new Date());
    order.put("customerId", customerId);

    return sf.getWorkflowService()
        .createBusinessObjectInstance(
            new QName(model.getId(), "Order").toString(), (Serializable) order);
  }
 /**
  * @param userId
  * @return
  */
 public QueryResultDTO getAllInstances(Options options, ActivityInstanceQuery query) {
   QueryResult<?> queryResult = activityInstanceUtils.getActivityInstances(options, query);
   if (CollectionUtils.isNotEmpty(options.extraColumns)) {
     return ActivityTableUtils.buildTableResult(
         queryResult, MODE.ACTIVITY_TABLE, null, options.extraColumns);
   } else {
     return ActivityTableUtils.buildTableResult(queryResult, MODE.ACTIVITY_TABLE);
   }
 }
  public static ActivityStatisticsQuery forProcesses(Set<ProcessDefinition> processes) {
    Set<String> processIds = CollectionUtils.newSet();
    for (Iterator<ProcessDefinition> i = processes.iterator(); i.hasNext(); ) {
      ProcessDefinition process = i.next();
      processIds.add(process.getQualifiedId());
    }

    return forProcessIds(processIds);
  }
 private static List<IActivity> getEndActivities(IProcessDefinition process) {
   List<IActivity> activities = CollectionUtils.newList();
   for (IActivity activity : process.getActivities()) {
     if (activity.getOutTransitions().isEmpty()) {
       activities.add(activity);
     }
   }
   return activities;
 }
  /**
   * Validates email address and returns validation error messages
   *
   * @return
   */
  private List<String> validateMailAddresses(Map<RecipientType, String[]> recipientDetails) {
    ArrayList<String> errorMsg = new ArrayList<String>();

    // Validate From email address
    if (StringUtils.isEmpty(mailSender)) {
      errorMsg.add(getMessages().get("fromAddressMessage"));
    } else if (!EMailAddressValidator.validateEmailAddress(mailSender)) {
      errorMsg.add(getMessages().get("fromMessage"));
    }

    if (StringUtils.isEmpty(mailSubject)) {
      errorMsg.add(getMessages().get("subjectMessage"));
    }

    if (StringUtils.isEmpty(toMailAddress)
        && StringUtils.isEmpty(ccMailAddress)
        && StringUtils.isEmpty(bccMailAddress)) {
      errorMsg.add(getMessages().get("recipientAddressMessage"));
    } else {
      if (StringUtils.isNotEmpty(toMailAddress)) {
        if (!CollectionUtils.isEmpty(EMailAddressValidator.validateEmailAddresses(toMailAddress))) {
          errorMsg.add(getMessages().get("toMessage"));
        } else {
          recipientDetails.put(RecipientType.TO, toMailAddress.trim().split(";"));
        }
      }
      if (StringUtils.isNotEmpty(ccMailAddress)) {
        if (!CollectionUtils.isEmpty(EMailAddressValidator.validateEmailAddresses(ccMailAddress))) {
          errorMsg.add(getMessages().get("ccMessage"));
        } else {
          recipientDetails.put(RecipientType.CC, ccMailAddress.trim().split(";"));
        }
      }
      if (StringUtils.isNotEmpty(bccMailAddress)) {
        if (!CollectionUtils.isEmpty(
            EMailAddressValidator.validateEmailAddresses(bccMailAddress))) {
          errorMsg.add(getMessages().get("bccMessage"));
        } else {
          recipientDetails.put(RecipientType.BCC, bccMailAddress.trim().split(";"));
        }
      }
    }
    return errorMsg;
  }
  /**
   * @param modelCache
   * @param ai
   * @return
   */
  private static Map<String, DescriptorDTO> getProcessDescriptors(
      ModelCache modelCache, ActivityInstance ai) {
    List<ProcessDescriptor> processDescriptorsList = CollectionUtils.newList();

    Model model = modelCache.getModel(ai.getModelOID());
    ProcessDefinition processDefinition =
        (model != null) ? model.getProcessDefinition(ai.getProcessDefinitionId()) : null;
    if (processDefinition != null) {
      ProcessInstanceDetails processInstanceDetails =
          (ProcessInstanceDetails) ai.getProcessInstance();
      Map<String, Object> descriptorValues = processInstanceDetails.getDescriptors();
      CommonDescriptorUtils.updateProcessDocumentDescriptors(
          descriptorValues, ai.getProcessInstance(), processDefinition);
      if (processInstanceDetails.isCaseProcessInstance()) {
        processDescriptorsList =
            CommonDescriptorUtils.createCaseDescriptors(
                processInstanceDetails.getDescriptorDefinitions(),
                descriptorValues,
                processDefinition,
                true);
      } else {
        processDescriptorsList =
            CommonDescriptorUtils.createProcessDescriptors(
                descriptorValues, processDefinition, true, true);
      }

      Map<String, DescriptorDTO> descriptors = new LinkedHashMap<String, DescriptorDTO>();
      for (Object descriptor : processDescriptorsList) {
        if (descriptor instanceof ProcessDocumentDescriptor) {
          ProcessDocumentDescriptor desc = (ProcessDocumentDescriptor) descriptor;

          List<DocumentDTO> documents = new ArrayList<DocumentDTO>();

          for (DocumentInfo documentInfo : desc.getDocuments()) {
            DocumentDTO documentDTO = new DocumentDTO();
            documentDTO.name = documentInfo.getName();
            documentDTO.uuid = documentInfo.getId();
            documentDTO.contentType =
                (MimeTypesHelper.detectMimeType(documentInfo.getName(), null).getType());
            documents.add(documentDTO);
          }

          DescriptorDTO descriptorDto =
              new DescriptorDTO(desc.getKey(), desc.getValue(), true, documents);
          descriptors.put(desc.getId(), descriptorDto);
        } else {
          ProcessDescriptor desc = (ProcessDescriptor) descriptor;
          DescriptorDTO descriptorDto =
              new DescriptorDTO(desc.getKey(), desc.getValue(), false, null);
          descriptors.put(desc.getId(), descriptorDto);
        }
      }
      return descriptors;
    }
    return null;
  }
  private BusinessObject createCustomer(DeployedModelDescription model, int customerId) {
    final Map<String, Object> order = CollectionUtils.newMap();
    order.put("id", customerId);
    order.put("firstName", "Danny" + customerId);
    order.put("lastName", "North" + customerId);

    return sf.getWorkflowService()
        .createBusinessObjectInstance(
            new QName(model.getId(), "Customer").toString(), (Serializable) order);
  }
 /**
  * Add descriptor policy
  *
  * @param options
  * @param query
  */
 public static void addDescriptorPolicy(Options options, Query query) {
   if (options.allDescriptorsVisible) {
     query.setPolicy(DescriptorPolicy.WITH_DESCRIPTORS);
   } else if (CollectionUtils.isNotEmpty(options.visibleDescriptorColumns)) {
     query.setPolicy(
         DescriptorPolicy.withIds(new HashSet<String>(options.visibleDescriptorColumns)));
   } else {
     query.setPolicy(DescriptorPolicy.NO_DESCRIPTORS);
   }
 }
  /**
   * Create some instances for a given BO and validate if they can be queried:
   *
   * <ul>
   *   <li>where the qualified business object id is set
   *   <li>the primary key is passed to findForBusinessObject()
   *   <li>the qualified business object id is passed to findForBusinessObject and the primary key
   *       is set as a data filter
   *   <li>the qualified business object id is passed to findForBusinessObject and an attribute of
   *       the BO is set as a data filter
   * </ul>
   */
  @Test
  public void CheckFiltering() throws Exception {
    DeployedModelDescription model =
        sf.getQueryService().getModels(DeployedModelQuery.findActiveForId(MODEL_NAME3)).get(0);

    String businessObjectQualifiedId = new QName(model.getId(), "Fund").toString();
    for (int i = 1; i <= 9; i++) {
      final Map<String, Object> fund = CollectionUtils.newMap();
      fund.put("AccountNumber", "100100" + i);
      fund.put("AccountName", "Fund" + i);

      sf.getWorkflowService()
          .createBusinessObjectInstance(businessObjectQualifiedId, (Serializable) fund);
    }

    BusinessObjectQuery query =
        BusinessObjectQuery.findForBusinessObject(businessObjectQualifiedId);
    query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
    BusinessObjects bos = sf.getQueryService().getAllBusinessObjects(query);
    Assert.assertEquals("Objects", 1, bos.getSize());
    BusinessObject bo = bos.get(0);
    List<BusinessObject.Value> values = bo.getValues();
    Assert.assertEquals("Values", 9, values.size());

    query = BusinessObjectQuery.findWithPrimaryKey(businessObjectQualifiedId, "1001003");
    query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
    bos = sf.getQueryService().getAllBusinessObjects(query);
    Assert.assertEquals("Objects", 1, bos.getSize());
    bo = bos.get(0);
    values = bo.getValues();
    Assert.assertEquals("Values", 1, values.size());
    checkValue(values, true, "AccountNumber", "1001003");

    query = BusinessObjectQuery.findForBusinessObject(businessObjectQualifiedId);
    query.where(DataFilter.isEqual("Fund", "AccountNumber", "1001005"));
    query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
    bos = sf.getQueryService().getAllBusinessObjects(query);
    Assert.assertEquals("Objects", 1, bos.getSize());
    bo = bos.get(0);
    values = bo.getValues();
    Assert.assertEquals("Values", 1, values.size());
    checkValue(values, true, "AccountNumber", "1001005");

    query = BusinessObjectQuery.findForBusinessObject(businessObjectQualifiedId);
    query.where(DataFilter.isEqual("Fund", "AccountName", "Fund7"));
    query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
    bos = sf.getQueryService().getAllBusinessObjects(query);
    Assert.assertEquals("Objects", 1, bos.getSize());
    bo = bos.get(0);
    values = bo.getValues();
    Assert.assertEquals("Values", 1, values.size());
    checkValue(values, true, "AccountName", "Fund7");
  }
 @Override
 public Collection<IDaemon> getDaemons() {
   List<IModel> models = ModelManagerFactory.getCurrent().findActiveModels();
   if (!models.isEmpty()) {
     Set<String> ids = CollectionUtils.newSet();
     List<IDaemon> daemons = CollectionUtils.newList();
     for (IModel model : models) {
       // Compute and store the model dependent daemons in model for faster lookup
       List<IDaemon> modelDependentDaemons;
       synchronized (model) {
         modelDependentDaemons =
             (List<IDaemon>) model.getRuntimeAttribute(CACHED_DAEMON_FACTORY);
         if (modelDependentDaemons == null) {
           modelDependentDaemons = CollectionUtils.newList();
           for (Iterator i = model.getAllTriggerTypes(); i.hasNext(); ) {
             ITriggerType type = (ITriggerType) i.next();
             if (type.isPullTrigger()) {
               modelDependentDaemons.add(new TriggerDaemon(type));
             }
           }
           model.setRuntimeAttribute(CACHED_DAEMON_FACTORY, modelDependentDaemons);
         }
       }
       // Compute union of all daemons
       // This always has to be computed as the daemons of a model might change
       // if new model version is deployed
       for (IDaemon daemon : modelDependentDaemons) {
         String type = daemon.getType();
         if (!ids.contains(type)) {
           daemons.add(daemon);
           ids.add(type);
         }
       }
     }
     return daemons;
   }
   return Collections.emptyList();
 }
  public Map getOutDataValues(ActivityInstance ai) {
    trace.info("JSP Application");
    HttpSession webSession =
        (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);

    ApplicationContext applicationContext =
        ai.getActivity().getApplicationContext(PredefinedConstants.JSP_CONTEXT);

    Map outData = CollectionUtils.newMap();
    for (Iterator iterator = applicationContext.getAllOutDataMappings().iterator();
        iterator.hasNext() && webSession != null; ) {
      DataMapping mapping = (DataMapping) iterator.next();
      String mappingID = mapping.getId();
      outData.put(mappingID, webSession.getAttribute(mappingID));
    }

    return outData;
  }
/**
 * @author rsauer
 * @version $Revision$
 */
public class AuditTrailActivator extends Plugin {
  private final List<IAuditTrailDbListener> dbListeners = CollectionUtils.newList();

  private static AuditTrailActivator instance = null;

  public static AuditTrailActivator instance() {
    return instance;
  }

  public AuditTrailActivator() {}

  public void start(BundleContext context) throws Exception {
    super.start(context);

    instance = this;
  }

  public void stop(BundleContext context) throws Exception {
    super.stop(context);

    instance = null;
  }

  public void addDbListener(IAuditTrailDbListener listener) {
    if (!dbListeners.contains(listener)) {
      dbListeners.add(listener);
    }
  }

  public void removeDbListener(IAuditTrailDbListener listener) {
    dbListeners.remove(listener);
  }

  protected void notifyDbListeners(IFolder dbFolder, int change) {
    if (!dbListeners.isEmpty()) {
      IAuditTrailDbListener[] listeners =
          (IAuditTrailDbListener[]) dbListeners.toArray(new IAuditTrailDbListener[0]);
      for (int i = 0; i < listeners.length; i++) {
        listeners[i].onAuditTrailDbChanged(dbFolder, change);
      }
    }
  }
}
  /**
   * Save mail as a document
   *
   * @throws DocumentManagementServiceException
   * @throws IOException
   */
  private void saveEmailDocument() throws DocumentManagementServiceException, IOException {
    Folder processAttachmentsFolder =
        RepositoryUtility.getProcessAttachmentsFolder(processInstance);
    StringBuilder attachmentInfo = new StringBuilder("");
    JCRVersionTracker vt = null;

    if (!CollectionUtils.isEmpty(attachments)) {
      for (Attachment attachment : attachments) {
        attachmentInfo.append(attachment.getName());
        if (attachment.isContainsDocument()) {
          vt = new JCRVersionTracker(attachment.getDocument());
          attachmentInfo.append("(").append(vt.getCurrentVersionNo()).append(")");
        } else {
          createDocumentFromAttachment(attachment, processAttachmentsFolder);
        }
        attachmentInfo.append(";");
      }
    }
    createDocumentForMail(processAttachmentsFolder, attachmentInfo.toString());
  }
 private void select() {
   if (model == null
       && departmentList != null
       && !departmentList.isEmpty()
       && departmentList.size() == 1) {
     for (Department d : departmentList) {
       addDepartmentData(d);
     }
   } else if (model != null) {
     DepartmentDialogBean deptBean = DepartmentDialogBean.getCurrent();
     deptBean.setModel(model);
     deptBean.openPopup();
   } else if (model == null) {
     // TODO support asynchronous/synchronous start selection?
     ActivityInstance nextActivityInstance = null;
     ProcessInstance processInstance = PPUtils.startProcess(processDefinition, true);
     if (!(ProcessInstanceUtils.isTransientProcess(processInstance)
         || ProcessInstanceUtils.isCompletedProcess(processInstance))) {
       nextActivityInstance = PPUtils.activateNextActivityInstance(processInstance);
       if (nextActivityInstance != null) {
         Map<String, Object> params = CollectionUtils.newTreeMap();
         if (WorklistsBean.getInstance()
             .isAssemblyLineActivity(nextActivityInstance.getActivity())) {
           params.put("assemblyLineActivity", true);
           params.put("worklistsBean", WorklistsBean.getInstance());
         }
         ActivityInstanceUtils.openActivity(nextActivityInstance, params);
       }
     }
     if (nextActivityInstance == null) {
       MessageDialog.addInfoMessage(
           MessagePropertiesBean.getInstance()
               .getParamString("common.processStarted.message", new String[] {getName()}));
     }
   }
 }
  private static IActivity consume(
      IActivity startActivity,
      LinkedList<ITransition> unconsumed,
      HashSet<ITransition> visited,
      boolean forward,
      boolean supportsLoops) {
    int unchanged = 0;
    while (!unconsumed.isEmpty()) {
      ITransition transition = unconsumed.element();
      IActivity target = forward ? transition.getToActivity() : transition.getFromActivity();

      if (startActivity == target) {
        // unsupported loop
        break;
      }

      JoinSplitType inJsType = forward ? target.getJoinType() : target.getSplitType();
      if (JoinSplitType.And == inJsType) {
        List<ITransition> pending = CollectionUtils.newList();
        ModelElementList<ITransition> transitions =
            forward ? target.getInTransitions() : target.getOutTransitions();
        for (ITransition incoming : transitions) {
          if (unconsumed.remove(incoming)) {
            pending.add(incoming);
          }
        }
        if (pending.size() == transitions.size()) // all incoming transitions consumed
        {
          if (unconsumed.isEmpty()) {
            return target;
          }
        } else {
          if (!unconsumed
              .isEmpty()) // unable to consume all transitions, but there are more branches, put
          // them all back to the end
          {
            unconsumed.addAll(pending);
            unchanged++;
          }
          if (unchanged == unconsumed.size()) {
            return null;
          }
          continue;
        }
      } else {
        unconsumed.remove(transition);
      }
      unchanged = 0;

      ModelElementList<ITransition> transitions =
          forward ? target.getOutTransitions() : target.getInTransitions();
      if (transitions.isEmpty()) {
        return null;
      }

      JoinSplitType outJsType = forward ? target.getSplitType() : target.getJoinType();
      if (JoinSplitType.Xor == outJsType && transitions.size() > 1) {
        return consumeXor(startActivity, unconsumed, visited, forward, supportsLoops, transitions);
      } else {
        for (ITransition out : transitions) {
          if (visited.contains(out)) // loop
          {
            if (!supportsLoops) {
              return null;
            }
          } else {
            visited.add(out);
            unconsumed.add(out);
          }
        }
      }
    }
    return null;
  }
/**
 * @author sauer
 * @version $Revision$
 */
public class RtDetailsFactory {
  private static final String DATA_PATH_KEY = DataPathDetails.class.getName();

  private Map<Object, Object> cache = CollectionUtils.newMap();
  private boolean usingCaches = false;

  public boolean isUsingCaches() {
    return usingCaches;
  }

  public void setUsingCaches(boolean usingCaches) {
    this.usingCaches = usingCaches;
  }

  public DataPath createDetails(IDataPath dp) {
    DataPath details = dp.getRuntimeAttribute(DATA_PATH_KEY);
    if (details == null) {
      details = new DataPathDetails(dp);
      dp.setRuntimeAttribute(DATA_PATH_KEY, details);
    }
    return details;
  }

  public DataPath createDetails(CaseDescriptorRef ref) {
    DataPath details = null;
    if (!usingCaches || (details = (DataPath) cache.get(ref)) == null) {
      details = new DataPathDetails(ref);
      cache.put(ref, details);
    }
    return details;
  }

  public ProcessInstance createDetails(IProcessInstance pi) {
    ProcessInstance details = null;
    if (!usingCaches || (details = (ProcessInstance) cache.get(pi)) == null) {
      details = new ProcessInstanceDetails(pi);
      cache.put(pi, details);
    }
    return details;
  }

  public ProcessInstanceLinkType createDetails(IProcessInstanceLinkType pilt) {
    ProcessInstanceLinkType details = null;
    if (!usingCaches || (details = (ProcessInstanceLinkType) cache.get(pilt)) == null) {
      details =
          new ProcessInstanceLinkTypeDetails(pilt.getOID(), pilt.getId(), pilt.getDescription());
      cache.put(pilt, details);
    }
    return details;
  }

  public ProcessInstanceLink createDetails(IProcessInstanceLink pil) {
    ProcessInstanceLink details = null;
    if (!usingCaches || (details = (ProcessInstanceLink) cache.get(pil)) == null) {
      details =
          new ProcessInstanceLinkDetails(
              pil.getProcessInstanceOID(),
              pil.getLinkedProcessInstanceOID(),
              DetailsFactory.create(pil.getLinkType()),
              pil.getCreateTime(),
              pil.getCreatingUserOID(),
              pil.getComment());
      cache.put(pil, details);
    }
    return details;
  }

  public UserInfo createDetails(IUser user) {
    UserInfo details = (UserInfo) cache.get(user);
    if (details == null) {
      details =
          new UserInfoDetails(user.getOID(), user.getId(), PerformerUtils.getQualifiedName(user));
      cache.put(user, details);
    }
    return details;
  }

  public User createUserDetails(IUser user) {
    UserKey key = new UserKey(user);
    User details = (User) cache.get(key);
    if (details == null) {
      details = new UserDetails(user);
      cache.put(key, details);
    }
    return details;
  }

  public UserGroupInfo createDetails(IUserGroup group) {
    UserGroupInfo details = (UserGroupInfo) cache.get(group);
    if (details == null) {
      details = new UserGroupInfoDetails(group.getOID(), group.getId(), group.getName());
      cache.put(group, details);
    }
    return details;
  }

  public DepartmentInfo createDetails(IDepartment department) {
    DepartmentInfo details = (DepartmentInfo) cache.get(department);
    if (details == null) {
      details = new DepartmentInfoDetails(department);
      cache.put(department, details);
    }
    return details;
  }

  private static class UserKey {
    private IUser user;

    public UserKey(IUser user) {
      this.user = user;
    }

    @Override
    public int hashCode() {
      return 31 + user.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      return user.equals(((UserKey) obj).user);
    }
  }
}
/**
 * @author ubirkemeyer
 * @version $Revision$
 */
public final class DaemonFactory {
  private static final ServiceLoader<IDaemon.Factory> factoryLoader =
      ServiceLoader.load(IDaemon.Factory.class);

  private Map<String, IDaemon> daemons = CollectionUtils.newMap();

  private DaemonFactory() {
    for (IDaemon.Factory factory : DaemonFactory.factoryLoader) {
      for (IDaemon daemon : factory.getDaemons()) {
        daemons.put(daemon.getType(), daemon);
      }
    }
  }

  public static DaemonFactory instance() {
    return new DaemonFactory();
  }

  public IDaemon get(String type) {
    return (IDaemon) daemons.get(type);
  }

  public Iterator<IDaemon> getAllDaemons() {
    return daemons.values().iterator();
  }

  public static final class PredefinedDaemonsFactory implements IDaemon.Factory {
    private static final Collection<IDaemon> predefinedDaemons =
        Arrays.asList(
            new IDaemon[] {
              new EventDaemon(), new CriticalityDaemon(), new SystemDaemon(), new BenchmarkDaemon()
            });

    @Override
    public Collection<IDaemon> getDaemons() {
      return predefinedDaemons;
    }
  }

  public static final class TriggerDaemonsFactory implements IDaemon.Factory {
    private static final String CACHED_DAEMON_FACTORY = "cached.daemon.factory";

    @Override
    public Collection<IDaemon> getDaemons() {
      List<IModel> models = ModelManagerFactory.getCurrent().findActiveModels();
      if (!models.isEmpty()) {
        Set<String> ids = CollectionUtils.newSet();
        List<IDaemon> daemons = CollectionUtils.newList();
        for (IModel model : models) {
          // Compute and store the model dependent daemons in model for faster lookup
          List<IDaemon> modelDependentDaemons;
          synchronized (model) {
            modelDependentDaemons =
                (List<IDaemon>) model.getRuntimeAttribute(CACHED_DAEMON_FACTORY);
            if (modelDependentDaemons == null) {
              modelDependentDaemons = CollectionUtils.newList();
              for (Iterator i = model.getAllTriggerTypes(); i.hasNext(); ) {
                ITriggerType type = (ITriggerType) i.next();
                if (type.isPullTrigger()) {
                  modelDependentDaemons.add(new TriggerDaemon(type));
                }
              }
              model.setRuntimeAttribute(CACHED_DAEMON_FACTORY, modelDependentDaemons);
            }
          }
          // Compute union of all daemons
          // This always has to be computed as the daemons of a model might change
          // if new model version is deployed
          for (IDaemon daemon : modelDependentDaemons) {
            String type = daemon.getType();
            if (!ids.contains(type)) {
              daemons.add(daemon);
              ids.add(type);
            }
          }
        }
        return daemons;
      }
      return Collections.emptyList();
    }
  }
}
  /**
   * Adds filter criteria to the query
   *
   * @param query Query
   * @param options Options
   */
  public static void addFilterCriteria(Query query, Options options) {

    WorklistFilterDTO filterDTO = (WorklistFilterDTO) options.filter;

    if (filterDTO == null) {
      return;
    }

    FilterAndTerm filter = query.getFilter().addAndTerm();

    boolean worklistQuery = query instanceof WorklistQuery;

    // Activity ID
    if (null != filterDTO.activityOID) {
      if (null != filterDTO.activityOID.from) {
        filter.and(
            (worklistQuery ? WorklistQuery.ACTIVITY_INSTANCE_OID : ActivityInstanceQuery.OID)
                .greaterOrEqual(filterDTO.activityOID.from));
      }
      if (null != filterDTO.activityOID.to) {
        filter.and(
            (worklistQuery ? WorklistQuery.ACTIVITY_INSTANCE_OID : ActivityInstanceQuery.OID)
                .lessOrEqual(filterDTO.activityOID.to));
      }
    }
    // Process Instance Oid
    if (null != filterDTO.processOID) {
      if (null != filterDTO.processOID.from) {
        filter.and(
            (worklistQuery
                    ? WorklistQuery.PROCESS_INSTANCE_OID
                    : ActivityInstanceQuery.PROCESS_INSTANCE_OID)
                .greaterOrEqual(filterDTO.processOID.from));
      }
      if (null != filterDTO.processOID.to) {
        filter.and(
            (worklistQuery
                    ? WorklistQuery.PROCESS_INSTANCE_OID
                    : ActivityInstanceQuery.PROCESS_INSTANCE_OID)
                .lessOrEqual(filterDTO.processOID.to));
      }
    }
    // Start Filter
    if (null != filterDTO.startTime) {

      if (filterDTO.startTime.from != null) {
        Date fromDate = new Date(filterDTO.startTime.from);
        filter.and(
            (worklistQuery ? WorklistQuery.START_TIME : ActivityInstanceQuery.START_TIME)
                .greaterOrEqual(fromDate.getTime()));
      }

      if (filterDTO.startTime.to != null) {
        Date toDate = new Date(filterDTO.startTime.to);
        filter.and(
            (worklistQuery ? WorklistQuery.START_TIME : ActivityInstanceQuery.START_TIME)
                .lessOrEqual(toDate.getTime()));
      }
    }
    // Modified Filter
    if (null != filterDTO.lastModified) {

      if (filterDTO.lastModified.from != null) {
        Date fromDate = new Date(filterDTO.lastModified.from);

        filter.and(
            (worklistQuery
                    ? WorklistQuery.LAST_MODIFICATION_TIME
                    : ActivityInstanceQuery.LAST_MODIFICATION_TIME)
                .greaterOrEqual(fromDate.getTime()));
      }

      if (filterDTO.lastModified.to != null) {
        Date toDate = new Date(filterDTO.lastModified.to);

        filter.and(
            (worklistQuery
                    ? WorklistQuery.LAST_MODIFICATION_TIME
                    : ActivityInstanceQuery.LAST_MODIFICATION_TIME)
                .lessOrEqual(toDate.getTime()));
      }
    }
    // Status Filter
    if (null != filterDTO.status) {
      FilterOrTerm or = filter.addOrTerm();
      for (String status : filterDTO.status.like) {
        Integer actState = Integer.parseInt(status);
        if (!worklistQuery) {
          or.add(ActivityInstanceQuery.STATE.isEqual(Long.parseLong(status.toString())));
        } else if (worklistQuery) {
          // Worklist Query uses ActivityStateFilter.
          or.add(new ActivityStateFilter(ActivityInstanceState.getState(actState)));
        }
      }
    }
    // Priority Filter
    if (null != filterDTO.priority) {
      FilterOrTerm or = filter.addOrTerm();
      for (String priority : filterDTO.priority.like) {
        or.or(
            (worklistQuery
                    ? WorklistQuery.PROCESS_INSTANCE_PRIORITY
                    : ActivityInstanceQuery.PROCESS_INSTANCE_PRIORITY)
                .isEqual(Integer.valueOf(priority)));
      }
    }
    // Criticality Filter
    if (null != filterDTO.criticality) {
      FilterOrTerm or = filter.addOrTerm();
      for (RangeDTO criticality : filterDTO.criticality.rangeLike) {
        or.or(
            (worklistQuery
                    ? WorklistQuery.ACTIVITY_INSTANCE_CRITICALITY
                    : ActivityInstanceQuery.CRITICALITY)
                .between(
                    (criticality.from / PORTAL_CRITICALITY_MUL_FACTOR),
                    criticality.to / PORTAL_CRITICALITY_MUL_FACTOR));
      }
    }
    // Activities Filter
    if (null != filterDTO.activityName) {

      if (!CollectionUtils.isEmpty(filterDTO.activityName.activities)) {
        FilterOrTerm or = filter.addOrTerm();
        if (!filterDTO.activityName.activities.contains("-1")) {
          for (String activity : filterDTO.activityName.activities) {

            or.add(ActivityFilter.forAnyProcess(activity));
          }
        }
      }

      if (!CollectionUtils.isEmpty(filterDTO.activityName.processes)) {
        FilterOrTerm or = filter.addOrTerm();
        if (!filterDTO.activityName.processes.contains("-1")) {
          for (String processQId : filterDTO.activityName.processes) {
            or.add(new ProcessDefinitionFilter(processQId, false));
          }
        }
      }
    }
    // Process Filter
    if (null != filterDTO.processName) {
      FilterOrTerm or = filter.addOrTerm();
      if (!filterDTO.processName.processes.contains("-1")) {
        for (String processQId : filterDTO.processName.processes) {
          or.add(new ProcessDefinitionFilter(processQId, false));
        }
      }
    }
    // Assigned To
    if (null != filterDTO.assignedTo) {
      FilterOrTerm or = filter.addOrTerm();
      for (ParticipantDTO participant : filterDTO.assignedTo.participants) {

        if (ParticipantType.USER.toString().equals(participant.type)) {

          or.add(
              new org.eclipse.stardust.engine.api.query.PerformingUserFilter(
                  Long.valueOf(participant.OID)));
        } else if (ParticipantType.ROLE.toString().endsWith(participant.type)) {
          RoleInfoDetails roleInfo = new RoleInfoDetails(participant.qualifiedId);
          or.add(
              org.eclipse.stardust.engine.api.query.PerformingParticipantFilter.forParticipant(
                  roleInfo));
        } else if (ParticipantType.ORGANIZATION.toString().equals(participant.type)) {

          OrganizationInfoDetails organizationInfo =
              new OrganizationInfoDetails(participant.qualifiedId);
          or.add(
              org.eclipse.stardust.engine.api.query.PerformingParticipantFilter.forParticipant(
                  organizationInfo));
        } else if (ParticipantSearchComponent.PerformerTypeUI.Department.name()
            .equals(participant.type)) {

          DepartmentInfo departmentInfo =
              new DepartmentInfoDetails(
                  participant.OID,
                  participant.id,
                  participant.name,
                  participant.runtimeOrganizationOid);
          or.add(
              org.eclipse.stardust.engine.api.query.ParticipantAssociationFilter.forDepartment(
                  departmentInfo));
        }
      }
    }
    // Completed By
    if (null != filterDTO.completedBy) {
      FilterOrTerm or = filter.addOrTerm();
      for (ParticipantDTO user : filterDTO.completedBy.participants) {
        or.add(new org.eclipse.stardust.engine.api.query.PerformedByUserFilter(user.OID));
      }
    }
    addDescriptorFilters(query, filterDTO);
  }
  /**
   * @param queryResult
   * @return
   */
  public static QueryResultDTO buildTableResult(
      QueryResult<?> queryResult,
      MODE mode,
      Map<String, TrivialManualActivityDTO> trivialManualActivityDetails,
      List<String> extraColumns) {
    List<ActivityInstanceDTO> list = new ArrayList<ActivityInstanceDTO>();
    List<CriticalityCategory> criticalityConfigurations =
        CriticalityUtils.getCriticalityConfiguration();

    ModelCache modelCache = ModelCache.findModelCache();
    QueryResultDTO resultDTO = new QueryResultDTO();
    if (null != queryResult) {
      for (Object object : queryResult) {
        if (object instanceof ActivityInstance) {
          ActivityInstance ai = (ActivityInstance) object;
          ActivityInstanceDTO dto;

          if (ActivityInstanceUtils.isTrivialManualActivity(ai)) {
            TrivialActivityInstanceDTO trivialDto =
                DTOBuilder.build(ai, TrivialActivityInstanceDTO.class);
            trivialDto.trivial = true;

            if (null != trivialManualActivityDetails
                && trivialManualActivityDetails.keySet().contains(String.valueOf(ai.getOID()))) {
              TrivialManualActivityDTO tivialManualActivity =
                  trivialManualActivityDetails.get(String.valueOf(ai.getOID()));
              trivialDto.dataMappings = tivialManualActivity.dataMappings;
              trivialDto.inOutData = tivialManualActivity.inOutData;
            }

            dto = trivialDto;
          } else {
            dto = DTOBuilder.build(ai, ActivityInstanceDTO.class);
          }

          dto.auxillary = isAuxiliaryActivity(ai.getActivity());
          dto.duration = ActivityInstanceUtils.getDuration(ai);
          dto.assignedTo = getAssignedToLabel(ai);
          dto.criticality = populateCriticalityDTO(criticalityConfigurations, ai);
          dto.priority = DTOBuilder.build(ai, PriorityDTO.class);
          dto.status = DTOBuilder.build(ai, StatusDTO.class);
          dto.status.label = ActivityInstanceUtils.getActivityStateLabel(ai);
          dto.descriptorValues = getProcessDescriptors(modelCache, ai);
          dto.activatable = findIfActivatable(ai);
          dto.relocationEligible =
              org.eclipse.stardust.ui.web.viewscommon.utils.ActivityInstanceUtils
                  .isRelocationEligible(ai);
          dto.benchmark = getBenchmarkForActivity(ai);

          List<Note> notes =
              org.eclipse.stardust.ui.web.viewscommon.utils.ProcessInstanceUtils.getNotes(
                  ai.getProcessInstance());
          if (null != notes) {
            dto.notesCount = notes.size();
          }

          if (CollectionUtils.isNotEmpty(extraColumns)
              && extraColumns.contains(Constants.RESUBMISSION_TIME)) {
            Date resubmissionDate =
                org.eclipse.stardust.ui.web.viewscommon.utils.ActivityInstanceUtils
                    .getResubmissionDate(ai);
            if (null != resubmissionDate) {
              dto.resubmissionTime = resubmissionDate.getTime();
            }
          }
          ProcessDefinition processDefinition =
              ProcessDefinitionUtils.getProcessDefinition(
                  ai.getModelOID(), ai.getProcessDefinitionId());
          dto.processInstance.supportsProcessAttachments =
              ProcessDefinitionUtils.supportsProcessAttachments(processDefinition);

          if (mode.equals(MODE.ACTIVITY_TABLE)) {
            dto.completedBy = ActivityInstanceUtils.getPerformedByName(ai);
            dto.participantPerformer = getParticipantPerformer(ai);
            dto.abortActivity = !dto.isCaseInstance && isAbortable(ai);
            dto.delegable = isDelegable(ai);
            dto.abortProcess = ProcessInstanceUtils.isAbortable(ai.getProcessInstance());

          } else {
            dto.lastPerformer = getLastPerformer(ai, UserUtils.getDefaultUserNameDisplayFormat());
            if (!dto.defaultCaseActivity) {
              dto.abortActivity = isAbortable(ai);
              dto.delegable = isDelegable(ai);
            }
          }
          dto.defaultCaseActivity = ActivityInstanceUtils.isDefaultCaseActivity(ai);
          dto.isCaseInstance = ai.getProcessInstance().isCaseProcessInstance();
          if (dto.defaultCaseActivity) {
            dto.activity.name = getCaseName(ai);
          }
          list.add(dto);
        }
      }
      resultDTO.totalCount = queryResult.getTotalCount();
    }
    resultDTO.list = list;
    return resultDTO;
  }
  /**
   * The following test case should ensure that
   *
   * <ul>
   *   <li>Any modifications to an attribute of a BOI via API isn't reflected to process data which
   *       are using the BO
   *   <li>Any modifications to an attribute of a BOI via the process data is only reflected to the
   *       BOI which is attached to the synthetic process instance and that it doesn't affect other
   *       BOIs which are used in other processes
   * </ul>
   */
  @Test
  public void checkFilteringOnBusinessObjectAttrChange() {
    // setup
    final int customerIdOffset = 100;
    final int customerCount = 3;
    for (int customerId = 1; customerId <= customerCount; customerId++) {
      ProcessInstance pi =
          sf.getWorkflowService()
              .startProcess(new QName(MODEL_NAME2, "DistributedOrder").toString(), null, true);
      List<ActivityInstance> w = getWorklist(pi);
      Assert.assertEquals("worklist", 1, w.size());
      ActivityInstance ai = w.get(0);
      Assert.assertEquals("activity instance", "CreateOrder", ai.getActivity().getId());
      Map<String, Object> order = CollectionUtils.newMap();
      order.put("date", new Date());
      order.put("customerId", customerIdOffset + customerId);
      order.put("items", "item " + customerId);
      ai =
          complete(
              ai, PredefinedConstants.DEFAULT_CONTEXT, Collections.singletonMap("Order", order));

      try {
        ActivityInstanceStateBarrier.instance().await(ai.getOID(), ActivityInstanceState.Completed);
      } catch (Exception e) {
      }
    }

    // after DistributeCreation activity is completed we have the following state:
    // * 2 asynchronous subprocesses are started: one which copies the data and the
    //   other one which doesn't
    // * 3 synchronous subprocesses are triggered: one with shared data, one with separate
    //   but copied data and the last one with separate data without copying
    // This results into the following state:
    // * Each process has created four business object instances
    //   * One which is attached to a synthetic process instance
    //   * 3 other BOIs which are attached to a real process instance
    String businessObjectQualifiedId = new QName(MODEL_NAME2, "Order").toString();
    BusinessObjectQuery businessObjectQuery =
        BusinessObjectQuery.findForBusinessObject(businessObjectQualifiedId);
    businessObjectQuery
        .getFilter()
        .addAndTerm()
        .add(DataFilter.greaterThan("Order", "customerId", customerIdOffset));
    businessObjectQuery.setPolicy(
        new BusinessObjectQuery.Policy(
            BusinessObjectQuery.Option.WITH_VALUES, BusinessObjectQuery.Option.WITH_DESCRIPTION));
    BusinessObjects bos = sf.getQueryService().getAllBusinessObjects(businessObjectQuery);
    Assert.assertEquals("Only one business object, namely Order, is expected", 1, bos.getSize());
    Assert.assertEquals(
        "Business object instances count isn't the same as started process ergo the count of the synthetic process instances",
        customerCount,
        getTotalSize(bos));

    // Wait that all ShowOrder processes are started (unfortunately we cannot use
    // ProcessInstanceStateBarrier here
    // because of the async processes.
    ProcessInstanceQuery piQuery = ProcessInstanceQuery.findAlive("ShowOrder");
    boolean waitForPIs = true;
    while (waitForPIs) {
      long instanceCount = sf.getQueryService().getProcessInstancesCount(piQuery);
      waitForPIs = instanceCount != (customerCount * 5);

      if (waitForPIs) {
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
        }
      }
    }

    BusinessObject bo = bos.get(0);
    BusinessObject.Value customer101 = null;
    for (BusinessObject.Value boValue : bo.getValues()) {
      Map<?, ?> boAttr = (Map<?, ?>) boValue.getValue();
      Integer customerId = (Integer) boAttr.get("customerId");
      if (Integer.valueOf(customerIdOffset + 1).equals(customerId)) {
        customer101 = boValue;
      }
    }
    Assert.assertNotNull("Customer " + customerIdOffset + 1 + " not found", customer101);

    // Update BOI via API...
    ((Map) customer101.getValue()).put("items", "newitems");
    sf.getWorkflowService()
        .updateBusinessObjectInstance(businessObjectQualifiedId, customer101.getValue());

    // ...and validate if no process data is modified
    piQuery = ProcessInstanceQuery.findActive();
    FilterTerm filter = piQuery.getFilter().addAndTerm();
    filter.add(
        DataFilter.between(
            "Order", "customerId", customerIdOffset, customerIdOffset + customerCount));
    filter.add(DataFilter.like("Order", "items", "item%"));
    filter.addAndTerm().add(ProcessInstanceHierarchyFilter.ROOT_PROCESS);
    piQuery.setPolicy(SubsetPolicy.UNRESTRICTED);
    ProcessInstances rootPIs = sf.getQueryService().getAllProcessInstances(piQuery);
    // Root process instances are the DistributedOrder processes and the ShowOrder processes which
    // was started
    // as async processes and which had copied the data
    Assert.assertEquals(
        "Changes in BOIs must not be reflected in process instance data",
        customerCount * 2,
        rootPIs.getTotalCount());

    // Update BOI for a given process via data path...
    long piOid = rootPIs.get(0).getOID();
    ((Map) customer101.getValue()).put("items", "newitems1");
    sf.getWorkflowService().setOutDataPath(piOid, "OrderDataPath", (Map) customer101.getValue());

    // ...and validate if the BOI is updated...
    businessObjectQuery =
        BusinessObjectQuery.findWithPrimaryKey(
            businessObjectQualifiedId, ((Map) customer101.getValue()).get("customerId"));
    businessObjectQuery.setPolicy(
        new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
    bos = sf.getQueryService().getAllBusinessObjects(businessObjectQuery);
    Assert.assertEquals("Only one business object, namely Order, is expected", 1, bos.getSize());
    List<BusinessObject.Value> boValues = bos.get(0).getValues();
    Assert.assertEquals(1, boValues.size());
    Assert.assertEquals("newitems1", ((Map) boValues.get(0).getValue()).get("items"));

    // ...but the other process instance data should be untouched
    piQuery = ProcessInstanceQuery.findActive();
    filter = piQuery.getFilter().addAndTerm();
    filter.add(
        DataFilter.between(
            "Order", "customerId", customerIdOffset, customerIdOffset + customerCount));
    filter.add(DataFilter.like("Order", "items", "item%"));
    filter.addAndTerm().add(ProcessInstanceHierarchyFilter.ROOT_PROCESS);
    piQuery.setPolicy(SubsetPolicy.UNRESTRICTED);
    rootPIs = sf.getQueryService().getAllProcessInstances(piQuery);
    Assert.assertEquals(
        "Changes in BOIs must not be reflected in process instance data",
        (customerCount * 2) - 1,
        rootPIs.getTotalCount());
  }
 private void createEmployee(String bo, String id, String name) {
   final Map<String, Object> fund = CollectionUtils.newMap();
   fund.put("EmpID", id);
   fund.put("EmpName", name);
   sf.getWorkflowService().createBusinessObjectInstance(bo, (Serializable) fund);
 }