/**
   * 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());
  }
 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;
 }
  private static void addActivity(
      Set<TransitionTarget> visited,
      List<TransitionTarget> targets,
      IActivity target,
      TransitionOptions options,
      boolean forward,
      Stack<TransitionStep> steps) {
    TransitionTarget candidate =
        TransitionTargetFactory.createTransitionTarget(target, steps, forward);
    if (!visited.add(candidate)) {
      // target already visited, stop processing
      return;
    }
    if (target.getBooleanAttribute(PredefinedConstants.ACTIVITY_IS_RELOCATE_TARGET_ATT)) {
      // found a relocation target, check filters
      String processIdPattern = options.getProcessIdPattern();
      if (processIdPattern == null
          || target.getProcessDefinition().getId().matches(processIdPattern)) {
        String activityIdPattern = options.getActivityIdPattern();
        if (activityIdPattern == null || target.getId().matches(activityIdPattern)) {
          targets.add(candidate);
        }
      }
    }

    if (options.isTransitionIntoSubprocessesAllowed()
        && target.getImplementationType() == ImplementationType.SubProcess
        && target.getSubProcessMode() != SubProcessModeKey.ASYNC_SEPARATE) {
      IProcessDefinition process = target.getImplementationProcessDefinition();
      if (process != null) {
        steps.push(TransitionTargetFactory.createTransitionStep(target));
        addActivities(visited, targets, process, options, forward, steps);
        steps.pop();
      }
    }

    addActivities(visited, targets, target, options, forward, steps);
  }
  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;
  }