Erweiterte Programmierung


In diesem Kapitel lernen Sie wie man Klassen für die dynamische Instanziierung programmiert (Workflows). Bevor Sie hier weiterlesen, machen Sie sich bitte zuerst mit Workflows aus Anwendersicht vertraut.

Das folgende Klassendiagramm ist eine Erweiterung des Klassendiagramms für Prozessanwendungen aus dem vorigen Kapitel:

 

Workflowklassen lassen sich nach verschiedenen Aspekten kategorisieren:

  1. Gruppierfähigkeit:
    Workflowklassen, die die Schnittelle "IACComponentPWGroup" implementieren, können Kind-Workflowknoten besitzen. Sie werden graphisch als ein Rahmen dargestellt. Die Klassen PWProcessFunction und PWGroup implementieren diese Schnittstelle. Die Klasse PWProcessFunction oder eine Ihrer Ableitungen repräsentieren immer den Wurzel-Workflowknoten. Die Klasse PWGroup oder eine Ihrer Ableitungen dienen zur Belegung eines Prozessmoduls (bzw. Ressource).
  2. Programmfluss:
    Workflowknoten arbeiten Ereignisgesteuert durch die Verwendung von Ereignispunkten. Workflowknoten, die einen oder mehrere ACPointEvent-Punkte besitzen (Sender), implementieren die Schnittstelle IPWNodeOut. Workflowknoten, die einen oder mehrere Abonnement-Punkte (IACPointEventSubscr, Empfänger) besitzen, implementieren die Schnittstelle IPWNodeIn. Mittels grafischer Programmierung des Workflows werden diese mittels Kanten verbunden. Eine Kante ist im Prinzip eigentlich nur eine Abonnierung eines EventPunktes die beim Laden des Workflows stattfindet.  Wenn ein Workflowknoten seine Arbeit erledigt hat, löst er mit seinem ACPointEvent-Punkt das Ereignis aus und benachrichtigt seine Empfänger. Somit stellt sich indirekt ein Programmfluss ein.
  3. Zustandsgesteuert:
    Manche Workflowknoten die gestartet werden können Ihre Aufgabe unmittelbar durchführen und sofort Ihre Ausgangspunkte auslösen. Andere dagegen müssen eine bestimmte Zeit verharren, bis Ihre Aufgabe abgeschlossen ist. Das sind Workflowklassen, die Ableitungen von PWBaseExecutable sind. Ist ein umfangreicherer Zustandsautomat notwendig entsprechend den S88-Hauptzuständen, dann müssen Workflowklassen verwendet werden, die Ableitungen von PWBaseNodeProcess sind.
  4. Delegation an Funktionen
    Workflowknoten, die Ihre Aufgaben nicht selbst erledigen können und Funktionen im physikalischen Modell aufrufen müssen, sind Ableitungen von PWNodeProcessMethod.

 


PWBase ist abgeleitet von PABase und ist die Basisklasse aller Workflowklassen. Sie übernimmt folgende Aufgaben:

  1. Initialisierung einer Workflowinstanz auf Grundlage der Workflowbeschreibung mittels der Tabellen ACClassMethod, ACClassWF und ACClassWFEdge. Bei der Initialisierung werden auch die Ereignispunkte miteinander verbunden.
  2. Protokollierung des Programmflusses in die ACProgramLog-Tabelle. Immer wenn ein Workflowknoten gestartet wird, wird ein Eintrag in die ACProgramLog-Tabelle geschrieben. ACProgramLog enthält Informationen über den Start- und Endezeitpunkt, das Vorgänger-ProgramLog (ParentProgramLog) und die Konfigurations- und Ergebnisparameter (ACMethod) mit denen der Workflowknoten gearbeitet hat. Der Programmfluss kann im Nachhinein mit dem ProgramLog-Presenter abgeschaut werden. ACProgramLogs verweisen auf ein ACProgram der beim Starten eines Workflows  generiert wird.
  3. Suchfunktionen für Workflowknoten innerhalb eines Workflows.

 

Dynamische Erweiterung des Anwendungsbaums

Workflowklassen werden erst während der Laufzeit instanziiert und in den Anwendungsbaum geladen. Damit bei einem Neustart des iPlus-Dienstes auch diese Workflowinstanzen wiederhergestellt werden können, wird der Anwendungsbaum in der Tabelle ACClassTask gespeichert. Auf das ACClassTask-Entity-Objekt können Sie über die Eigenschaft "Content" zugreifen, die bereits im Abschnitt zur "Programmierung einer ACComponent" erklärt worden ist.
Wenn der Programmfluss das Ende des Workflows erreicht hat, werden die Instanzen (Workflowknoten) aus dem Anwendungsbaum entladen und die entsprechenden ACClassTask-Einträge gelöscht.

Bei der Instanziierung einer Workflowklasse wird der ACIdentifier in der überschriebenen Methode InitACIdentifier() gesetzt. Der ACIdentifier wird mit dem ACIdentifier des ACClassWF-Tabelleneintrags gesetzt (ACClassWF-Einträge entstehen beim Editieren des Workflows mit dem graphischen Editor). Nur der ACIdentifier des Wurzelknotens, der eine Ableitung der Klasse PWProcessFunction ist, bekommt zusätzlich eine fortlaufende Instanznummer

