Implementing an Assembly Line Activity Provider

The logic to decide which assembly line has to be activated next is implemented via an assembly line activity provider class, which has to implement the interface IAssemblyLineActivityProvider. The following class, which is used as default provider class for the Infinity Process Platform portal, illustrates an example implementation:

package org.eclipse.stardust.ui.web.processportal.common;

import java.util.Iterator;
import java.util.Set;

import org.eclipse.stardust.ui.web.processportal.spi.IAssemblyLineActivityProvider;

import org.eclipse.stardust.common.CompareHelper;
import org.eclipse.stardust.common.error.ConcurrencyException;
import org.eclipse.stardust.engine.api.web.jsf.common.AbstractProcessExecutionPortal;
import org.eclipse.stardust.engine.api.web.jsf.common.PortalException;
import org.eclipse.stardust.engine.api.model.ConditionalPerformer;
import org.eclipse.stardust.engine.api.model.ModelParticipant;
import org.eclipse.stardust.engine.api.model.Participant;
import org.eclipse.stardust.engine.api.query.ParticipantWorklist;
import org.eclipse.stardust.engine.api.query.PerformingParticipantFilter;
import org.eclipse.stardust.engine.api.query.SubsetPolicy;
import org.eclipse.stardust.engine.api.query.UserWorklist;
import org.eclipse.stardust.engine.api.query.Worklist;
import org.eclipse.stardust.engine.api.query.WorklistQuery;
import org.eclipse.stardust.engine.api.runtime.ActivityInstance;
import org.eclipse.stardust.engine.api.runtime.WorkflowService;

/**
 * Default implementation of assembly line contract.
 * 
 * The order of the next pending assembly line activity is not predictable
 * but you get at first the activities from the user worklist and after
 * that from the participant worklist.
 * 
 * @see org.eclipse.stardust.ui.web.client.common.spi.IAssemblyLineActivityProvider
 * @author rsauer
 * @version $Revision: 31069 $
 */
public class DefaultAssemblyLineActivityProvider implements IAssemblyLineActivityProvider
{

   private WorklistQuery createWorklistQuery(Set participantIds, boolean outline)
   {
      WorklistQuery query = new WorklistQuery();
      query.setUserContribution(SubsetPolicy.UNRESTRICTED);
      for (Iterator i = participantIds.iterator(); i.hasNext();)
      {
         String participantId = (String) i.next();
         query.setParticipantContribution(
               PerformingParticipantFilter.forModelParticipant(participantId, false),
               outline ? new SubsetPolicy(0, true) : null);
      }
      return query;
   }
   
   private boolean isAssemblyLineActivity(Set assemblyLineParticipants, ActivityInstance ai)
   {
      ModelParticipant modelParticipant = ai.getActivity().getDefaultPerformer();
      
      if(modelParticipant != null)
      {
         String aiParticipantId = modelParticipant.getId();
         if(modelParticipant instanceof ConditionalPerformer)
         {
            ConditionalPerformer cp = (ConditionalPerformer)modelParticipant;
            Participant rp = cp.getResolvedPerformer();
            if (rp instanceof ModelParticipant)
            {
               aiParticipantId = rp.getId();
            }
         }
         if(assemblyLineParticipants != null)
         {
            for (Iterator patIter = assemblyLineParticipants.iterator(); patIter.hasNext();)
            {
               String participantId = (String) patIter.next();
               if(CompareHelper.areEqual(participantId, aiParticipantId))
               {
                  return true;
               }
            }
         }
      }
      return false;
   }
   
   public ActivityInstance getNextAssemblyLineActivity(
         AbstractProcessExecutionPortal portal, Set participantIds) throws PortalException
   {
      ActivityInstance result = null;

      WorkflowService ws = portal.getWorkflowService();
      if(ws != null)
      {
         Worklist wl = ws.getWorklist(
               createWorklistQuery(participantIds, false));
   
         for (Iterator i = wl.getCumulatedItems().iterator(); i.hasNext() && result == null;)
         {
            ActivityInstance ai = (ActivityInstance) i.next();
            if(isAssemblyLineActivity(participantIds, ai))
            {
               try
               {
                  // lock activity
                  ws.activate(ai.getOID());
      
                  result = ai;
                  break;
               }
               catch (ConcurrencyException ce)
               {
                  continue;
               }
            }
         }
      }
      return result;
   }

   public long getAssemblyLineActivityCount(AbstractProcessExecutionPortal portal,
         Set participantIds) throws PortalException
   {
      WorkflowService ws = portal.getWorkflowService();
      Worklist worklist = ws != null ? ws.getWorklist(
            createWorklistQuery(participantIds, true)) : null;
      long activityCount = 0;
      if(worklist != null)
      {
         if(worklist instanceof UserWorklist)
         {
            for(Iterator aiIter = worklist.iterator(); aiIter.hasNext();)
            {
               ActivityInstance ai = (ActivityInstance)aiIter.next();
               if(isAssemblyLineActivity(participantIds, ai))
               {
                  activityCount += 1;
               }
            }
         }
         Iterator worklistIter = worklist.getSubWorklists();
         while (worklistIter.hasNext())
         {
            worklist = (Worklist) worklistIter.next();
            if (worklist instanceof ParticipantWorklist)
            {
               activityCount += worklist.getTotalCount();
            }
         }
      }
      return activityCount;
   }
}

The property Carnot.ProcessPortal.AssemblyLineActivityProvider determines the provider class to use. Per default, this is set to:

Carnot.ProcessPortal.AssemblyLineActivityProvider = 
    org.eclipse.stardust.ui.web.processportal.common.DefaultAssemblyLineActivityProvider

In case you created a custom implementation class, change the value accordingly.

Implementing Activity Criticality with Assembly Line Provider

The org.eclipse.stardust.ui.web.processportal.common.CriticalityAwareAssemblyLineActivityProvider class uses the given criticality formula to order the worklist. The property Carnot.ProcessPortal.AssemblyLineActivityProvider in carnot.properties should point to this class instead of DefaultAssemblyLineActivityProvider. To use the given criticality criteria to order the worklist, following property should be set in the Carnot.properties file:

Carnot.ProcessPortal.AssemblyLineActivityProvider = org.eclipse.stardust.ui.web.processportal.
common.CriticalityAwareAssemblyLineActivityProvider