• Keine Ergebnisse gefunden

6.4 Transformation in plattformspezifische Implementierung

6.4.4 Transformationsschablonen

Die Inhalte des Transformationsübergangsmodells, welche sich aus den ursprünglichen Inhalten des EPMN-Modells ableiten, werden schließlich mittels in MOFM2T formulierten Transformations-schablonen in die entsprechenden Esper-EPL-Anweisungen überführt. Dazu wird in der steuernden Haupt-Transformationsschablone zunächst eine neue Datei mit der spezifischen Dateiendung*.epl erzeugt und mit dem Schlüsselwortmoduleein neues Esper-Modul eingeleitet, dessen Bezeichnung aus dem EPMN-Modell extrahiert wird. In MOFM2T werden diese Aktionen mit dem Codefragment in Listing 6.3 realisiert.

[file (filename(m.moduleName) + ’.epl’, false, ’UTF-8’)]

[eplComment(’Name of this module’)/]

module [m.moduleName /];

...

[/file]

Listing 6.3:Erzeugung des Esper-Moduls in der Haupt-Transformationsschablone

Anstelle der Auslassungspunkte im Codefragement werden mithilfe weiterer Transformationsscha-blonen die einzelnen EspEPL-Anweisungen aus dem EPMN-Modell generiert und in das neu er-stellte Esper-Modul eingefügt. Die betrachtete Haupt-TransformationsschablonegenerateEpl.mtl

ist vollständig in Listing D.1 in Anhang D aufgeführt.

Um die in Abschnitt 6.4.2 erwähnten Hilfskonstrukte für die Esper-Umsetzung zu erzeugen, wird zunächst eine weitere Transformationsschablone aufgerufen. Wesentliche Hilfskonstrukte sind et-wa der Wrapper-Ereignisstrom, durch den alle spezifizierten Ereignistypen um einen Zeitstempel und eine Ereigniskennung erweitert werden, sowie der Zeitticker-Ereignisstrom, dessen Diskreti-sierungsintervall mit Millisekunden als Einheit frei konfiguriert werden kann. Diese beiden zweck-dienlichen Ereignisströme werden in MOFM2T mit dem Codefragment in Listing 6.4 erzeugt.

[eplComment(’Adds metadata to any incoming event. Subtypes will add a __wrapped

property containing the actual event’)/]

create schema [const.eventWrapperTypeName/] as ([const.timestampPropertyName/] long, [

const.streamNamePropertyName/] String);

[eplComment(’Tick events provide temporal discretization - the smallest possible

interval is 1 millisecond, the actual interval depends on the configuration’)/]

create schema [const.tickEventStreamName/] as ([const.timestampPropertyName/] long);

insert into [const.tickEventStreamName/] select current_timestamp() as [const.

timestampPropertyName/] from pattern[’[’/]every timer:interval(1 millisecond)

[’]’/];

Listing 6.4:Erzeugung von Wrapper- und Zeitticker-Ereignisströmen

Darüber hinaus werden als Hilfskonstrukt auch die erforderlichen Ereignisströme für die Auslöser-Ereignisse von festen Fenstern erzeugt. Hierunter fällt je ein Ereignisstrom für den Startauslöser und den Endauslöser sowie bei beiden noch je ein Ereignisstrom für den Zeitraum vor dem Auslöser-Ereignis, die Auslösung des Ereignisses selbst sowie den Zeitraum nach dem Auslöser-Auslöser-Ereignis, um bei der Evaluation von Ereignisverarbeitungsregeln mit festen Fenstern stets das Wissen über den aktuellen Zustand einer Fensterinstanz zu besitzen. Die Realisierung dieses Hilfskonstrukts in der Transformationsschablone zeigt das in Listing 6.5 aufgeführte Codefragment.

[eplComment(’Establish temporal order by splitting’)/]

on [const.contextStartEventStreamName/]

insert into [const.contextBeforeStartEventStreamName/] select * insert into [const.contextOnStartEventStreamName/] select * insert into [const.contextAfterStartEventStreamName/] select * output all;

on [const.contextEndEventStreamName/]

insert into [const.contextBeforeEndEventStreamName/] select * insert into [const.contextOnEndEventStreamName/] select * insert into [const.contextAfterEndEventStreamName/] select * output all;

Listing 6.5:Erzeugung von Auslöser-Ereignisströmen von festen Fenstern

Diese beiden Codefragmente aus den Listings 6.4 und 6.5 zur Erzeugung der erforderlichen Hilfskon-strukte stammen aus der TransformationsschablonegenerateHelperStreams.mtl, welche in ihrer Gesamtheit in Listing D.2 in Anhang D aufgeführt ist. Nach deren Aufruf werden von der Haupt-Transformationsschablone anschließend alle weiteren Haupt-Transformationsschablonen zur Überführung

des EPMN-Modells in die entsprechenden Esper-EPL-Anweisungen aufgerufen. Diese werden in den nachfolgenden Abschnitten erläutert.