Im folgenden Bild erhält Wurzelknoten (F) den ACIdentifier "MixeryDef(1)". Der zweite Wurzelknoten, der aus derselben Workflow-Vorlage geladen wurde, erhält den ACIdentifier "MixeryDef(2)". In der Prozesssteuerung werden diese fortlaufenden Instanznummern rechts unten in der Spalte "ID"  des Datagrids (3) angezeigt:

 

Konfiguration

PWBase implementiert die Schnittstelle IACComponentPWNode:

public interface IACComponentPWNode : IACComponent, IACObjectDesign, IACConfigURL, IACConfigStoreSelection, IACConfigMethodHierarchy

IACComponentPWNode ist so deklariert, dass auch die Schnittstellen IACConfigUrl, IACConfigStoreSelection und IACConfigMethodHierarchy implementiert werden müssen, damit eine Workflowklasse vollständig konfigurationsfähig ist und das Lesen von überschriebenen Konfgurationsspeichern unterstützt. Um die Parameterliste einer virtuellen Methode zu befüllen stellt PWBase folgende Methode zur Verfügung:

public virtual bool GetConfigForACMethod(ACMethod paramMethod, bool isForPAF, params Object[] acParameter)

Ableitungen, die entweder die Konfigurationsparameter der Workflowklasse selbst oder die Parameter für einen Funktionsaufruf befüllt haben möchten, rufen diese Methode auf.

  

Eigenschaften

NameBeschreibung
IACObject Content

Gibt das ACClassTask-Objekt (Entity-Framework) zurück das zur Speicherung des Anwendungsbaums dient.

ACClassWF ContentACClassWFReferenz auf die Definition des Workflowknotens. (Entsteht bei der graphischen Editierung des Workflows)

PWProcessFunction RootPW

IACComponentPWNode ParentRootWFNode

Referenz auf den Wurzelknoten des geladenen Workflows. Ist die Instanz selbst ein Wurzelknoten, dann wird der this-Zeiger zurückgegeben.
IACComponentPWGroup GroupPWComponentGibt den "umgebenden" Workflowgruppenknoten zurück, zu dem dieser Knoten gehört.
IACWorkflowContext WFContextGibt eine ACProgram-Instanz zurück (ContentTask.ACProgram), damit die Konfigurationsdaten gelesen und gespeichert werden können.
ACProgramLog CurrentProgramLogAktueller Log des Workflowknotens.
IEnumerable<ACProgramLog> PreviousProgramLogsVergangene Logs des Workflowknotens.
ACProgramLog ParentProgramLogLog des Eltern-Knotens.
ACProgramLog PreviousParentProgramLogVergangener Log des Eltern-Knotens.
string ConfigACUrlACUrl für den Zugriff der IACConfig-Einträge von einem IACConfigProvider.
string PreValueACUrlACUrl des Aufrufers.
List<ACClassMethod> ACConfigMethodHierarchyHierarchie der Sub-Workflowaufrufe.
List<IACConfigStore> MandatoryConfigStoresÜberschreibungsfolge der Konfigurationsspeicher.

 

Suchfunktionen

Bei der Programmierung einer eigenen Workflowklasse ist es manchmal notwendig zu wissen wie der Endanwender den Workflow erstellt hat. Konkret bedeutet dies, dass man vom ausgehenden Knoten die "Umgebung" erkunden will welche Vorgänger und Nachfolgeknoten es gibt. Dazu dienen folgende Methoden:

public List<TResult> FindPredecessors<TResult>(bool inSameGroup, Func<PWBase, bool> selector, Func<PWBase, bool> deselector = null, int maxRecursionDepth = 0) 
where TResult : PWBase

public List<TResult> FindSuccessors<TResult>(bool inSameGroup, Func<PWBase, bool> selector, Func<PWBase, bool> deselector = null, int maxRecursionDepth = 0)
where TResult : PWBase

Verwenden Sie diese Methoden wie die Suchfunktionen der ACComponent-Klasse. Im Gegensatz zu den Suchfunktionen der ACComponent-Klasse, die innerhalb des  Anwendungsbaums suchen (Parent/Child), suchen die Workflow-Suchfunktionen über die Kanten des Workflows. Technisch gesehen, durchlaufen Sie die Verweise (ConnectionList) der Ereignispunkte und selektieren die Elemente, die der übergebene selector-Delegat (Suchbedingung) gefunden hat. Mit dem deselector-Delegaten brechen Sie die weitere Suche ab.

Anwendungsbeispiel:

PWNodeCheckWeighing checkWeighing = this.FindSuccessors<PWNodeCheckWeighing>(false, c => c is PWNodeCheckWeighing, null, 1).FirstOrDefault();

 


