@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);
  }
  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);
  }
  /**
   * 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");
  }
 /** Test if a field, other than the primary key, of a BO instance can be modified. */
 @Test
 public void ModifyOrdersCheck() {
   DeployedModelDescription model =
       sf.getQueryService().getModels(DeployedModelQuery.findActiveForId(MODEL_NAME2)).get(0);
   BusinessObject bo = createOrder(model, 777);
   @SuppressWarnings("unchecked")
   final Map<String, Object> order = (Map<String, Object>) bo.getValues().get(0).getValue();
   Date date = (Date) order.get("date");
   order.put("date", new Date(date.getTime() + TIME_LAPSE));
   sf.getWorkflowService()
       .updateBusinessObjectInstance(
           new QName(model.getId(), "Order").toString(), (Serializable) order);
   BusinessObjectQuery query =
       BusinessObjectQuery.findWithPrimaryKey(new QName(model.getId(), "Order").toString(), 777);
   query.setPolicy(new BusinessObjectQuery.Policy(BusinessObjectQuery.Option.WITH_VALUES));
   BusinessObjects bos = sf.getQueryService().getAllBusinessObjects(query);
   bo = bos.get(0);
   @SuppressWarnings("unchecked")
   Map<String, Object> updatedOrder = (Map<String, Object>) bo.getValues().get(0).getValue();
   Date updatedDate = (Date) updatedOrder.get("date");
   Assert.assertEquals("Time difference", TIME_LAPSE, updatedDate.getTime() - date.getTime());
 }
 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);
 }
  /**
   * 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());
  }