Transformation von Ereignistypen

Für jeden im EPMN-Modell spezifizierten Ereignistyp wird ein separater Ereignisstrom erzeugt, wobei jeder dieser Ereignisströme zur Laufzeit die Ereignisse vom jeweiligen Ereignistyp enthält.

Dies wird in MOFM2T durch das Codefragment in Listing 6.6 bewerkstelligt.

[eplComment(’Event type streams - each stream accepts all events of a certain type’)/]

[for (eventTypeStream: EventTypeStream | m.eventTypeStreams)]

[let typeName: Identifier = asIdentifier(eventTypeStream.underlying.oclAsType(EventType

).name)]

insert into [eventTypeStream.name/] select [alias(0)/].* as [const.

wrappedEventPropertyName/],

[quoteLiteral(eventTypeStream.name.value)/] as [const.streamNamePropertyName/], current_timestamp as [const.timestampPropertyName/]

from [typeName/] as [alias(0)/];

[/let]

[/for]

Listing 6.6:Erzeugung separater Ereignisströme von Ereignistypen

Wird im EPMN-Modell beispielsweise ein Ereignistyp mit der BezeichnungTEventAspezifiziert, so erzeugt dieses MOFM2T-Codefragement die in Listing 6.7 aufgeführte Esper-EPL-Anweisung.

insert into TEventA_Type select __alias0.* as __wrapped,

’TEventA_Type’ as __streamName, current_timestamp as __timestamp from TEventA as __alias0;

Listing 6.7:Beispiel eines transformierten Ereignisstroms für einen Ereignistyp

Anschließend werden diese separaten Ereignisströme in einen übergreifenden Ereignisstrom inte-griert, welcher demnach Ereignisse von verschiedenen Ereignistypen beinhaltet. Ein solcher Ereig-nisstrom wird in Esper durch die EPL-Anweisungcreate variant schemaerzeugt, in welchen die Ereignisse aus den separaten Ereignisströmen mittels einer Schleife über allen Ereignistypen und der EPL-Anweisunginsert intoeingefügt werden,280wie das Codefragment in Listing 6.8 zeigt.

[eplComment(’Stream containing all events of any type’)/]

create variant schema [const.anyEventTypeStreamName/] as *;

[for (eventTypeStream: EventTypeStream | m.eventTypeStreams)]

insert into [const.anyEventTypeStreamName/] select * from [eventTypeStream.name/];

[/for]

Listing 6.8:Erzeugung des übergreifenden Ereignisstroms von Ereignistypen

Listing D.3 in Anhang D beinhaltet den vollständigen Quellcode der betrachteten Transformations-schablonegenerateEventTypeStreams.mtlzur Erzeugung der Ereignisströme für Ereignistypen.

280vgl. Esper Team und EsperTech Inc. 2012

Transformation von eingehenden Ereignissen

Zur Verarbeitung von eingehenden Ereignissen müssen diese zunächst mit dem Ereignisstrom des zugrunde liegenden Ereignistyps verknüpft werden, was in MOFM2T mit dem in Listing 6.9 aufge-führten Codefragment ausgeführt wird.

[let typeName: Identifier = asIdentifier(inStream.oclAsType(IncomingEventStream).

typeStream.underlying.oclAsType(EventType).name)]

[let event: IncomingEvent = inStream.underlying.oclAsType(IncomingEvent)]

...[/let][/let]

Listing 6.9:Verknüpfung eingehender Ereignisse und Ereignistypen

Daraufhin ist bei der Ausführung der Ereignisverarbeitung für jedes aktuell eingehende Ereignis zu prüfen, ob es in Bezug auf eine im EPMN-Modell spezifizierte Ereignisverarbeitungsregel einen pas-senden Ereignistyp und die positive Evaluation der zugehörigen Filterausdrücke mit ihrer logischen Verknüpfung erfüllt. Das Codefragment in Listing 6.10 realisiert diese Prüfung in MOFM2T.

[comment Part 1: positive match of the filter expressions/]

insert into [inStream.name/] select [’’

/][quoteLiteral(inStream.name)/] as [c.streamNamePropertyName/], [’’

/]current_timestamp() as [c.timestampPropertyName/], [’’

/][alias(0)/].* as [c.wrappedEventPropertyName/] [’’

/]from [typeName/]([inclusionCondition/]) as [alias(0)/];

[comment Part 2: negative match of the filter expressions/]

insert into [inStream.unmatchedName/] select [’’

/][quoteLiteral(’’)/] as [c.streamNamePropertyName/], [’’

/]current_timestamp as [c.timestampPropertyName/], [’’

/][alias(0)/].* as [c.wrappedEventPropertyName/] [’’

/]from [typeName/]([if (isBlank(inclusionCondition))]false[else]not ([

inclusionCondition/])[/if]) as [alias(0)/];

Listing 6.10:Prüfung der Übereinstimmung eingehender Ereignisse