Eine PWProcessFunction (Workflow-Prozessfunktion) repräsentiert den Wurzelknoten eines geladenen Workflows. Jedem neuen geladenen Workflow, der dynamisch zum Anwendungsbaum hinzugefügt wird, wird der ACIdentifier der Instanz mit einer fortlaufenden Instanznummer ergänzt. Lesen Sie dazu den vorigen Abschnitt "PWBase" durch.

 

Starten von Workflows

PWProcessFunction implementiert die Schnittstelle IACComponentProcessFunction und ist daher vergleichbar mit einer gewöhnlichen Prozessfunktion, weil diese durch einen asynchronen Aufruf der Start()-Methode aktiviert werden kann. Im Gegensatz zu einer Funktion, die statisch im physikalischen Modell deklariert und instanziiert wird, wird die Workflow-Prozessfunktion dynamisch instanziiert, indem die "ACComponent.StartWorkflow()"-Methode aufgerufen wird. StartWorkflow() ist nur eine besondere Form eines Methodenaufrufs, bei der der Methodenname dem Workflownamen entspricht, der bei der grafischen Erstellung vergeben worden ist.

Da Workflows andere Unterworkflows aufrufen können, werden diese ebenfalls per StartWorkflow() geladen; nur mit dem Unterschied das dies automatisch durch die Workflowklasse "PWNodeProcessWorkflow" erfolgt. Der asynchrone Aufruf kann über die Eigenschaft public ACPointAsyncRMIWrap<ACComponent> CurrentTask abgefragt werden. Wie auch bei gewöhnlichen Prozessfunktionen findet der asynchrone Aufruf über die ParentACComponent statt, die IACComponentTaskExec implementiert. Bei gewöhnlichen Prozessfunktionen ist es das Prozessmodul, bei Workflows ist es die ApplicationManager-Klasse (Wurzel des Anwendungsbaums), weil Workflows immer als Kindelemente des ApplicationManagers hinzugefügt werden und auch die "Methoden" bzw. Workflows dort deklariert werden.

PWProcessFunction ist mit der Atrributklase ACClassConstructorInfo versehen:

[ACClassConstructorInfo( new object[] { 
new object[] {ACProgram.ClassName, Global.ParamOption.Required, typeof(Guid)},
new object[] {ACProgramLog.ClassName, Global.ParamOption.Optional, typeof(Guid)}
} )]

Das bedeutet, dass eine Instanziierung bzw. Konstruktion dieser Klasse dringend einen ACProgram-Tabelleneintrag erfordert. Ein ACProgram ist im übertragenen Sinne vergleichbar mit dem Doppelklick einer Windows-Applikation, bei der ein Programmaufruf (Main-Methode) erfolgt und unter dem alle Aufgaben, die das Programm erledigt protokolliert werden. Die Protokolldaten werden in die Tabelle ACProgramLog geschrieben. Auch Unterprogrammaufrufe (Unterworkflows die gestartet werden) werden unter dem gleichen ACProgram gespeichert. Erst wenn der zuerst gestartete Workflow abgearbeitet und aus dem Anwendungsbaum entladen worden ist, wird ein ACProgram nicht mehr beschrieben und dient nur noch zur späteren Nachverfolgung über den ProgramLog-Viewer.

Folgendes Beispiel zeigt wie ein ACProgram angelegt und ein Workflow gestartet wird (Das Beispiel entstammt der Klasse BSOInOrder aus dem Beispielprojekt):

 

  1. Da Geschäftsobjekte auf Clients verwendet werden, wird am Anfang auf die Proxy-Instanz des Anwendungsmanagers zugegriffen und geprüft ob der Benutzer überhaupt Zugriffsrechte und Verbindung zum Server hat. Danach wird geprüft, ob ein Workflow mit dem Methodennamen "ExampleWorkflow" für den Anwendungsmanager existiert, indem eine Referenz auf ACClassMethod zurückgegeben wird.
  2. Mit dem Aufruf der Methode "NewACMethod()" wird eine ACMethod zurückgegeben, die eine Parameterliste entsprechend der ACClassConstructorInfo-Deklaration enthält.
  3. Ein neues ACProgram-Entity-Objekt sollte über einen eigenständigen Datenbankkontext angelegt werden. Aus diesem Grund muss auch die ACClassMethod-Referenz aus Schritt 1 mittels der Methode FromIPlusContext() aus dem eigenständigen Datenbankkontext geladen werden.
  4. Nun kann ein neues ACProgram-Entity-Objekt angelegt und die ACClassMethod zugewiesen werden.
  5. Speichern Sie die Änderungen.
  6. Wenn der Speichervorgang erfolgreich war, tragen Sie in die Parameterliste die ACProgramID ein. Rufen Sie anschließend die Methode "ExecuteMethod" auf und übergeben die ACMethod. 

Im Schritt 6 wurde zudem ein zweiter Parameter "InOrder" mit der InOrderID gesetzt. Das liegt daran, dass anstatt der PWProcessFunction die abgeleitete Klasse PWProcFuncOrder aus dem Beispielprojekt instanziiert werden soll, die in Ihrer ACClassConstructorInfo-Deklaration diesen zusätzlichen Parameter deklariert hat. Dieser Parameter ist notwendig, damit die Klasse weiß mit welchem Datenkontext Sie arbeiten muss. Beim Anlegen des Workflows muss im Feld "Zu instanziierende Klasse des Wurzelknotens" festgelegt werden, dass PWProcFuncOrder als Root-Klasse verwendet werden soll.

