Package nexj.core.meta.workflow

Source Code of nexj.core.meta.workflow.Workflow

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.meta.workflow;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import nexj.core.meta.Attribute;
import nexj.core.meta.Event;
import nexj.core.meta.Member;
import nexj.core.meta.Metaclass;
import nexj.core.meta.Metadata;
import nexj.core.meta.MetadataException;
import nexj.core.meta.MetadataLookupException;
import nexj.core.scripting.Compiler;
import nexj.core.scripting.CompilerException;
import nexj.core.scripting.Function;
import nexj.core.scripting.Machine;
import nexj.core.scripting.PCodeFunction;
import nexj.core.scripting.Pair;
import nexj.core.scripting.Symbol;
import nexj.core.util.EmptyIterator;
import nexj.core.util.HashTab2D;
import nexj.core.util.Lookup2D;

/**
* Workflow metadata.
*/
public final class Workflow extends Flow implements Handler
{
   // constants

   /**
    * The empty association.
    */
   protected final static Pair EMPTY_ASSOC = new Pair(null);

   // associations

   /**
    * The containing metaclass.
    */
   protected Metaclass m_metaclass;

   /**
    * The attribute list for primary object retrieval.
    */
   protected Pair m_attributes;

   /**
    * The association collection.
    */
   protected List m_associationList; // of type Attribute

   /**
    * The action event.
    */
   protected Event m_event;

   /**
    * The condition.
    */
   protected Object m_condition;

   /**
    * Map of event objects to scripting functions implementing the state management: Function[Event][Association].
    * On the first pass it maps the event objects to cond code: Object[Event][Association].
    */
   protected Lookup2D m_functionMap = new HashTab2D();

   // constructors

   /**
    * Constructs the workflow.
    * @param sName The workflow name.
    */
   public Workflow(String sName)
   {
      super(sName);
   }
  
   // operations