Je nach Ergebnis dieser Prüfung wird im Anschluss jedes eingehende Ereignis entweder in den über-einstimmenden oder in den nicht-überüber-einstimmenden Ereignisstrom eingefügt. Da die eingehenden Ereignisse verschiedene Ereignistypen besitzen können, erfolgt auch hier wieder die Erzeugung der Ereignisströme jeweils durch die Esper-EPL-Anweisung create variant schema. Zuletzt werden der übereinstimmende und der nicht-übereinstimmende Ereignisstrom in einem übergreifenden Er-eignisstrom vereint, welcher demnach alle eingehenden Ereignisse enthält. Das Codefragment in Listing 6.11 sorgt für die Erzeugung dieser drei Ereignisströme mittels MOFM2T.

[eplComment(’Stream containing all matched events’)/]

create variant schema [c.matchedIncomingEventsStreamName/] as [’’

/][for (stream: IncomingEventStream | m.incomingEventStreams) separator (’, ’)][stream.

name/][/for];

[for (stream: IncomingEventStream | m.incomingEventStreams)]

insert into [c.matchedIncomingEventsStreamName/] select * from [stream.name/];[/for]

[eplComment(’Stream containing all unmatched events’)/]

create variant schema [c.unmatchedIncomingEventsStreamName/] as [’’

/][for (stream: IncomingEventStream | m.incomingEventStreams) separator (’, ’)][stream.

unmatchedName/][/for];

[for (stream: IncomingEventStream | m.incomingEventStreams)]

insert into [c.unmatchedIncomingEventsStreamName/] select * from [stream.unmatchedName

/];[/for]

[eplComment(’Stream containing all matched and unmatched incoming events’)/]

create variant schema [c.anyIncomingEventStreamName/] as [c.

matchedIncomingEventsStreamName/], [c.unmatchedIncomingEventsStreamName/];

insert into [c.anyIncomingEventStreamName/] select * from [c.

matchedIncomingEventsStreamName/];

insert into [c.anyIncomingEventStreamName/] select * from [c.

unmatchedIncomingEventsStreamName/];

Listing 6.11:Erzeugung übereinstimmender und nicht-übereinstimmender Ereignisströme

Die vollständige TransformationsschablonegenerateIncomingEventStreams.mtlist in Listing D.4 in Anhang D aufgeführt.

Transformation von Fenstern

Bei den Fenstern wird zunächst nach der Art des betrachteten Fensters unterschieden, um die pas-sende Transformationsschablone für ein gleitendes Zeitfenster, ein gleitendes Längenfenster, ein festes Fenster oder ein unbegrenztes Fenster aufzurufen, wobei letzteres ein Hilfskonstrukt für den Fall ist, dass im EPMN-Modell kein Fenster mit der Ereignisverarbeitungsregel verknüpft ist. Diese Unterscheidung wird in MOFM2T durch das Codefragment in Listing 6.12 durchgeführt.

[let w: Window = windowStream.underlying.oclAsType(Window)]

[if (w.oclIsKindOf(SlidingTimeWindow))]

[generateSlidingTimeWindow(m, windowStream, w.oclAsType(SlidingTimeWindow))/]

[elseif (w.oclIsKindOf(SlidingEventWindow))]

[generateSlidingEventWindow(m, windowStream, w.oclAsType(SlidingEventWindow))/]

[elseif (w.oclIsKindOf(FixedWindow))]

[generateFixedWindow(m, windowStream, w.oclAsType(FixedWindow))/]

[elseif (w.oclIsKindOf(UnboundedWindow))]

[generateUnboundedWindow(m, windowStream)/]

...[/if][/let]

Listing 6.12:Unterscheidung von Fensterarten

Die zugehörige TransformationsschablonegenerateWindowStreams.mtlist in ihrer Gesamtheit in Listing D.5 in Anhang D enthalten.

Bei einem gleitenden Fenster wird in Esper mit der EPL-Anweisungcreate windowein Fenster-Ereignisstrom gebildet, in welchen Ereignisse per EPL-Anweisung insert intointegriert werden können. Die Größe dieses Fenster-Ereignisstroms wird bei einem gleitenden Zeitfenster durch das Esper-EPL-Fragmentwin:time()mit Angabe einer Zeitdauer begrenzt.281Das in Listing 6.13

aufge-281vgl. Esper Team und EsperTech Inc. 2012

führte Codefragment in MOFM2T bewerkstelligt die Transformation eines gleitenden Zeitfensters aus dem EPMN-Modell in die entsprechende Esper-EPL-Anweisung.

create window [windowStream.name/].win:time([format(w.timespan)/]) as select * from [m.constants.anyIncomingEventStreamName/];

insert into [windowStream.name/]

select * from [m.constants.anyIncomingEventStreamName/];

Listing 6.13:Erzeugung gleitender Zeitfenster