Schauen wir uns nun an wie die Beispielklasse PWProcFuncOrder programmiert wird:

 

Programmierung einer eigenen Klasse

 

  1. Leiten Sie von PWProcessFunction ab. Die ACClassInfo-Attributklasse muss folgendermaßen konstruiert werden:
    1. Verwenden Sie "Global.ACKinds.TPWMethod" um iPlus bekannt zugeben, dass es um eine Workflow-Prozessfunktion handelt.
    2. "Global.ACStorableTypes.Required" muss verwendet werden, weil z.B. die ACState-Eigenschaft persistierbar ist und der Zustand beim Neustart des Dienstes wiederhergestellt werden muss.
  2. Deklarieren Sie ACClassConstructorInfo und fügen zusätzlich den "InOrder"-Parameter hinzu.
  3. Deklarieren einen Execute-Helper für die statischen Aufrufe, indem Sie den statischen Execute-Handler als Delegat der RegisterExecuteHandler()-Methode übergeben.
  4. Überschreiben Sie die Start-Methode.
  5. Prüfen Sie, ob der InOrder-Datenbankeintrag existiert, indem Sie die Hilfsmethode "GetInOrder()" aufrufen. "GetInOrder()" liest den "InOrder"-Parameter aus der Parameterliste, der im Businessobjekt gesetzt worden ist. Setzen Sie zum Schluss die "CurrentInOrder"-Eigenschaft. Sie fungiert als Datenkontext, auf den später alle anderen Workflowknoten zugreifen können. Wenn Sie später Ihre eigene Klasse entwickeln werden, dann wird der Datenkontext eine Ihrer Tabellen sein.
  6. Rufen Sie die Start-Methode aus der Basisklasse auf, um den Ablauf des Workflows zu starten.
  7. Optional können Sie die CanRunWorkflow()-Methode überschreiben, um den Ablauf "anzuhalten" solange noch irgendwelche Bedingungen noch nicht eingetreten sind.
  8. Die LoadEntites()-Methode ist eine Hilfsfunktion um den Datenkontext nach dem Neustart des iPlus-Dienstes wiederherzustellen.
  9. Setzen Sie alle privaten Felder in der ACDeInit()-Methode und der Recycle()-Methode zurück, damit Ihre Klasse poolfähig ist. Poolfähige Workflowklassen sollten immer in den Grundzustand gebracht werden - so wie sie initial bei der Generierung ursprünglich im Heap angelegt worden sind!

 

Eigenschaften

NameBeschreibung
IACContainerTNet<ACMethod> CurrentACMethod

Die virtuelle Methode (ACMethod) mit der dieser Workflow gestartet worden ist.

ACPointAsyncRMIWrap<ACComponent> CurrentTaskWenn der Workflow als Unterworkflow asynchron gestartet worden ist, dann ist diese Eigenschaft gesetzt. Durch Zugriff auf die ValueT-Eigenschaft erhält man eine Referenz auf den Workflowknoten (Klasse PWNodeProcessWorkflow), die den asnychronen Aufruf gestartet hat.

IACComponentTaskExec ParentTaskExecComp

Referenz auf den Anwendungsmanager, der diesen Worklowknoten als Kindinstanz besitzt.
PWNodeStart PWNodeStartStart-Workflowknoten, den diese Funktion startet damit die Workflowabarbeitung startet.
WFDictionary WFDictionaryEin Dictionary die alle Kind-Instanzen dieses Workflowknotens enthält. Der Schlüssel ist ACClassWF.

IACContainerTNet<uint> ACSubState

uint CurrentACSubState

Eine Zustands-Eigenschaft, um neben der ACState-Eingeschaft weitere Unterzustände speichern zu können.

 


 

PWNodeStart

Die Klasse PWNodeStart ist immer der erste Workflow-Knoten (S) innerhalb eines Knotens der die Schnittstelle IACComponentPWGroup implementiert (Das sind die Klassen PWProcessFunction und PWGroup). PWNodeStart implementiert die Schnittstelle IPWNodeOut, die den Ausgangs-Ereignispunkt "PWPointOut" von Typ ACPointEvent spezifiziert. Nachfolgende Knoten innerhalb der Gruppe müssen mit diesem Ereignispunkt verbunden werden. Der Ereignispunkt wird getriggert, wenn die umgebende Gruppe die Start()-Methode aufgerufen hat.

 

PWNodeEnd

Die Klasse PWNodeEnd ist immer der letzte Workflow-Knoten (E) innerhalb eines Knotens der die Schnittstelle IACComponentPWGroup implementiert (Das sind die Klassen PWProcessFunction und PWGroup). PWNodeEnd implementiert die Schnittstelle IPWNodeIn, die den Abbonementpunkt "PWPointIn" von Typ PWPointIn spezifiziert. Der Programmfluss innerhalb einer Gruppe muss so programmiert werden, dass er zwangsläufig in "PWPointIn" endet. PWNodeEnd ruft dann in der zugehörigen Gruppe die Methode GroupComplete() auf die wiederum Ihren Ausgangs-Ereignispunkt auslöst.

 