   /**
    * @see nexj.core.meta.workflow.Flow#getMetadata()
    */
   public Metadata getMetadata()
   {
      return m_metaclass.getMetadata();
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getPropName()
    */
   public String getPropName()
   {
      return "workflow";
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getTypeName()
    */
   protected String getTypeName()
   {
      return "Workflow";
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getURLPrefix()
    */
   protected String getURLPrefix()
   {
      return "workflow:";
   }

   /**
    * Sets the containing metaclass.
    * @param metaclass The containing metaclass to set.
    */
   public void setMetaclass(Metaclass metaclass)
   {
      verifyNotReadOnly();
      m_metaclass = metaclass;
   }

   /**
    * @return The containing metaclass.
    */
   public Metaclass getMetaclass()
   {
      return m_metaclass;
   }

   /**
    * Sets the attribute list for primary object retrieval.
    * @param attributes The attribute list for primary object retrieval to set.
    */
   public void setAttributes(Pair attributes)
   {
      verifyNotReadOnly();
      m_attributes = attributes;
   }

   /**
    * @return The attribute list for primary object retrieval.
    */
   public Pair getAttributes()
   {
      return m_attributes;
   }
  
   /**
    * @see Flow#isCurrentVersion()
    */
   public boolean isCurrentVersion()
   {
      return m_metaclass.getMetadata().getWorkflow(getName()).getVersion() == m_nVersion;
   }

   /**
    * Adds a new association to the action.
    * @param association The association to add.
    */
   public void addAssociation(Attribute association)
   {
      verifyNotReadOnly();

      if (association.getReverse() == null)
      {
         throw new MetadataException("err.meta.workflow.association",
            new Object[]{association.getName(), association.getMetaclass().getName(), getFullName()});
      }
     
      if (association.getReverse().isCollection())
      {
         throw new MetadataException("err.meta.workflow.associationMultiplicity",
            new Object[]{association.getName(), association.getMetaclass().getName(), getFullName()});
      }

      if (m_associationList == null)
      {
         m_associationList = new ArrayList(4);
      }
     
      m_associationList.add(association);
   }

   /**
    * Gets a association by ordinal number.
    * @param nOrdinal The association ordinal number (0-based).
    * @return The association object.
    */
   public Attribute getAssociation(int nOrdinal)
   {
      return (Attribute)m_associationList.get(nOrdinal);
   }

   /**
    * @return The association count.
    */
   public int getAssociationCount()
   {
      if (m_associationList == null)
      {
         return 0;
      }
     
      return m_associationList.size();
   }

   /**
    * @return An iterator for the contained association objects.
    */
   public Iterator getAssociationIterator()
   {
      if (m_associationList == null)
      {
         return EmptyIterator.getInstance();
      }

      return m_associationList.iterator();
   }

   /**
    * @return The target class of the event.
    */
   public Metaclass getTarget()
   {
      if (m_associationList != null)
      {
         return (Metaclass)((Attribute)m_associationList.get(m_associationList.size() - 1)).getType();
      }

      return m_metaclass;
   }

   /**
    * Sets the action event.
    * @param sName The event name.
    * @param nArgCount The event argument count.
    */
   public void setEvent(String sName, int nArgCount)
   {
      if (nArgCount < 0)
      {
         throw new MetadataException("err.meta.workflow.negativeEventArgCount",
            new Object[]{sName, getFullName()});
      }

      Member member = getTarget().getSelector(sName).getMember(nArgCount);

      if (!(member instanceof Event))
      {
         throw new MetadataException("err.meta.workflow.invalidEvent",
            new Object[]{sName, member.getMetaclass().getName(), getFullName()});
      }

      setEvent((Event)member);
   }

   /**
    * Sets the action event.
    * @param event The action event to set.
    */
   public void setEvent(Event event)
   {
      verifyNotReadOnly();

      if (event != null)
      {
         if (event.isStatic())
         {
            throw new MetadataException("err.meta.workflow.staticActionEvent",
               new Object[]{event.getName(), event.getMetaclass().getName(),
                  getFullName(), m_metaclass.getName()});
         }
      }
     
      m_event = event;
   }

   /**
    * @return The action event.
    */
   public Event getEvent()
   {
      return m_event;
   }
  
   /**
    * Sets the condition.
    * @param condition The condition to set.
    */
   public void setCondition(Object condition)
   {
      verifyNotReadOnly();
      m_condition = condition;
   }

   /**
    * @return The condition.
    */
   public Object getCondition()
   {
      return m_condition;
   }

   /**
    * Adds a state management function code to the flow.
    * @param step The step that provides the code.
    * @param assoc The association path to the instance handling the event.
    * @param event The event, which is handled by the function.
    * @param code The function code.
    */
   public void addFunction(Step step, Pair assoc, Event event, Object code)
   {
      verifyNotReadOnly();

      if (assoc == null)
      {
         assoc = EMPTY_ASSOC;
      }

      m_functionMap.put(event, assoc, new Pair(code, m_functionMap.get(event, assoc)));
      setPosURLs(code, step.getName());
   }

   /**
    * Gets a state management function list for a given event.
    * @param assoc The association path to the instance handling the event.
    * @param event The event for which to get the function.
    * @return The state management function list.
    */
   public Pair getFunctions(Pair assoc, Event event)
   {
      if (assoc == null)
      {
         assoc = EMPTY_ASSOC;
      }

      return (Pair)m_functionMap.get(event, assoc);
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getEmptyFunction()
    */
   public PCodeFunction getEmptyFunction()
   {
      return Machine.EMPTY_FUNCTION;
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getDefaultReturnCode()
    */
   public Pair getDefaultReturnCode()
   {
      return null;
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getArgument(int)
    */
   public Variable getArgument(int nOrdinal)
   {
      throw new ArrayIndexOutOfBoundsException();
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getArgument(java.lang.String)
    */
   public Variable getArgument(String sName) throws MetadataLookupException
   {
      throw new MetadataLookupException("err.meta." + getPropName() + ".argLookup", sName, this);
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getArgumentCount()
    */
   public int getArgumentCount()
   {
      return 0;
   }

   /**
    * @see nexj.core.meta.workflow.Flow#getArgumentIterator()
    */
   public Iterator getArgumentIterator()
   {
      return EmptyIterator.getInstance();
   }

   /**
    * @see nexj.core.meta.workflow.Flow#generate(nexj.core.scripting.Machine)
    */
   protected void generate(Machine machine)
   {
      // Generate the flow startup action for the latest version of the flow
      if (m_event != null && isCurrentVersion())
      {
         m_event.addFlowStarter(this);
      }

      super.generate(machine);

      generateDeleteFlowAction(m_metaclass.findEvent("delete", 0));
   }
  
   /**
    * @see nexj.core.meta.workflow.Flow#compile(nexj.core.scripting.Machine)
    */
   protected void compile(Machine machine) throws CompilerException
   {
      Lookup2D map = new HashTab2D(m_functionMap.size());

      // Compile the flow functions
      for (Lookup2D.Iterator itr = m_functionMap.valueIterator(); itr.hasNext();)
      {
         itr.next();

         Event event = (Event)itr.getKey1();
         Pair body = (Pair)machine.invoke((Function)machine.getGlobalEnvironment()
            .getVariable(Symbol.SYS_GENERATE_FLOW_FUNCTION), itr.getValue(), (Object[])null);

         itr.setValue(new Pair(new Compiler().compile(m_variables,
            event.getArguments(true), body, m_posMap, m_urlMap, machine)));
         map.put(event.getRoot(), itr.getKey2(), null);
      }

      for (Lookup2D.Iterator itr = map.valueIterator(); itr.hasNext();)
      {
         itr.next();

         addDerivedFlowFunctions((Pair)itr.getKey2(), (Event)itr.getKey1(),
            (Pair)m_functionMap.get(itr.getKey1(), itr.getKey2()));
      }
   }

   /**
    * Adds the flow functions from an event to its derived events.
    * @param assoc The association path to the instance handling the event.
    * @param event The event.
    * @param pair The flow function list.
    */
   protected void addDerivedFlowFunctions(Pair assoc, Event event, Pair pair)
   {
      Metaclass metaclass = event.getMetaclass();
     
      for (int i = 0, nCount = metaclass.getDerivedCount(); i < nCount; ++i)
      {
         Event derived = metaclass.getDerived(i).findEvent(event.getName(), event.getArgumentCount());
         Pair dpair = (Pair)m_functionMap.get(derived, assoc);
        
         if (pair != null)
         {
            dpair = Pair.append(pair, dpair);
            m_functionMap.put(derived, assoc, dpair);
         }

         addDerivedFlowFunctions(assoc, derived, dpair);
      }
   }

   /**
    * Generates a delete flow action in the delete event
    * of the associated class and its subclasses.
    * @param event The delete event.
    */
   protected static void generateDeleteFlowAction(Event event)
   {
      if (event == null)
      {
         return;
      }
     
      if (event.generateDeleteFlowAction())
      {
         Metaclass metaclass = event.getMetaclass();
        
         for (int i = 0, nCount = metaclass.getDerivedCount(); i < nCount; ++i)
         {
            generateDeleteFlowAction(metaclass.getDerived(i).findEvent(event.getName(), event.getArgumentCount()));
         }
      }
   }
}
TOP

Related Classes of nexj.core.meta.workflow.Workflow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.