Ist im EPMN-Modell beispielsweise ein gleitendes Zeitfenster mit einer Größe von 20 Sekunden spezifiziert, so wird durch dieses MOFM2T-Codefragment die in Listing 6.14 aufgeführte Esper-EPL-Anweisung erzeugt. Dabei wird das in EPMN genutzte ISO 8601-Format für eine Zeitdauer, im BeispielPT20S, in das Esper-spezifische Format, im Beispiel20 seconds, überführt.282

create window SlidingTime20s_WndStream.win:time(20 seconds) as select * from __AnyIncoming;

insert into SlidingTime20s_WndStream select * from __AnyIncoming;

Listing 6.14:Beispiel eines transformierten gleitenden Zeitfensters

Die Größe eines gleitenden Längenfensters wird durch das Esper-EPL-Fragmentwin:length()mit Angabe einer Anzahl von Ereignissen angegeben,283wie das Codefragment zur Erzeugung gleiten-der Längenfenster in MOFM2T in Listing 6.15 zeigt.

create window [windowStream.name/].win:length([w.size/]) as select * from [m.constants.anyIncomingEventStreamName/];

insert into [windowStream.name/]

select * from [m.constants.anyIncomingEventStreamName/];

Listing 6.15:Erzeugung gleitender Längenfenster

Als Beispiel wird mit diesem MOFM2T-Codefragment die in Listing 6.16 aufgeführte Esper-EPL-Anweisung erzeugt, wenn im EPMN-Modell ein gleitendes Längenfenster mit einer Größe von 10 Ereignissen spezifiziert ist.

create window SlidingEvent10E_WndStream.win:length(10) as select * from __AnyIncoming;

insert into SlidingEvent10E_WndStream select * from __AnyIncoming;

Listing 6.16:Beispiel eines transformierten gleitenden Längenfensters

Die zugehörigen Transformationsschablonen generateSlidingTimeWindow.mtl für das gleitende Zeitfenster sowiegenerateSlidingEventWindow.tmlfür das gleitende Längenfenster sind in ihrer Gesamtheit den Listings D.6 und D.7 in Anhang D zu entnehmen.

282vgl. Esper Team und EsperTech Inc. 2012 283vgl. Esper Team und EsperTech Inc. 2012

Bei festen Fenstern wird zunächst zwischen den verschiedenen Kombinationen von Start- und Endauslösern differenziert, die in Esper jeweils unterschiedlich umgesetzt werden. Listing 6.17 setzt diese Unterscheidung mit einem jeweiligen Aufruf weiterer Transformationsschablonen um.

[if (w.start.oclIsKindOf(IncomingEvent))]

[if w.end.oclIsKindOf(IncomingEvent)][eventUntilEvent(w, windowStream)/]

[elseif w.end.oclIsKindOf(TimeInstant)][eventUntilInstant(w, windowStream)/]

[elseif w.end.oclIsKindOf(TimePeriod)][eventUntilInterval(w, windowStream)/]

...[/if]

[elseif (w.start.oclIsKindOf(TimeInstant))]

[if w.end.oclIsKindOf(IncomingEvent)][instantUntilEvent(w, windowStream)/]

[elseif w.end.oclIsKindOf(TimeInstant)][instantUntilInstant(w, windowStream)/]

[elseif w.end.oclIsKindOf(TimePeriod)][instantUntilInterval(w, windowStream)/]

...[/if]

...[/if]

Listing 6.17:Unterscheidung von festen Fenstern

Ein festes Ereignisfenster, welches im EPMN-Modell jeweils ein EingehendesEreignis als Start-und Endauslöser besitzt, wird durch das in Listing 6.18 aufgeführte MOFM2T-Codefragment in die entsprechende Esper-EPL-Anweisung transformiert.

[let running: Identifier = m.getUniqueIdentifier(’ctx’)]

[newCtxStateVar(windowStream, running)/]

[ctxEndDecl(windowStream,

’pattern[every(’ + ctxOnStart(windowStream) + ’ -> ’ + streamRef(windowStream.

endEventStream.name) +

while (’ + running + ’))]’)/];

[ctxStartDecl(windowStream,

’pattern[every(’ + streamRef(windowStream.endEventStream.name) +

while (not ’ + running + ’))]’)/];

[createNonOverlappingContext(windowStream)/];[/let]

Listing 6.18:Erzeugung fester Ereignisfenster

Hier wird zunächst eine Zustandsvariable erzeugt, die eine aktive Fensterinstanz kennzeichnet. Un-ter Nutzung des Hilfskonstrukts der Auslöser-Ereignisströme (siehe Listing 6.5) wird das feste Ereig-nisfenster anschließend dermaßen erzeugt, dass eine aktive Fensterinstanz durch Eintreffen eines Endauslöser-Ereignisses wieder geschlossen wird, während beim Nichtvorhandensein einer aktiven Fensterinstanz eine solche mit dem Eintreffen eines Startauslöser-Ereignisses geöffnet wird.