PWBaseInOut

Die Klasse PWBaseInOut ist eine Kombination aus PWNodeStart und PWNodeEnd. Sie kann sowohl Ereignisse empfangen (Eingangspunkt vom Typ PWPointIn) als auch ein Ausgangsereignis senden (Ausgangspunkt vom Typ ACPointEvent). Sie ist daher die Basisklasse für alle weiteren Workflowklassen.

 

PWPointIn

Die Klasse PWPointIn ist eine spezielle Variante eines Abbonementpunktes, der in der Lage ist anhand der Workflowkanten (Tabelle ACClassWFEdge) die entsprechenden Ereignisse der Ausgangspunkte zu abonnieren. Zudem bietet er Eigenschaften an, um abfragen zu können wie viele Ereignisse bereits gefeuert worden sind und dementsprechend das Ergebnis UND-/ ODER- oder EXUND-Verknüpft zurückzugeben. Eine EXUND-Verknüpfung ist eine Besonderheit in iPlus, die bedeutet, dass nur ein Ausgangsereignis empfangen wurde und alle anderen Ausgangsereignisse wurden nicht gefeuert und die Gruppe des Workflowknotens dem sie angehören ist nicht aktiv.

 

PWNodeOr, PWNodeAnd, PWNodeXAnd

Diese drei Klassen sind Ableitungen von PWBaseInOut und fungieren als logisches Gatter. Sie verwenden die in PWPointIn bereitgestellten Eigenchaften IsActiveAND, IsActiveOR und IsActiveExAND um das logische Gatter zu schalten.

 

PWBaseExecutable erweitert PWBaseInOut, damit ein Workflowknoten konfigurierbar ist. Dabei wird eine ACMethod-Instanz erzeugt und die Parameter mittels der überschreibbaren Konfigurationsspeicher zusammengestellt. Die endgültige Konfiguration wird in den Eigenschaften CurrentACMethod und ExecutingACMethod bereitgestellt.

PWBaseExcecutable ist zudem die Basisklasse für alle Workflowknoten, die eine bestimmte Zeit in den ACState-Zuständen verharren, bis Ihre Aufgabe abgeschlossen ist. Bevor ein Workflowknoten in den "Starting"-Zustand wechselt, kann er durch einen Haltepunkt angehalten werden. Dafür stellt diese Klasse einige Methoden zur Verfügung. Außerdem liest sie beim Starten die Konfigurationsspeicher und setzt den Haltepunkt von alleine.

Alle weiteren Klassen die in den nachfolgenden Abschnitten erklärt werden, sind Ableitungen von PWBaseExecutable:

 

PWGroup ist zum einen eine Ableitung von PWBaseExecutable und zum anderen implementiert sie die Schnittelle "IACComponentPWGroup". Somit ist Sie wie auch PWProcessFunction in der Lage Kind-Workflowknoten zu besitzen. Sie enthält einen Start- und Endeknoten (PWNodeStart und PWNodeEnd) und sollte mindestens einen Knoten vom Typ "PWNodeProcessMethod" enthalten. "PWNodeProcessMethod"-Klassen rufen nämlich Funktionen asynchron im physikalischen Modell auf. Dies dürfen sie allerdings erst dann, wenn das zugehörige Prozessmodul von der PWGroup-Instanz belegt worden ist, indem der "PAProcessModule.Semaphore"-Servicepunkt mit dem "PWGroup.TrySemaphore"-Clientpunkt verbunden wird. Diese Prozessmodulbelegung findet im Zustand "SMStarting" statt und wird, nachdem alle Kind-Workflowknoten abgearbeitet worden sind und der Endeknoten triggert, wieder entfernt. PWGroup wird danach vom Zustand "SMRunning" wieder in den Grundzustand "SMIdle" versetzt.

 

SMStarting-Zustandsmethode

Diese Methode ist eine zyklische Methode, die zyklisch aufgerufen wird, solange sie den Zustandsautomaten nicht in den Zustand SMRunning überführt hat und den Start-Knoten getriggert hat. Bevor der Algorithmus erklärt werden kann, müssen Sie zunächst folgende Eigenschaften einer PWGroup kennenlernen:

(A) PAProcessModule[] PossibleModuleList:
Diese Liste enthält Prozessmodule, die theoretisch von dieser Workflow-Gruppe belegt werden könnten. Es wählt alle Prozessmodule aus, die eine Ableitung einer Klasse  sind, auf die die Eigenschaft "ContentACClassWF.RefPAACClass" verweist. "ContentACClassWF.RefPAACClass" ist ein Verweis auf eine Klasse im Application-Definition-Projekt, die als Basisklasse für die Prozessmodule im physikalischen Modell (Anwendung) dient.

