BPEL Simplified Syntax (simBPEL) has been edited by Matthieu Riou (Oct 25, 2007).

Change summary:

Added SimPEL proposal

(View changes)

Content:

Proposal by IAAS

Tammo and Oliver from the IAAS took your ideas and worked on a syntax for BPEL4Coders. This file is a quick summary of our results.

Main design goals:

  1. Use _javascript_ Syntax as basis
  2. Provide a 1:1 mapping to BPEL and back

We introduced implicit variable declaration, which does not fulfill the second goal, but perfectly fits to the first goal.

BPEL offers block-structured and graph-based programming. Since block-structured programming is more in-line with _javascript_, we first present on a ordering process how this is reflected in BPEL4Coders.

The commands are executed in sequential order (BPEL: <sequence>)

process OrderCheapestBook  {
	// partner porttypes - identified by QNames of their WSDL porttype
	service amazon = {http://aws.amazon.com/aws}Bookstore
	service bol = {http://bws.bol.de/bws}Bookstore

	// port types offered by the process. Since the process acts as "client" for the partner, "client" as chosen as keyword
	client me = {urn:iaas:toll}BookReseller
	
	// variable declaration. XML support is built-in: po is an XML variable, whose type is defined in a WSDL
	var {urn:iaas:ourxsd}PurchaseOrder po

	// the variable purchaseOrder is declared
	// the type is the type returned by the function me.orderBook()
	// me is a client. Therefore the semantics of function calls on that object is to wait for a partner to call. The received message is returned by the function
	// BPEL: <receive partnerLink="me" operation="orderBook" variable="purchaseOrder" />
	var purchaseOrder = me.orderBook()

	// Service declaration. Type is determined by the first assignment to it
	service res

	// Variables without direct type declaration get their type by the first assigment to them
	var tmp1, tmp2

	// Parallel execution (BPEL: <flow> instead of <sequence>.)
	// nested sequential execution can be made by "seq {...}"
	par {
		tmp1 = amazon.getDollarPriceForISBN()
		tmp2 = bol.getEURPriceForISBN()
	}

	// compiler exception
	tmp1 = tmp2 

	// TODO: compiler exception, since amazon and bol are type incompatible
	if (tmp1/@price < tmp2/@price) {
		res = amazon
	} else {
		res = bol
	}

	// me.orderBook() is a synchronous operation
	// <reply> is done by assigning a value to the operation (cf. Pascal-Syntax)
	me.orderBook() = res.buyBook()
}

Having seen the block-structured part, a simplified loan approval process is now used to illustrate the graph-based part of the language.

process LoanApproval {
	service autoAssessor = {urn:auto}pt
	service humanAssessor = {urn:human}pt
	service customer = {urn:customer}pt
	client me = {urn:me}pt

	// After the statement, links may come
	// Links are separated by commas
	// The condition is enclosed in square brackets
	// the target of a link (indicated by ->) is a label
	var request = me.request() [$request.amount < 50000]->lauto, [$request.amount >= 50000]->lhuman

	// Label "lauto" for the autoAssessor
	lauto: var risk = autoAssessor.approve(request) l1=[$risk = 'high']->lhuman, l2=[risk = 'low']->lapp

	lhuman: var hresult = humanAssessor.approve(request) [$hresult = 'approved']->lapp, [$hresult = 'rejected']->lrej

	lapp: customer.appoved();
	lrej: customer.rejected();
}

The example misses join conditions. Join conditions are put in square brackets in front of the label. To reference links in the join conditions, links have to be named. This happens by putting <linkName>= in front of the link-condition and target.

For example:

lauto: var risk = autoAssessor.approve(request) l1=[$risk = 'high']->lhuman, l2=[risk = 'low']->lapp
[l1 and l2] lapp: customer.appoved();

Scopes are enclosed in braces (prefixed by {{scope }} -> Matthieu):

// Scope
scope {
	onEvent: me.getStatus() {|msg|
		// Event handler for call at operation "getStatus()"
		// msg contains the message sent by the partner
		client.notify("processing");
	}
	onEvent: me.getExtStatus() {|msg|
		...
	}
	...
	} onFault f {
		// Fault Handler for fault f
	} onCompensation {
		// Compensation Handler
		...
	} onTermination {
		// Termination Handler
		...
	}
	...
}

There is no disambiguity in the usage of the brackets. For example, if a scope should be nested in a handler, it looks like follows:

...
} onFault f {
	scope("test") {
		...
	} onFault g {
	}
} onCompensation {
...

Future work:

  • Check whether all aspects of <assign> are covered by BPEL4Hackers
  • How should the extension activity be modeled?
    {{{XML-Code for the extension}}}
    (Three braces, because some Wiki-Syntax definitions use that for verbatim text)
  • Should activity naming be supported? (could be done via , name="..." put before/after the outgoing links)
  • Provide syntax for all BPEL activities. Especially forEach (parallel vs. non-parallel)
  • Clarify whether a grouping of clients and services is needed. - BPEL's partnerLink concept offers myRole and partnerRole. BPEL4Coders currently offers either myRole or partnerRole (you can choose between "client" and "service").
  • Describe implicit variable declaration
  • Provide a grammar for BPEL4Coders
  • Describe the transformation from BPEL4Coders to WS-BPEL 2.0

SimPEL

First a few general points:

  • Syntax is not _javascript_ but it has the same flavor.
  • We prefered language elegance over BPEL compatibility, although everything can be added back to BPEL with extensions.
  • _javascript_ code is supported natively anytime an _expression_ can be passed (rvalues) or at some specific places of the process declaration (like before the process {}).
  • Namespaces are optional. When no namespace is provided for the process, a default one is assumed.
  • Service definitions aren't necessary, we're just dealing with partner links.
  • XML is a native type and can directly be included in-line, just like E4X (including inner expressions).
  • Everything is executed in sequence (through an implicit sequence in some elements).

Optional target namespace declaration, defaults to ODE target namespace

namespace foo = "urn:/example.com"
process foo::request {
}
# Or
use namespace foo
process request {
}

Importing documents definitions. After import, elements can be referenced relatively.

foo = import "xsd|wsdl|..."
foo.portTypes.bar

Function definition in _javascript_ that returns an xpath function, plain _javascript_ inside and allows to "hook" other _expression_ languages. Those functions are also used for correlation.

function foo(msg) {
  xpath("foo/bar");
}
something.other = foo
something.other = xpath('.....')

Process definition

process foo {
  ...
}

Sequence is always easy

sequence {
}

Pick syntax, receive is the same thing without the pick wrapper

pick {
  receive(p1, o1) (msg) {
    # More BPEL code
  }
  receive(p2, o2) (msg,...) {
  }
  someVar = receive(p1, o1) (msg)
  timeout(val) {
  }
}

Flow, no links:

flow {
}

If, else if and else:

if (expr) {
} else if (expr) {
} else {
}

While:

while(i<10) {
  i = i + 1
}

Repeat until:

do {
  i = i+1
} until(i<10)

Sequential foreach and parrallel foreach are two different constructs. Allow break?

for(m = 0; m < 10; m = m + 2) {
}
forall(m = 0..10) {
}

Invoke syntax - toParts? fromParts?

foo = plink.operation(bar)

Assignment

foo = bar
foo = bar + " World"
foo = [xpath: concat(bar, " World")]

Throw, faultVar is optional:

throw faultName, faultVar

Wait, support now()+duration _expression_

wait 2m

Examples

Hello world example

process Helloworld {
  receive(client, hello) (msg) {
    msg = msg + " World"
    reply msg
  }
}

External counter example

process ExternalCounter {
  receive(my_pl, start_op) (msg_in) {
    resp = <root><count>0</count></root>
    while(resp < 10) {
      invoke(partner_pl, partner_start_op) (msg_in)
      resp = receive(partner_pl, partner_reply_op)
    }
    reply resp
  }
}

Missing stuff

The following are left out for now and need to be addressed:

  • We know that correlation will be handled with functions, the exact syntax in receive / invoke is missing.
  • Scope with all its handlers
  • Compensation
  • Flow links

Reply via email to