Zur Illustration zeigt Listing 6.19 die erzeugte Esper-EPL-Anweisung eines beispielhaften festen Ereignisfensters, bei dem die eingehenden Ereignisse WndStartEvent und WndEndEvent exempla-risch als Start- und Endauslöser angegeben sind.

create variable boolean ctx = false;

on __OnCtxStart(__name=’FixedEvent_WndStream’) set ctx = true;

on __OnCtxEnd(__name=’FixedEvent_WndStream’) set ctx = false;

insert into __OnCtxEnd

select ’FixedEvent_WndStream’ as __name

from pattern[every(__OnCtxStart(__name=’FixedEvent_WndStream’) ->

In_WndEndEvent_Type() while (ctx))];

insert into __OnCtxStart

select ’FixedEvent_WndStream’ as __name

from pattern[every(In_WndStartEvent_Type() while (not ctx))];

create context FixedEvent_WndContext

start __BeforeCtxStart(__name=’FixedEvent_WndStream’) end __AfterCtxEnd(__name=’FixedEvent_WndStream’);

Listing 6.19:Beispiel eines transformierten festen Ereignisfensters

Die übrigen Arten von festen Fenstern werden analog erzeugt, wobei einZeitpunktals Start- oder Endauslöser bei der Transformation durch das Hilfskonstrukt des Zeitticker-Ereignisstroms (siehe Listing 6.4) in die Esper-EPL umgesetzt wird, während bei einer Zeitdauer als Endauslöser das Esper-EPL-Fragment timer:interval()zum Einsatz kommt.284 Die vollständige Transformations-schablonegenerateFixedWindow.mtlist in Listing D.8 in Anhang D aufgeführt.

Transformation von Beziehungsoperatoren

Bei den Beziehungsoperatoren erfolgt zunächst die Unterscheidung zwischen einem Konjunktions-operator, einem DisjunktionsKonjunktions-operator, einem Sequenzoperator und einem FunktionsKonjunktions-operator, wie im MOFM2T-Codefragment in Listing 6.20 dargestellt ist.

[for (s: OperatorStream | m.operatorStreams)]

[if (s.oclIsKindOf(ConjunctionOperatorStream))]

[conjunction(s.oclAsType(ConjunctionOperatorStream))/]

[elseif (s.oclIsKindOf(DisjunctionOperatorStream))]

[disjunction(s.oclAsType(DisjunctionOperatorStream))/]

[elseif (s.oclIsKindOf(SequenceOperatorStream))]

[sequence(s.oclAsType(SequenceOperatorStream))/]

[elseif (s.oclIsKindOf(FunctionOperatorStream))]

[function(s.oclAsType(FunctionOperatorStream))/]

...[/if]

[/for]

Listing 6.20:Unterscheidung von Arten von Beziehungsoperatoren

Daraufhin wird für jede Art von Beziehungsoperator eine eigene Transformationsschablone auf-gerufen. Dabei ist die Transformation eines Beziehungsoperators in die entsprechende Esper-EPL-Anweisung von der jeweils verbundenen Fensterart abhängig, für die je eine Transformationsscha-blone existiert. Die vollständige TransformationschaTransformationsscha-blonegenerateOperatorStreams.mtlist in Lis-ting D.10 in Anhang D verfügbar.

In der Esper-EPL werden der Konjunktionsoperator und der Disjunktionsoperator durch die wohlbekannten Codefragmente and und or realisiert, während für den Sequenzoperator das spe-zielle Codefragment-> zum Einsatz kommt.285 Für die Transformation aus dem EPMN-Modell in

284vgl. Esper Team und EsperTech Inc. 2012 285vgl. Esper Team und EsperTech Inc. 2012

die entsprechenden Esper-EPL-Anweisungen werden demnach unter Berücksichtigung der verbun-denen Fensterart die jeweiligen Operanden um diese Codefragmente herum zusammengesetzt.

Stellvertretend für diese drei Arten von Beziehungsoperatoren wird in Listing 6.21 das MOFM2T-Codefragment für einen Konjunktionsoperator aufgeführt, der in einer Ereignisverarbeitungsregel mit einem gleitendem Fenster verbunden ist.

insert into [opStream.name/] select * from [opStream.windowStream.name/] where

[for (inStream: EventStream | opStream.presenceStreams->union(opStream.absenceStreams))

separator(’ and ’) after (’;’)]

[let streamNameExpression: String = m.constants.streamNamePropertyName + ’ = ’ +

quoteLiteral(inStream.name.value)]

[let i: IncomingEvent = inStream.underlying.oclAsType(IncomingEvent)]

[let c: CardinalityOperator = if i.cardinality.oclIsUndefined() then cardinality(1,

null) else i.cardinality endif]

([cardinalityCountOfExpression(opStream.windowStream.name, c, streamNameExpression, ’’,

m.constants)/]) [/let][/let][/let]

[/for]

Listing 6.21:Erzeugung von Konjunktionsoperatoren mit gleitenden Fenstern