(B) List<PAProcessModule> ProcessModuleList:
ProcessModuleList entfernt Prozessmodule aus PossibleModuleList (A), die sich nicht im automatischen Modus befinden und nicht mit den Routingregeln übereinstimmen. Zum Anwenden der Routingregeln liest es zuerst die überschreibbaren Konfigurationsspeicher (MandatoryConfigStores). Anschließend werden alle Prozessmodule entfernt, die nicht von den vorhergehenden Prozessmodulen erreicht werden können, wenn die Eigenschaft "RoutingCheck" festgelegt ist.

(C) List<PAProcessModule> AvailableProcessModuleList:
AvailableProcessModuleList entfernt Prozessmodule aus ProcessModuleList (B), die nicht von anderen Workflow-Gruppen belegt sind.

(D) PAProcessModule FirstAvailableProcessModule:
Gibt das erste Element aus AvailableProcessModuleList (C) zurück.

(E) bool HasHighestPriorityForMapping:
Diese Eigenschaft gibt "true" zurück, falls diese Workflow-Gruppe die höchste Priorität hat, um ein Prozessmodul zuerst belegen zu dürfen. Dazu werden alle konkurrienden Workflow-Gruppeninstanzen mit derselben "ContentACClassWF.RefPAACClass" in eine Liste eingetragen, die nach dem Start-Datum ihres Wurzel-Workflowknotens (PWProcessFunction) sortiert sind ("ContentACClassWF.RefPAACClass" ist ein Verweis auf eine Klasse im Application-Definition-Projekt, die als Basisklasse für die Prozessmodule im physikalischen Modell dient). Diese Priroritätsliste kann mittels der Eigenschaft IEnumerable<PWGroup> PriorizedCompetingWFNodes abgefragt werden.

(F) bool NeedsAProcessModule:
Diese Eigenschaft gibt "true" zurück, wenn diese Workflow-Gruppe mit einem Prozessmodul verbunden werden muss (Das ist die Standardeinstellung). Mittels der Konfigurationseigenschaft "WithoutPM" kann eingestellt werden, dass eine Workflow-Gruppe nur zur Organisation von Kind-Knoten dienen soll, die keine Ableitungen von PWNodeProcessMethod sind.

(G) bool OccupationByScan:
Mit dieser Konfigurationseingeschaft wird festgelegt, dass die Belegung eines Prozessmoduls durch ein Scan-Event erfolgt. Dazu müssen die entsprechenden Prozessmodule eine PAFWorkTaskScanBase-Instanz als untergeordnetes Element haben. Die PAFWorkTaskScanBase-Instance ruft die OccupyWithPModuleOnScan()-Methode auf, um diesen Workflowknoten in den Running-Zustand zu versetzen. Der Standard ist FALSE!

 

Algorithmus der SMStarting-Methode:

  1. Wenn die OccupationByScan (G) gesetzt ist, wird sie vom zyklischen Rückruf abgemeldet und wartet, bis ein Scannereignis ein Prozessmodul belegt hat und in den Running-State wechselt. Ansonsten wird Schritt 2 ausgeführt (Standardfall):
  2. Wenn NeedsAProcessModule (F) = TRUE ist (= ein Prozessmodul sollte belegt werden), liest es die FirstAvailableProcessModule (D)-Eigenschaft und ruft die virtual bool OnHandleAvailableProcessModule(PAProcessModule processModule) auf. Unterklassen können OnHandleAvailableProcessModule() überschreiben, um die Belegung selbst zu übernehmen. Wenn OnHandleAvailableProcessModule() TRUE zurückgibt, dann wird SMStarting abgebrochen. 
    Wenn NeedsAProcessModule (F) = FALSE ist, wird der ACState auf SMRunning geschaltet, ohne ein Prozessmodul zu besetzen.
  3. Diese zyklische Methode wartet so lange, bis HasHighestPriorityForMapping (E) = True ist und FirstAvailableProcessModule (D) einen Wert aufweist und somit diese Workflow-Gruppe das Prozessmodul besetzen darf.
  4. Das Prozessmodul wird durch Aufrufen von TrySemaphore.AddToServicePoint() besetzt.
  5. Der ACState wird auf SMRunning gewechselt und der erste untergeordnete Knoten "PWNodeStart" wird gestartet.

 

SMCompleted-Zustandsmethode

Der SMCompleted-Zustand wird aktiv, wenn der Endeknoten (PWNodeEnd) erreicht wird. Die Statusmethode SMCompleted() ruft die Methode ReleaseAllAccessedModules() auf, um das belegte Prozessmodul wieder frei zugeben. Danach löst es das PWPointOut-Event aus und ruft die Reset()-Methode auf um in den Grundzustand zurückzukommen.

 

PWGroupVB

"gip.mes.processapplication.PWGroupVB" ist eine Ableitung von PWGroup für die MES-Funktionalität. Sie arbeitet mit den MES-Tabellen für Produktionsaufträge, Lieferscheine und Kommissionieraufträge. Diese Tabellen enthalten Informationen darüber wohin ein Produkt transportiert werden soll. PWGroupVB verhindert dann Prozessmodule zu belegen die nicht zum endgültigen Ziel führen können. Aus diesem Grund überschreibt PWGroupVB ProcessModuleList (B), um die diese nicht verwendbaren Prozessmodule herauszufiltern. Für die Berechnung der möglichen Ziele wird der Routing-Service verwendet.

Ein weiteres Feature von PWGroupVB ist, dass es ein Prozessmodul überhaupt nicht belegt, wenn kein Material zu verarbeiten ist, damit andere Workflows nicht unnötig warten müssen. Dies stellen Sie mit der Konfigurationseigenschaft "SkipIfNoComp" ein.

 

PWBaseNodeProcess erweitert PWBaseExecutable, um einen umfangreicheren Zustandsautomaten.  Es wird der

  • SMPaused-Zustand unterstützt, damit ein laufender Prozess angehalten werden kann und der
  • SMCompleted-Zustand unterstützt, damit ein eröffneter ProgramLog abgeschlossen werden kann.

Der SMCompleted-Zustand wird entweder in den Ableitungen direkt gesetzt oder durch die Callback-Methode

public virtual void TaskCallback(IACPointNetBase sender, ACEventArgs e, IACObject wrapObject).

Diese Methode erhält PWBaseNodeProcess durch die Implementierung der Schnittstelle IACComponentTaskSubscr. IACComponentTaskSubscr ist das Gegenstück zur Schnittstelle IACComponentTaskExec, um den dafür nötigen Abbonement-Punkt für asynchrone Aufrufe bereitzustellen.

 


PWNodeProcessMethod ermöglicht Funktionen im physikalischen Modell zu starten (asynchron). Die Parameterliste wird dabei als virtuelle Methode (ACMethod) übergeben. Welche virtuelle Methode verwendet werden soll, ist in der Eigenschaft "ContentACClassWF.RefPAACClassMethod" festgelegt, die beim Entwurf des Workflows durch den Workflow-Editor gesetzt worden ist. Die Parameter werden, wie auch die Konfigurationseigenschaften, durch die überschreibbaren Konfigurationsspeicher (MandatoryConfigStores) zusammengestellt, indem die "PWBase.GetConfigForACMethod()" aufgerufen und eine leere ACMethod (Template) übergeben wird. Diese Logik ist in der überschriebenen Statusmethode SMStarting() implementiert. Wurde die Funktion erfolgreich gestartet, wird in den Zustand SMRunning gewechselt.

 

Beispiel

Folgender Programmcode wurde dem Beispielprojekt entnommen, das Sie auf der Startseite herunterladen können, um die Schritte nachvollziehen zu können wie man eine eigene Workflowklasse implementiert:

 

Diese Beispielklasse ist für die Verwendung der Beispielfunktion PAFOrder aus dem vorigen Kapitel vorgesehen.

  1. Leiten Sie von PWNodeProcessMethod ab. Die ACClassInfo-Attributklasse muss folgendermaßen konstruiert werden:
    1. Verwenden Sie "Global.ACKinds.TPWNodeMethod" um iPlus bekannt zugeben, dass es sich um eine Workflowklasse zum Starten von Prozessfunktionen handelt.
    2. "Global.ACStorableTypes.Required" muss verwendet werden, weil z.B. die ACState-Eigenschaft persistierbar ist und der Zustand beim Neustart des Dienstes wiederhergestellt werden muss.
    3. Referenzieren Sie die zugehörige Root-Workflowklasse, mit der diese Workflowklasse kompatibel ist. In diesem Beispiel ist das "PWProcessFunction.PWClassName".
    4. Implementieren Sie die Schnittstelle IACMyConfigCache.
  2. Deklarieren Sie Parameterliste der virtuellen Methode (ACMethod), die für die Konfiguration der Workflowklasse selbst benötigt wird. Zum Schluss generieren Sie eine Instanz von ACMethodWrapper, um die virtuelle Methode der iPlus-Runtime bekannt zu geben, indem Sie "RegisterVirtualMethod()" aufrufen.
  3. Deklarieren einen Execute-Helper für die statischen Aufrufe, indem Sie den statischen Execute-Handler als Delegat der RegisterExecuteHandler()-Methode übergeben.
  4. Überschreiben Sie die SMStarting-Zustandsmethode und veröffentlichen Sie sie, indem Sie ACMethodState-Attributklasse verwenden.
  5. Ab diesem Moment ist eine Prozessfunktion vollständig programmiert und kann in der iPlus-Entwicklungsumgebung verwendet werden. Jedoch würde die SMStarting-Methode (vorausgesetzt sie rufen base.SMStarting() auf) die Beispielfunktion PAFOrder mit leeren Parametern aufrufen. Es fehlt daher noch der eigentliche Programmcode für das, was die Workflowklasse eigentlich machen soll, bevor der asynchrone Aufruf stattfindet. Deshalb ist diesem Code-Beispiel die Methode GetOrderDataCSV() definiert, die Bestelldaten als CSV-String serialisiert und in die Parameterliste eintragen soll.
  6. Rufen Sie dazu die Methode TypeACSignature() auf, um eine leere ACMethod zu erhalten. Danach lassen Sie die Parameterliste befüllen, indem Sie GetConfigForACMethod aufrufen. Bitte beachten Sie, dass der Aufruf per ACUrlCommand erfolgt, damit Endanwender evtl. eine Skriptmethode programmieren können, die stattdessen aufgerufen wird.
  7. Nun ist die Parameterliste aus den Daten des überschreibbaren Konfigurationsspeichers befüllt und Sie können nun den serialisierten CSV-String in den Parameter "Content" eintragen.
  8. Starten Sie nun die Prozessfunktion durch den asynchronen Aufruf auf dem TaskInvocationPoint.
  9. Schalten Sie um in den SMRunning-Zustand. Wenn die Funktion fertig ist, ruft sie die im vorigen Abschnitt beschriebene TaskCallback()-Methode auf, die Sie in Ihrer Ableitung überschreiben dürfen.
  10. Übernehmen Sie exakt den Programmcode zur Implementierung der Eigenschaft MyConfiguration aus der Schnittstelle IACMyConfigCache.
  11. Übernehmen Sie exakt den Programmcode zur Implementierung der Methode ClearMyConfiguration aus der Schnittstelle IACMyConfigCache.
  12. Veröffentlichen Sie die Konfigurationswerte als normale ".NET-Eigenschaft".
  13. Sichern Sie die Zugriffe auf private Felder oder kritische Codeabschnitte per "ACMonitor.Lock" ab.
  14. Geben Sie private Feldwerte für die XML-Diagnose aus, damit Sie und andere Endanwender den Zustand Ihrer Klasse während der Laufzeit diagnostizieren können.
  15. Setzen Sie in der ACDeInit- und der Recycle-Methode ihre privaten Feldwerte zurück, damit die Instanz per Pooling wiederverwendet werden kann.
  16. Optional: Veröffentlichen Sie den Datenkontext mit dem Ihre Workflowklasse als normale ".NET-Eigenschaft".