Der Kardinalitätsoperator selbst wird hier mit dem Codefragmentseparator(’ and ’)eingeführt.

Dies wird in ähnlicher Weise beim Disjunktionsoperator mittelsseparator(’ or ’)und beim Se-quenzoperator mittelsseparator(’ -> ’)bewerkstelligt.

Darüber hinaus spielt es eine maßgebliche Rolle, ob ein Operand zusätzlich mit einem Kardinali-tätsoperator verknüpft ist, welcher die resultierende Esper-EPL-Anweisung beeinflusst. Dabei wird die Transformationsvorschrift festgelegt, dass bei einer Absenz für Minimum und Maximum jeweils der Wert0vergeben wird, während bei unspezifizierter Kardinalität für das Minimum der Wert1

und für das Maximum der Wert1000000000000000000als Repräsentation eines unendlichen Werts gesetzt werden. Ansonsten werden die jeweils spezifizierten Werte des Kardinalitätsoperators aus-gelesen. In Listing 6.21 wird hierfür die HilfsfunktioncardinalityCountOfExpression()genutzt.

Als Beispiel wird in Listing 6.22 die erzeugte Esper-EPL-Anweisung für einen Konjunktionsope-rator aufgeführt. Dieser wird auf die beiden EreignisseEventAundEventBangewendet, von denen

EventAmit einer Absenz versehen ist undEventBkeine spezifizierte Kardinalität besitzt. Die Ereig-nisregel ist mit einem gleitenden Zeitfenster verknüpft.

insert into Op_CardinalityOperator select * from SlidingTime_WndStream

where ((select count(*) from SlidingTime_WndStream where __streamName = ’In_EventA’)

between 0 and 0)

and ((select count(*) from SlidingTime_WndStream where __streamName = ’In_EventB’)

between 1 and 1000000000000000000);

Listing 6.22:Beispiel eines transformierten Konjunktionsoperators

Beim Funktionsoperator werden bereits bei der Modellierung im EPMN-Modell die zugehörigen Funktionsausdrücke direkt in der Esper-EPL spezifiziert (siehe Tabelle 6.19). Diese sind demnach bei der Transformation lediglich aneinanderzureihen, während der resultierende Funktionsoperator als Ganzes nur noch in das verbundene Fenster eingebettet wird. Listing 6.23 zeigt das hierfür erforderliche MOFM2T-Codefragment exemplarisch für den Funktionsoperator, welcher mit einem gleitenden Fenster verbunden ist.

[let windowName: Identifier = m.getUniqueIdentifier(opStream.name.withSuffix(’Wnd’))]

[let u: OclAny = opStream.windowStream.underlying]

[let op: FunctionOperator = opStream.underlying.oclAsType(FunctionOperator)]

create window [windowName/].win:[let w: SlidingTimeWindow = (if u.oclIsKindOf(

SlidingTimeWindow) then u.oclAsType(SlidingTimeWindow) else null endif) ]time([format(w.timespan)/])[elselet w: SlidingEventWindow = (if u.oclIsKindOf(

SlidingEventWindow) then u.oclAsType(SlidingEventWindow) else null endif) ]length([w.size/])[else][unimplemented(u)/][/let] as [opStream.inputStream.name/];

insert into [windowName/]

select * from [opStream.inputStream.name/];

insert into [opStream.name/]

select * from [windowName/][let f: String = (if isBlank(op.connection) then op.

functionExpression.toString() else op.connection.toString() endif)]

having ([f/])[/let][/let][/let][/let];

Listing 6.23:Erzeugung von Funktionsoperatoren mit gleitenden Fenstern

Zunächst wird zwischen einem gleitenden Zeitfenster und einem gleitenden Längenfenster unter-schieden, welches daraufhin an den erzeugten Ereignisstrom des Funktionsoperators angehängt wird, um die enthaltenen Ereignisse zu beschränken. Anschließend wird in diesen Ereignisstrom der Funktionseingang integriert, welcher aus einem der anderen drei Beziehungsoperatoren bestehen kann. Schließlich werden die spezifizierten Funktionsausdrücke aufgeführt und dienen als Prämisse zur Erzeugung von generierten Ereignissen.

Zur Illustration zeigt Listing 6.24 die erzeugte Esper-EPL-Anweisung eines exemplarischen Funk-tionsoperators. Dieser ist am Funktionseingang mit einem Konjunktionsoperator verknüpft, wel-cher wiederum mit dem einzelnen eingehenden Ereignis EventA ohne spezifizierte Kardinalität verbunden ist. Zudem begrenzt ein gleitendes Längenfenster die Anzahl der betrachteten Ereig-nisinstanzen vonEventAauf5. Folgende Funktionsausdrücke werden letztlich spezifiziert und kon-junktional verknüpft: bezogen auf alle innerhalb der aktiven Fensterinstanz befindlichen Ereignis-instanzen muss der Durchschnittswert des Attributsvolumegrößer sein als10und die Summe des Attributs valuegrößer als100. Sind beide Funktionsausdrücke erfüllt, werden die verknüpften ge-nerierten Ereignisse ausgelöst.