Zum Abschluss noch ein wichtiger Hinweis: Überschreiben Sie immer die "SMIdle()"-Methode, um ihre privaten Feldwerte zurückzusetzen. Im SMIdle-Zustand muss ein Workflowknoten immer in den Grundzustand gebracht werden - so wie er initial bei der Generierung ursprünglich im Heap angelegt worden ist!

 

Ableitungen von PWNodeProcessMethod in iplus.MES

Folgende Ableitungen gibt es in der Assembly gip.mes.processapplication:

KlasseBeschreibung
PWDosing

Klasse die zuständig ist, um Einsatz-Materialien abzuarbeiten, die einem Zwischenprodukt zugeordnet sind. Das Zwischenprodukt wiederum ist über den Materialworkflow mit einem oder mehreren Workflowknoten verknüpft, die von dieser Klasse PWDosing sind. PWDosing dient zur vollautomatischen Produktion. Sie ruft die Prozessfunktion PAFDosing asynchron auf, um die echtzeitkritische Aufgaben an eine SPS-Steuerung zu delegieren. Verbrauchte Mengen werden per Lagerverwaltung abgebucht (ACFacilityManager). Sie kann mit unterschiedlichen Datenkontexten arbeiten (Produktions- und Kommissionieraufträge).

PWDischargingKlasse die zuständig ist, um Materialien von einem Punkt zu einem anderen Punkt zu transportieren. Dabei kann es sich entweder um Rohwaren, Zwischenprodukte oder Endprodukte handeln. Der Workflowknoten kann dafür auch mit einem Zwischenprodukt in einem Materialworkflow verknüpft sein. PWDischarging dient zur vollautomatischen Produktion. Sie ruft die Prozessfunktion PAFDischarging asynchron auf, um die echtzeitkritische Aufgaben an eine SPS-Steuerung zu delegieren. Hergestellte, eingelagerte oder umgelagerte Mengen werden per Lagerverwaltung zugebucht (ACFacilityManager). Sie kann mit unterschiedlichen Datenkontexten arbeiten (Produktions- und Kommissionieraufträge oder Lieferscheine).

PWManualWeighing

Klasse die zuständig ist, um Einsatz-Materialien abzuarbeiten, die einem Zwischenprodukt zugeordnet sind. Das Zwischenprodukt wiederum ist über den Materialworkflow mit einem oder mehreren Workflowknoten verknüpft, die von dieser Klasse PWManualWeighing sind. PWManualWeighing dient zur Unterstützung der händischen Produktion. Sie ruft die Prozessfunktion PAFManualWeighing asynchron auf. Die Bedienerführung erfolgt per Businessobjekt  BSOManualWeighing, das ein Plugin für das Businessobjekt BSOWorkCenter ist. Verbrauchte Mengen werden per Lagerverwaltung abgebucht (ACFacilityManager). Sie kann mit unterschiedlichen Datenkontexten arbeiten (Produktions- und Kommissionieraufträge).
PWBinSelection 
PWBinDischarging 
PWMixing 
PWCooling 
PWDrying 
PWExtruding 
PWLoad 
PWUnload 
PWSampleWeighing 
PWScanning 
PWVacuum 
PWWorkTaskScanBase