insert into Op_ConjunctionOperator

select * from SlidingEvent5E_WndStream

where ((select count(*) from SlidingEvent5E_WndStream where __streamName = ’

In_EventA’) between 1 and 1000000000000000000);

create window Op_FunctionOperatorWnd.win:length(5) as Op_ConjunctionOperator;

insert into Op_FunctionOperatorWnd select * from Op_ConjunctionOperator;

insert into Op_FunctionOperator

select * from Op_FunctionOperatorWnd

having ((avg(volume) > 10) and (sum(value) > 100));

Listing 6.24:Beispiel eines transformierten Funktionsoperators

Die vollständige TransformationsschablonegenerateSlidingWindowOperators.mtl für die Erzeu-gung aller vier Arten von Beziehungsoperatoren bei gleitenden Fenstern ist in Listing D.11 in An-hang D aufgeführt. Mit der TransformationsschablonegenerateFixedWindowOperators.mtlin Lis-ting D.12 ist hier auch die Erzeugung aller Beziehungsoperatoren bei festen Fenstern enthalten, während Listing D.13 die TransformationsschablonegenerateUnboundedWindowOperators.mtlfür Beziehungsoperatoren ohne verbundene Fenster darstellt.

Transformation von generierten Ereignissen

Zu guter Letzt sind noch die generierten Ereignisse der in EPMN modellierten Ereignisverarbei-tungsregeln in die entsprechenden Esper-EPL-Anweisungen zu transformieren. Wie im MOFM2T-Codefragment in Listing 6.25 dargestellt ist, werden die generierten Ereignisse in einen separaten Ereignisstrom gesetzt.

[for (genStream: GeneratedEventStream | m.generatedEventStreams)]

@Name([quoteLiteral(m.getUniqueIdentifier(’GeneratedEvent_’ + genStream.underlying.

oclAsType(GeneratedEvent).name))/])

insert into [genStream.name/] select [columns(m, genStream.output, ’’)/] from [

genStream.generatingStream.name/];

[/for]

Listing 6.25:Erzeugung von generierten Ereignissen

Dabei werden auch die im EPMN-Modell spezifizierten Eigenschaftszuweisungen als Esper-EPL-Fragmente erzeugt und in die Anweisungen für die generierten Ereignisse eingebettet. Listing 6.26 zeigt das MOFM2T-Codefragment, welches die in JSON definierte Eigenschaftszuweisung in die entsprechende Esper-EPL-Anweisung überführt.

[let hasAlias: Boolean = not isBlank(alias)]

[let output: EpObject = (if obj.oclIsKindOf(EpObject) then obj.oclAsType(EpObject) else

null endif)]

[if (hasAlias)]select ([elseif (output.items->size()=0)]*[/if]

[comment The root select must not use braces and all subselects must have an alias/]

[for (item: EpObjectItem | output.items) separator(’, ’)]

[columns(m, item.value, item.name)/]

[/for]

[if (hasAlias)])[/if]

[elselet output: EpArray = (if obj.oclIsKindOf(EpArray) then obj.oclAsType(EpArray)

else null endif)]{[for (item: EpElement | output.items) separator(’, ’)]

[columns(m, item, ’’)/][/for]}

[elselet output: EpPrimitive = (if obj.oclIsKindOf(EpPrimitive) then obj.oclAsType(

EpPrimitive) else null endif)][output/]

[elselet output: EpNull = (if obj.oclIsKindOf(EpNull) then obj.oclAsType(EpNull) else

null endif)]null[else][unimplemented(obj)/][/let][if (hasAlias)] as [asIdentifier(

alias)/][/if][/let]

Listing 6.26:Überführung der Eigenschaftszuweisung

Als Beispiel für eine erzeugte Esper-EPL-Anweisung bei generierten Ereignissen kann wieder die ex-emplarische Ereignisverarbeitungsregel mit dem Funktionsoperator aus Listing 6.24 herangezogen werden. Diese löst bei Übereinstimmung beispielhaft ein generiertes Ereignis EventXaus, welches die AttributeavgVolumeundsumValuebeinhalten soll, deren Werte dynamisch aus der übereinstim-menden Ereignismusterinstanz ermittelt werden sollen. Die hierfür erforderliche Eigenschaftszu-weisung in JSON ist in Listing 6.27 aufgeführt.

{"avgVolume":"avg(volume)","sumValue":"sum(value)"}

Listing 6.27:Beispiel einer Eigenschaftszuweisung für ein generiertes Ereignis

Aus dem EPMN-Modell, in welchem diese Eigenschaftszuweisung mit dem generierten Ereignis

EventXverknüpft ist, wird schließlich die in Listing 6.28 aufgeführte Esper-EPL-Anweisung erzeugt.

@Name(’GeneratedEvent_EventX’) insert into EventX

select avg(volume) as avgVolume, sum(value) as sumValue from Op_FunctionOperator;

Listing 6.28:Beispiel eines transformierten generierten Ereignisses

Ein solcher Ereignisstrom kann schließlich zur Laufzeit derart überwacht werden, dass ein gene-riertes Ereignis als Resultat einer Ereignisverarbeitungsregel entweder als eingehendes Ereignis im Rahmen einer weiteren Ereignisverarbeitungsregel genutzt wird oder gar von der Ereignisverarbei-tungsebene auf die Geschäftsprozessebene gehoben wird, um hier einen dynamischen Einfluss auf den weiteren Verlauf des Geschäftsprozesses zu nehmen. Die vollständige Transformationsschablo-negenerateGeneratedEventStreams.mtlist in Listing D.14 in Anhang D aufgeführt.

Zur Unterstützung der konzipierten Methode [moby]dbpm wurden im Rahmen dieser Arbeit zwei wesentliche Softwarewerkzeuge prototypisch implementiert. Dabei handelt es sich zum einen um das Modellierungswerkzeug [moby:designer]dbpm, das die modellbasierte Entwicklung dynamischer Geschäftsprozesse auf Basis von Ereignisverarbeitung ermöglicht. Zum anderen wurde die passen-de Ausführungsumgebung [moby:runtime]dbpmaus frei verfügbaren Softwarekomponenten zusam-mengefügt und geeignet konfiguriert, sodass die mit dem Modellierungswerkzeug erstellten Mo-delle automatisiert ablaufen können. Diese beiden Softwarewerkzeuge werden in den folgenden Abschnitten beschrieben.

7.1 Webbasiertes Modellierungswerkzeug

Bei dem entwickelten Modellierungswerkzeug [moby:designer]dbpmhandelt es sich um eine webba-sierte Softwareanwendung, die auf einem zentralen Server installiert werden kann, um von den Be-nutzern über eine Netzwerkverbindung jeweils vollständig im eigenen Webbrowser bedient zu wer-den. Mit einer derartigen Implementierung wurde der allgemeinen Entwicklung und Verbreitung des Cloud Computing und der zugehörigen Bereitstellung von Software-as-a-Service-Angeboten als webbasierte Softwareanwendungen Rechnung getragen,286die nicht zuletzt durch die in den letzten Jahren enorm gestiegene Leistungsfähigkeit moderner Webtechnologien mit asynchroner Verarbei-tung ermöglicht wurde. Somit muss die Software nicht mehr auf jedem Benutzerrechner einzeln installiert werden und es steht dennoch ein mächtiges Werkzeug mit den von Desktopanwendun-gen gewohnten Funktionalitäten im Webbrowser zur Verfügung.287

Der [moby:designer]dbpmbasiert auf der quelloffenen und frei verfügbaren Software Oryx288, die als webbasierte Lösung für die grafische Entwicklung von Geschäftsprozessen in diversen Modellie-rungssprachen, wie etwa BPMN, WS-BPEL, EPK oder Petri-Netzen, sowie von Diagrammen in ver-schiedenen Notationen, wie etwa UML oder FMC (Fundamental Modeling Concepts)289, am Hasso-Plattner-Institut in Potsdam entwickelt wurde. Aufgrund des modularen Aufbaus mit profunder Plug-in-Struktur sowie der Nutzung standardisierter und weitverbreiteter Webtechnologien, wie SVG (Scalable Vector Graphics)290und dem auf ECMAScript291basierenden JavaScript292 im Front-end sowie RDF (Resource Description Framework)293und JSON (JavaScript Object Notation)294 im Backend,295 war eine Anpassung und Erweiterung von Oryx um die erforderlichen Funktionalitä-ten im Rahmen dieser Arbeit realisierbar. Der [moby:designer]dbpm unterstützt das Vorgehen aus Abschnitt 4.2 zur Entwicklung der Modelle aus den Kapiteln 5 und 6.

286vgl. Spath u. a. 2012, S. 6; Vehlow und Golkowsky 2011

287vgl. Weiner u. a. 2012a, S. 90

288siehehttp://bpt.hpi.uni-potsdam.de/Oryx 289vgl. Keller und Wendt 2003; Knöpfel u. a. 2005

290vgl. W3C 2011a

291vgl. Ecma International 2011

292vgl. Mozilla Developer Network 2011

293vgl. W3C 2004

294vgl. Crockford 2006; Crockford 2011

295vgl. Tscheschner 2007, S. 11 und 31–34; Czuchra 2007, S. 10; Peters 2007, S. 3–5

Die hierfür umgesetzten Erweiterungen von Oryx und die eigenen Implementierungen werden im folgenden Abschnitt dargelegt, während die Softwarearchitektur und die Benutzung des Model-lierungswerkzeugs [moby:designer]dbpmanschließend beschrieben werden.