Tutorials

Tutorials fmannhardt Tue, 11/15/2011 - 14:39

A main goal of the YAWL User Group is to make knowledge about the YAWL system explicit. On the following pages we'd like to build up a collection of tutorials for both beginners and experienced users. You are invited to take part and help us, please use the forum "Tutorials and examples" for submissions or contact us directly info@yaug.org.

Beginner track

Beginner track robert Sat, 11/08/2014 - 21:37

Installation

Installation fmannhardt Tue, 11/29/2011 - 12:50

Use YAWL in 5 Steps

  • Prerequisite:
  • Download the most recent YAWL(currently v4.2) suiting your operating system at  GitHub.
    • YAWL is ready out of the box, so that's the edition to choose for evaluation purpose.
    • YAWL Enterprise should be used in a production enviroment, but needs more configuration and contains no additional features.
  • Install YAWL using the guided installer (Windows), during the installation you will be asked your Java installation path.
    • Afterwards there should be a folder "YAWL vX.X.XX" in your program menu (Windows).
  • Start the YAWL Engine and the YAWL Editor.
    • On Windows you may need to adapt your firewall settings.
    • As YAWL is now running on Port 8080 on your local machine.
  • Examine for example the "/misc/examples/SimpleMakeTripProcess.yawl" specification in the YAWL editor
  • Now point your browser to the url "http://localhost:8080/resourceService/" and login using the credentials "admin / YAWL"
    • Congratulations! Your YAWL system is running.
    • If you would like to evaluate some of it's features, please head on to the next tutorial "Run a sample workflow"
  • If there are any issues, please consult the YAWL manual chapter 2 for more information.

sylvieratte

Sat, 03/21/2015 - 23:47

I am trying to install YAWL 3.0 (Mac OSX Maverick). I receive the message:
- Please stop the running YAWL engine (or nay Tomcat instance).
I am not aware having any engine running. This message puzzle me. How can I get thru the install?

Automated testing with Selenium

Automated testing with Selenium mRoskosch Mon, 07/01/2013 - 23:33

Testing workflows can be a tiresome task, but automating test cases can save time and make the process easier. Martin Giesler, a student of the Bonn-Rhein-Sieg University, has created an automated test suite for the "orderfullfillment" example using Selenium. This tutorial will show how to run the test suite and what it's prerequisites are.

The Selenium IDE can be downloaded from the homepage. Note that you need version 2.2 to run with Firefox 22. Other browser can be used, but there drivers are not supported be the selenium hq. Attached to this tutorial are the files needed for selenium to execute the workflow.

Next the orderfullfillment example needs to be loaded to the YAWL Engine. The workflow and oranisational data can be found in the YAWL Installation folder in the subfolder "examples\orderfulfillment". There you should find the "orderfulfillment_customforms.yawl" workflow specification and "orderfulfillment.ybkp", which should both be uploaded in the YAWL resource service.

Now that all preparations are complete, the test suite can be run. To open Selenium, you need to open the Firefox browser that has the Selenium add-on installed and start it from the "extras" or "tools" menu:

The Selenium window will open and after loading the "TestSuite" file in the subfolder "Order Fulfillment TestSuite" of the attached archive, the window will look something like this:

Below the Base URL is a slider, that lets you specify the speed at which the test case should be executed. Keep in mind, that a too high value can cause problems in execution. Next to the slider are buttons to start the test suite. If YAWL is running, clicking the button "Play entire test suite" should run the scripts and start the test suite. During execution serveral users will log in and complete the tasks assigned to them until the workflow is completed.

Result

These test suites are important for YAWL developers as well, since adding new features can add bugs and break existing functions. If you have test suites for other example workflows, the YAWL user group would be glad to publish them for other users and doing that, make developing for YAWL easier.

Please note:
This tutorial suppose that the YAWL-Server is in operation on the same machine as your Selenium-IDE.

How do you upload a ybkp file to the resourceService?

I got the message "Only yawl files with an extension of '.yawl' or '.xml' may be uploaded." after trying.

I give the answer to myself. The ybkp file must be imported as orgData.

Important for testers: This Selenium Script does not work with YAWL3 due to changes of the HTML-Element id's

Bien que l'effet secondaire le plus fréquent soit une éruption cutanée, les huiles essentielles peuvent causer des réactions plus graves et elles ont été associées à un cas de décès.
Les huiles qui ont le plus souvent été associées à des effets indésirables sont la lavande, la menthe poivrée, l'arbre à thé et l'ylang-ylang.
Les huiles riches en phénols, comme la cannelle, peuvent provoquer une irritation de la peau et ne doivent pas être utilisées sur la peau sans d'abord être combinées avec une huile de base.
Manger des huiles essentielles n'est généralement pas recommandé, car il pourrait potentiellement être nocif et dans certaines doses fatales.
More on http://huilesessentiellesbio.info/

Selenium test for "Timeout tasks manual"

Selenium test for "Timeout tasks manual" k.schildt Sat, 01/25/2014 - 16:23


If you haven't install Selenium IDE, go to the Selenium tutorial please.
Download the data "TestSuites TimeoutTasks manual".
Please check that you have uploaded the file "TimerManualTimeout" in the control
center and check that you imported the OrgData successful in the control center.

If you haven't the file "TimerManualTimeout.yawl" or the File of the OrgData (YAWLOrgDataExport_o.ybkp), please download these from the tutorial
"Using a timer for the timeout of manual tasks".
As next check , that the roles were distributed to the right members as it is written in the table.
After that you must log out of the control center. The test starts with the login screen.


TestSuite TimeoutTasks manual part1: That test suite is for a normal run of the
workflow without a timeout failure.
Load the data " TestSuite TimeoutTasks manual part1" of the folder " Part1"
in the Selenium tool and start the TestSuite.


TestSuite TimeoutTasks manual part2: The secound test suite should represent a task
timeout for the workflow.
For that you load the data " TestSuite TimeoutTasks manual part2" of the folder "Part2 "
in Selenium.
As next you must toogle a breakpoint in the task " Comment on health" at
the first command ( screenshot) and then go to the options tab and set the time for
default time out on 5000ms.


If you start the TestSuite , the run will be stop at the break point. Wait 2 min (timeout
time) and then click on the "pause/resume" - button. The run will go on now.
The three "comment"- tasks will be fail, but the "decide"-task will be run successful.

Build a Workflow using Deferred Allocation

Build a Workflow using Deferred Allocation ahense Sun, 11/10/2013 - 15:54

We want to use deferred allocation. An insurance claim will be forwarded to a specialist depending on its content. There are specialists for health, house, car and life insurance. The complete workflow is contained in file DeferredAllocation.yawl. We will outline the steps that are necessary to create this workflow.

Organisation

The first step is to set up an organisation

First name

Last name

Roles

Username

Password

Simone

Martini

claimer

sim

pass

Jean

Pucelle

allocator

jep

pass

Ambrogio

Lorenzetti

health specialist

aml

pass

Pietro

Lorenzetti

house specialist

pil

pass

Lorenzo

Monaco

car specialist

lom

pass

Jean

Fouquet

life specialist

jef

pass

You can either enter this organisation using the control center or you can import the file YAWLOrgDataExport.ybkp.

 

Instruction to import organisation data:

Please open the control center and log in as "admin" :

 

XSD Types

 

Instruction to import data type definitons:

 

In order to have the specialist roles in a drop down list in a task, we define the following type in the data type definitions of the net:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:simpleType name="SpecialistRolesType">

<xs:restriction base="xs:string">

<xs:enumeration value="health specialist" />

<xs:enumeration value="house specialist" />

<xs:enumeration value="car specialist" />

<xs:enumeration value="life specialist" />

</xs:restriction>

</xs:simpleType>

</xs:schema>

 

Net variables

We define the following variables in our top level net:

Variable name

Type

Usage

Remarks

claim

string

Local

A text explaining the claim.

accept

boolean

Local

True if the claim is accepted – false otherwise.

role

SpecialistRolesType

Local

The type for the drop down list from the previous section.

roleString

string

Local

A „type conversion“ of variable role, because variables for deferred allocation must be of type string.

 

Two nets for the control flow

The first plan was to create one simple net for this example.

However, there is a problem: the YAWL User Manual says:

„Additionally, in the Net Parameters panel you may nominate one or more net-level variables that at runtime will contain a value of the userid of a participant or the name of a role (that is, deferred allocation). For a variable to appear in the Net Parameters panel, it must be of type ‘string’ and usage ‘Input & Output’ or ‘Input Only’.“

This means that we want to use variable roleString for deferred allocation we have to change its usage to „input“. The consequence is that we have to enter some value each time we start the workflow. (We do not know the reason for this restriction)

As a workaround we put the deferred allocation task „Choose specialist“ in a subnet and get the following two nets:

as top level containing

We define the following variables in our subnet:

 

Variable name

Type

Usage

Remarks

claim

string

Input Only

 

accept

boolean

Input & Output

 

role

SpecialistRolesType

Input & Output

 

roleString

string

Input & Output

This variable can now be used for deferred allocation in „Evaluate the claim“.

We have defined the net variables first in order to use „Decompose to direct data transfer“ as much as possible. Most of the mappings are standard an can be examined by loading DeferredAllocation.yawl into the YAWL editor.

One thing worth mentioning is the task „Choose specialist“, where we want to have our drop down list. The variable containing the drop down list is called „role“. The result of the user selection must be in variable „roleString“. The solution is an output mapping of „role“ to „roleString“ and to hide the task variable „roleString“ using extended attributes.


 

Changing the look of dynamic forms

Changing the look of dynamic forms k.schildt Fri, 05/23/2014 - 20:32

If you have ever found yourself in a position to present some YAWL workflows, but would like to use something looking a bit moe modern, then this tutorial might be something for you.

I am going to present a new stylesheet for YAWL dynamic forms, giving them a more modern feeling using some CSS techinques. Of course this means some older browsers will not be able to display these new features, but for presentation purposes, it can give you an advantage to style the forms in the corporate design or colors of the company. To show the difference between the two styles, a side by side comparison is the best way, so now the results of the face-lift:

What I have done is adding some elements, that you surely have already seen on other web sites. Here is a list of the changes:

  • the form's edges have been smoothed
  • shadows have been added to the text fields
  • fields in focus now glow in a light blue
  • buttons now have a blue color and have an hover-over effect
  • invalid fields glow red instead of the field being filled red
  • other colors have been removed to get a cleaner look
  • required fields are now marked with a "*", instead of having a yellow background

 

Attached to this tutorial is the stylesheet.css file and the star.png used for the required fields. Both files have to be copied to the sub folder "resource" of the "resourceService" folder in the webapps dircetory of your YAWL installation. To use the new .css file you may need to reload the resource service site without using the cache, because some browsers don't load the css file everytime a website is called and use the cached file instead. In the Firefox browser this is done by the keybord shortcut [Ctrl] + [Shift] +[r].

The original CSS file is already well structured, so the classes used by the dynamic form generator are marked. Here is a list of classes that I have modified to achieve the result above:

  • dynformOuterPanel - the outer panel surrounding the entire form
  • dynformSubPanel - panel that is used to group together fields
  • dynformSubPanelAlt - panel that is used alternately with dynformSubPanel to create a visual distinction
  • dynFormButton - used for the three buttons below the form
  • dynformOccursButton - used for the buttons to increase or decrease number of elements using maxOccurs
  • dynformInput - text field for a not mandatory field
  • dynformInputRequired - text field for a mandatoy field
  • dynformInputError - fields that have invalid values

With CSS you can also use effects like the hover effect on the buttons or the focus effect on the fields. Since some elements could not be changed by just editing these classes, the specifity had to be increased for the date field to take effect:

td span .TxtFld{ ... }

and the checkbox would have received the style of the other text fields, which have to be overwritten by this rule:

dynformInput.CbSpn{ ... }

CSS allows a lot of customization itself and interesting effects can be made with animations. It would be interesting to receive styles that other users have made and give YAWL users a range of styles to choose from.

Use a timer for delaying automated tasks

Use a timer for delaying automated tasks ahense Tue, 12/03/2013 - 10:46

This example uses shell execution and is written for a Linux operating system. The YAWL workflow is here: TimerAutomatedDelay.yawl

We want to build a simple workflow that uses a delay for automated tasks as it is described in the YAWL User Manual. We create a new net that uses the shell execution codelet to create files in a temporary directory. The path to the temporary directory is stored in a net variable named tmpDir. In our case the path is /tmp/.

TimerAutomatedDelay.png

We create the Delay 10 task with tmpDir as input variable. Then we go to task decomposition and mark the task as automated. We select the ShellExecution Codelet. Note that after this step the variables command and result are automatically inserted into the task. We now populate the task variable command with
        touch {/TimerAutomatedDelay/tmpDir/text()}/Delay10.

Next we set the task timer. According to the YAWL User Manual we can express 10 seconds like this: PT10S.

We set up the tasks Delay 20 and Delay 30 in an analogous way.

Go to the /tmp directory. After starting this workflow you should see files called Delay10, Delay20 and Delay30 appear after 10, 20, and 30 seconds.

 

(Notice: This tutorial is based on  YAWL version 2.2.x)

Using a timer for the timeout of manual tasks

Using a timer for the timeout of manual tasks ahense Wed, 12/04/2013 - 10:10

A common problem is the coordination of several parties. We want to give a number of participants the chance to comment on something but we do not want to wait indefinitely.
YAWL timer tasks can help here.

For the following workflow, we will be using the same ybkp file as here. The YAWL file is here.



Someone submits a claim and several specialists comment on it before a decision is prepared. The specialists only have a limited time to comment.

We start a new net with string type net variables claim, healthComment, houseComment, and lifeComment. We add a boolean type net variable accept. The task Submit claim takes claim as input and output variable and is offered to the role claimer. The task Comment on health has the claim as input variable and  healthComment as output variable. It is offerd to the health specialist. It times out two minutes after enablement (PT2M).


The other two commenting tasks are similar.


The task Decide takes the claim and the comments as input and accept as input and output variable. This task is offered to the role allocator.

k.schildt

Sun, 12/08/2013 - 14:45

Hello,

I have a problem with the "Submit claim" task,  I can offer only one submit claim task to one specialist and not to all three. And so I can't reach the task "Decide" .

 

I hope somebody can help me.

Kai Schildt

 

How to reset YAWL to its original state?

How to reset YAWL to its original state? fmannhardt Fri, 01/06/2012 - 16:25

Resetting YAWL may be useful, if you want to delete all users from the resource service at once. Also if you've been hit by a bug inside YAWL that may be related to a specification you've uploaded recently. As YAWL stores everything inside the connected database, resetting YAWL just means to restore the initial database. If you've configured YAWL to work with another database than the file based Derby database (Default with YAWL4Study), you should simply delete the contents of your database. If you are using the default Derby database do the following:

  1. Stop YAWL
  2. Remove the file "/engine/apache-tomcat-7.0.55/databases/yawldb.h2.db" (Warning: You will lose all data inside YAWL)
  3. Start YAWL

 

 


For YAWL versions prior to 2.3.5

  1. Stop YAWL
  2. Remove the directory "/engine/databases/yawldb" (Warning: You will lose all data inside YAWL)
  3. Copy the directory "/misc/yawldb" to "/engine/databases/yawldb"
  4. Start YAWL

In my Version there is no 'databases/yawldb' and also no '/misc/yawldb'.
Even deleting the whole DB-folder does not lead to success.
Is there another way then reinstalling?

Documents in Workflows

Documents in Workflows ahense Wed, 09/24/2014 - 09:29

Document handling in workflows is an important topic. Uploading and downloading documents - possibly from a document management system - is at the core of administrative activities. Fortunately, YAWL has a built-in datatype called YDocumentType for doing exactly that. So let us follow the section on document type of the YAWL user manual to see how it works.

We start the YAWL engine, open the YAWL editor, and add two tasks.

step1

We click on the first task and create a new decomposition called "Upload".

step2

We create a data variable in our net called "document" of type "YDocumentType".

step3

We now edit the data variables of task "Upload", pull the variable "document" from the net variables down to the decomposition variables. We should change the scope to "Output".

We proceed in a similar fashion with task download. The only difference being that the scope of the variable is now "Input".

That should be all. Save the file as document.yawl. We can now upload it to the running YAWL engine with the "Upload this specification to the YAWL engine"-button (7th from the left). When we start the workflow we get the following work item.

Pressing the up-arrow will give us a browse-upload dialog. After choosing a file we complete the activity and proceed to the download activity.

If you don't want to build the workflow yourself and just try the functionality the result of this tutorial is attached here.

 

ury_sazontov

Wed, 05/27/2015 - 16:58

How to define custom user type in YAWL editor 3.01 based on YDocumentType. If I specify YDocumentType for element of complex type, the Yawl editor return the error:

FIRST EXAMPLE
Input:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
<xs:complexType name="myType">
<xs:sequence>
<xs:element name="myElelment" type="YDocumentType"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>

Error:
Error: 5:54: src-resolve: Cannot resolve the name 'YDocumentType' to a(n) 'type definition' component.

SECOND EXAMPLE
I new define YDocumentType, the Yawl Editor return next error
Input:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
<xs:complexType name="YDocumentType">
<xs:sequence>
<xs:element name="id" type="xs:long" minOccurs="0"/>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

Error:
Error 2:22: [YDocumentType] is a reserved type name.

Michael Adams

Mon, 05/08/2017 - 05:11

YDocumentType is a YAWL internal type specifically designed and used to support document passing and storage within a YAWL workflow instance. As such, it cannot be redeclared, extended, restricted or used as a type for a member element of a user-defined complex type.

Configure YAWL to use database XY

Configure YAWL to use database XY fmannhardt Tue, 02/21/2012 - 18:50

Introduction

As YAWL uses hibernate as persistence layer it supports every database that Hibernate supports. (see here) All you need to do is to configure the database in the hibernate.properties file of the three web applications "resourceService", "yawl" and "workletService". This is briefly explained in the YAWL user manual section 2.4.4. In the following sections we provide detailed information to get YAWL working with different database management systems.

Databases

Regardless the database you'd like to use, there is one (since YAWL 3) configuration file you have to adjust:

  • \engine\apache-tomcat-x.x.xx\yawllib\hibernate.properties

Apache Derby

The YAWL4Study edition is pre-configured to use the embedded database Apache Derby. Although this database provides full support for YAWL it is generally not recommended to be used in a production system. For development or evaluation use it is sufficient. The database is located in the directory \engine\databases of your YAWL4Study installation. Details on building the correct connection url for Apache Derby can be found in the Derby documentation.

hibernate.properties:

## Apache Derby
hibernate.dialect=org.hibernate.dialect.DerbyDialect
hibernate.connection.url=jdbc:derby://localhost/C:/Users/UserXY/YAWL4Study-2.2.01/engine/databases/yawldb;create=true
hibernate.connection.driver_class=org.apache.derby.jdbc.ClientDriver

PostgreSQL

PostgreSQL is the default database of the YAWL enterprise edition. Therefore the easiest way to use PostgreSQL is to install the enterprise edition of YAWL and you will be asked for details about your PostgreSQL server during installation. But if you already installed YAWL4Study, you have to adjust your hibernate.properties to the following configuration. Details on building the correct connection url for PostgreSQL can be found in the PostgreSQL documentation.

hibernate.properties:

## PostgreSQL
hibernate.dialect org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.driver_class org.postgresql.Driver
hibernate.connection.url jdbc:postgresql:yawl
hibernate.connection.username yawl
hibernate.connection.password yawl

MySQL

To use MySQL you should install the YAWL enterprise edition, as MySQL is a configuration option during the installation. If you'd like to switch to MySQL later on, then adjust the hibernate.properties files as follows and add the correct MySQL JDBC Driver to the lib directory of YAWLs Apache Tomcat. Details on building the correct connection url for MySQL can be found in the MySQL documentation. You may want to choose the MySQL5InnoDBDialect instead of the usual MySQlDialect if you want YAWL to generate InnoDB tables. (Read more about InnoDB)

MySQL JDBC Driver:

  1. Download JDBC Driver from http://dev.mysql.com/downloads/connector/j/
  2. Copy mysql-connector-java-5.x.xx-bin.jar to \engine\apache-tomcat-6.0.18\lib

hibernate.properties:

## MySQL
#hibernate.dialect org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.dialect org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql:///yawl
hibernate.connection.username root
hibernate.connection.password root

MSSQL (SQL Server 2005/2008)

To use MSSQL you need to adjust the hibernate.properties files as follow and add the correct MSSQL JDBC Driver to the lib directory of YAWLs Apache Tomcat. Please note, the Microsoft JDBC Driver is not Open Source and there are other implementations available. (For Example jDTS) Details on building the correct connection url for MSSQL can be found in the MSSQL documentation.

MSSQL JDBC Driver:

  1. Download JDBC Driver from http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=21599
  2. Copy sqljdbc4.jar to \engine\apache-tomcat-6.0.18\lib

hibernate.properties:

## MS SQL Server
hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver
hibernate.connection.url jdbc:sqlserver://localhost\SQLEXPRESS;databaseName=yawl;user=yawl;password=yawl;SelectMethod=cursor
hibernate.dialect org.hibernate.dialect.SQLServerDialect
hibernate.connection.username yawl
hibernate.connection.password yawl

I am using YAWL4Study 2.3 on an Ubuntu Linux.

I set up a postgres database with a database called 'yawl' and a user 'yawl' with password 'yawl' who owns the yawl database and has administration rights.

Then I modified the three hibernate properties files like this:

**********************************************************
## PostgreSQL
hibernate.dialect org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.driver_class org.postgresql.Driver
hibernate.connection.url jdbc:postgresql:yawl
hibernate.connection.username yawl
hibernate.connection.password yawl

## H2

#hibernate.dialect=org.hibernate.dialect.H2Dialect
#hibernate.connection.driver_class=org.h2.Driver
#hibernate.connection.url=jdbc:h2:/home/ahense/YAWL4Study-2.3final/engine/databases/yawldb;MVCC=TRUE
**********************************************************

After restarting the engine, YAWL keeps using the file-based database and does not create any tables in postgres.

What am I missing here?

I tried to run with all 'hibernate.properties' files modified like in your configuration. YAWL creates the tables in PostgreSQL automatically and is running fine. Can you check the console output of YAWL (or log file if used as service) for lines like the following and post them.

- HHH000130: Instantiating explicit connection provider: org.hibernate.service.j
dbc.connections.internal.C3P0ConnectionProvider
- HHH010002: C3P0 using driver: org.postgresql.Driver at URL: jdbc:postgresql:ya
wl
- HHH000046: Connection properties: {user=yawl, password=****}
- HHH000006: Autocommit mode: false
- Initializing c3p0 pool... com.mchange.v2.c3p0.PoolBackedDataSource@518f739a [
connectionPoolDataSource -> com.mchange.v2.c3p0.WrapperConnectionPoolDataSource@

Thank you. I have tried with several fresh installations of YAWL 2.3: it keeps using the file for persistence and ignores postgres. Even renaming the three hibernate.property files didn't work.

I have tried it with YAWL 2.2: it used postgres right away after changing the hibernate.property files accordingly.

I have looked at all the files in the logs directory of tomcat but there are no lines like the ones you posted. The catalina.out looks like this:

Dec 04, 2012 3:34:22 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Dec 04, 2012 3:34:22 PM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
Dec 04, 2012 3:34:22 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 449 ms
Dec 04, 2012 3:34:22 PM org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
Dec 04, 2012 3:34:22 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.18
Dec 04, 2012 3:34:22 PM org.apache.catalina.startup.DigesterFactory register
WARNING: Could not get url for /javax/servlet/resources/web-app_2_5.xsd
Dec 04, 2012 3:34:22 PM org.apache.catalina.startup.DigesterFactory register
WARNING: Could not get url for /javax/servlet/resources/web-app_2_5.xsd
log4j:WARN No appenders could be found for logger (com.sun.faces.config.ConfigureListener).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
ContextListener: attributeAdded('com.sun.faces.ApplicationAssociate', 'com.sun.faces.application.ApplicationAssociate@4faa65fe')
Dec 04, 2012 3:34:30 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
Dec 04, 2012 3:34:30 PM org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
Dec 04, 2012 3:34:30 PM org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/21  config=null
Dec 04, 2012 3:34:30 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 8392 ms

Maybe the log4j warnings give some hints?

The log4j warnings are not about the issue. Unfortunately I can't test with Linux at the moment. Recheck if there is a file like "postgresql-9.0-801.jdbc4.jar" in the "engine/apache-tomcat-6.0.18/lib" of YAWL.

Please attach all log files (I just enabled "attaching files in comments"), that includes log files in "engine/apache-tomcat-6.0.18/bin" and "engine/apache-tomcat-6.0.18/logs". Probably it is best to upload  the whole, zipped, YAWL directory and I will have a look.

Christoph Lehnert

Thu, 10/24/2013 - 17:54

I am also using YAWL4Study 2.3.5 on an Ubuntu Linux and faced the same problem.
After adjusting the configuration file \engine\apache-tomcat-6.0.18\webapps\documentStore\WEB-INF\classes\hibernate.properties as mentioned above everything worked fine for me.

matteo spiotta

Wed, 06/08/2016 - 10:19

I'm using YAWL 4 with MSSQL 2008. All work fine aside handling YDocument. Im using YAWL with the data store service. By default the yDoc column in the YDocument table is defined as varbinary(255).
It can be extended to 8000 (maximum size allowed by MSSQL) adapting the function fixH2BinarySize in DocumentSore.java to work also for MSSQL db.
To handle bigger file I had to modify the methods getDocument and PutDocument to store and retrive document directly in/from the filesystem.
Please contact me if you solved the same problem in other ways.

Using YAWL 3.0 Repositories

Using YAWL 3.0 Repositories ahense Fri, 10/03/2014 - 15:57

YAWL 3.0 has a new functionality for storing nets, extended attributes, and data types in repositories. In real life projects it is really important to reuse parts of workflow specifications. One example are extended attributes. The field name of a variable is its technical name by default. If we want to give it a nicer name including blanks or add text above, tooltips, etc. we can do that by giving the variable in a task extended attributes. If the variable appears in ten different places, in YAWL 2.3 we had to do the editing for the extended variables over and over again. This was not only time consuming but error prone. Now the repository concept in YAWL 3.0 tackles this issue. We will build a small workflow to see how it works.

The example is about applying for some post. We define the simple type FormOfEmploymentType as follows:

We define the following net variables:

Technical name Field name Type
postDesc Post description string
formEmpl Form of employment FormOfEmploymentType
stDate Start date date
avail Available boolean

The field name is not part of the net variable but will be entered as an extended attribute of the corresponding task variable. We do this now by defining task "Choose post":

For the variable postDesc we edit the extended attributes by clicking on (=)

Apart from the label, we check that it is a text area and enter some tooltip. We do something similar to the other task variables. We start the workflow to see if all works as expected:

That looks nice - also the tooltips work when we hover the mouse over the fields. Now we will save the extended attributes in the repository in order to reuse them in task "Check availability". We go back to the extended attributes of postDesc and store it in the repository:

We give it the name of the technical variable and put the same in the description.

Now we are ready to proceed to task "Check availability". We open it in the editor and pull the required variables inside and adjust their input/output behaviour as follows:

Next we pull the extended attributes for the variables we have already defined and define some for the variable "avail". We run the workflow to see if it works.

That concludes this short tutorial. The resulting workflow is attached. In the next tutorial we will see how we can import this workflow as a subnet to another workflow using repositories.

 

 

Run a sample workflow

Run a sample workflow robert Sat, 12/27/2014 - 17:25

This Tutorial will guide you through the process of running the short YAWL example workflow "Simple Make Trip Process". With the "Orderfulfillment Workflow" there is a more sophisticated example included in each YAWL installation (Path: /examples/orderfulfillment). It is assumed that you have installed YAWL successfully and the Control Center is running.

  1. Login to the Control Center (if the YAWL engine is locally installed - http://localhost:8080/resourceService) with the administrative account (Credentials: admin/YAWL)
  2. Select the tab "Cases"
    • Select and upload the "Simple Make Trip Process" specification (Path: /examples/SimpleMakeTripProcess.yawl)
    • The  specification should appear in the "Loaded Specifications" box as on the following screenshot:
    • Click "Launch Case" to start the workflow.
  3. Select the tab "Admin Queues"
    • Because there is no organisational data loaded in YAWL the first task "register" appears as a work item in the "Unoffered" queue. These work items are net yet assigned to any participant.
    • The administrative user account can not be used to actually perform work. Therefore we need to create at least one participant, who performs the work. 
  4. Select the tab "Users"
    • Create a new participant by clicking on the "New" button.
    • Fill in details as in the following screenshot (Password: test)
    • Click on the "Add" button to save the participant. There will be a warning message about missing role, position and capability that can be safely ignored.
  5. Return to tab "Admin Queues"
    • Select the work item "register" and click on the "Offer" button.
    • Now a list containing the just created user John Smith will appear. Select John Smith and proceed to put this work item into his offered queue.
  6. Logout the administrative user and Login as Joe Smith (Credentials: joe/test)
    • The work item "register" should appear in Joes "Offered" work queue.
    • Click the "Accept & Start" button to immediately move the work item to the "Started" work queue, skipping the "Allocated" work queue. You may also click "Accept" to move the work item to the "Allocated" work queue and perform your work later on.
    • If you click on the "View/Edit" button a page with the work item appears.
    • Fill out the form as you like and click the "Complete" button to check-in the work item back into the YAWL Engine. Due to the AND-Split of the "Register" task the YAWL Engine now instanciates three tasks: "book flight", "book car", "book hotel"
  7. Logout Joe Smith and login as the administrative user
  • All three work items should be in the "Unoffered" work queue. Now you should be able to complete the whole workflow on your own. Simply assign all work items to Joe Smith, fill out the forms and complete them. Afterwards look for the "pay" work item in the "Unoffered" admins queue and repeat the steps. If the "Running Cases" box on the tab "Cases" is empty you have just completed your first YAWL workflow.

Web Service Invoker

Web Service Invoker ahense Fri, 12/12/2014 - 13:28

We will see how the web service invoker service of YAWL can be used. We will create a workflow that invokes a publicly available web service.

workflow

The first thing to check is if the YAWL web service invoker is installed. In the YAWL control panel click on Updates. In the line yawlWSInvoker check the mark if it is not checked and click Update.

We create a new workflow and a task with a new decomposition called "Invoke WS". We choose the webServiceInvoker service as the custom service of this decompostion. The editor will then insert the following three task variables:

  • YawlWSInvokerWSDLLocation
  • YawlWSInvokerPortName
  • YawlWSInvokerOperationName

We create corresponding net variables and map them to the created task variables via an input mapping.

Next we look for a simple web service that is publicly available:

http://www.service-repository.com/service/overview/877027757

shows a web service that does calculations. We can use it to add two numbers x and y and get the result. We add the net variable x, y, and Result to the net and insert two tasks that do the input and output to the user. We initialise our net variables in order to access our web sevice like this:

That's all. Workflow is attached here.

Note that all types used by the web service invoker must be simple types. This means that if you want to work with web services and use complex types you would have to call web services from codelets.

Using a timer for the timeout of manual tasks

Using a timer for the timeout of manual tasks robert Mon, 03/09/2015 - 17:32

A common problem is the coordination of several parties. We want to give a number of participants the chance to comment on something but we do not want to wait indefinitely.
YAWL timer tasks can help here.

For the following workflow, we will be using the ybkp-File which is attached.



Someone submits a claim and several specialists comment on it before a decision is prepared. The specialists only have a limited time to comment.

We start a new net with string type net variables claim, healthComment, houseComment, and lifeComment. We add a boolean type net variable accept. The task Submit claim takes claim as input and output variable and is offered to the role claimer. The task Comment on health has the claim as input variable and  healthComment as output variable. It is offerd to the health specialist. It times out two minutes after enablement (PT2M).

To set the timer first click on the task which should contain the timer. Now is on the left hand of the editor the properties table there you will find the entry "Timer". At the following picture you see how you set the timer

The other two commenting tasks are similar.


The task Decide takes the claim and the comments as input and accept as input and output variable. This task is offered to the role allocator.

 

 

Applying extended attributes to elements of complex types

Applying extended attributes to elements of complex types ahense Sat, 06/02/2018 - 16:33

In YAWL extended attributes cannot be applied directly to single elements of complex types. Let us assume that we want to display the "Comment" element of the "candidateType" as a text area.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="candidateType">
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Phone_number" type="xs:string" />
      <xs:element name="Comment" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="candidatesType">
    <xs:sequence>
      <xs:element name="Candidate" type="candidateType" minOccurs="1" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

We will demonstrate a way to solve the problem in task "Interview_candidate" of the as in the next screenshot:

The input mapping of task variable "Name" is

/Do_interview/candidates_Item/Name/text()

Variables "Phone_number" and "Comment" are treated in a similar fashion. The output mapping of task variable "candidates_item" is

<Name>{/Interview_candidate/Name/text()}</Name>
<Phone_number>{/Interview_candidate/Phone_number/text()}</Phone_number>
<Comment>{/Interview_candidate/Comment/text()}</Comment>
 

Task variable "candidates_item" is hidden using an extended attribute. Task variable "Comment" has an extended attribute "Text area". The specification is attached.

 

This solved my problem. Thanks a lot for the detailed tutorial!

Using Multiple Instance Tasks

Using Multiple Instance Tasks ahense Tue, 12/08/2015 - 13:28

Net

This tutorial illustrates the use of multiple instance tasks.

Imagine a company in the process of selecting candidates for a position. There is a task of editing the list of promising candidates when the applications are evaluated. After this is finished, a task for each candidate of the list should be created. Each task should record the results of an interview by phone. These interview tasks should be offered to all staff in the HR department.

We define the following types for candidates in the specification's data definitions:

<xs:complexType name="candidateType">
   <xs:sequence>
      <xs:element name="Name" type="xs:string"/>
      <xs:element name="Phone_number" type="xs:string"/>
      <xs:element name="Comment" type="xs:string"/>
   </xs:sequence>
</xs:complexType>
<xs:complexType name="candidatesType">
   <xs:sequence>
      <xs:element name="Candidate" type="candidateType" minOccurs="1" maxOccurs="unbounded"/>
   </xs:sequence>
</xs:complexType>

We declare a net variable candidates:candidatesType. We use this variable as input/output in task "Edit candidate". We also pull this variable into the MI-task "Interview candidates". Then we click on the button "mark as MI". If all is correct the variable is renamed "candidates_item" (see screenshot).

Editor

If we now click on the input mapping we see that the following splitter query has been created:

for $s in /candidates/*
return <candidates_Item>{$s/*}</candidates_Item>

The joining query in the output mapping looks like this:

for $j in /Interview_candidates/Candidate
return $j

The last task is called "Check candidate list" and takes the net variable candidates as input.

Now let's not touch anything and see if it works. We upload the workflow, start a case and assign the first tasks to an existing participant.

The complete spec is attached below.

Dynamic Instance Creation

Next we will explore how dynamic instance creation works. For this purpose, we open the attached spec in the editor, select "Interview candidates" and set the checkmark in the MI-attributes as show here.

We save the spec, start a new workflow, and fill in two candidates.

Next we fill in the first interview form.

In our started queue, we click the button "New Instance".

The next dialoge comes up. We have to fill in the correct XML elements.

We can now edit the corresponding work item.

 

Advanced track

Advanced track robert Sat, 11/08/2014 - 21:38

Backup a running YAWL system

Backup a running YAWL system fmannhardt Thu, 04/19/2012 - 03:07

Introduction

YAWL is build out of several independent web services. The two most important web services of a YAWL system are the YAWL Engine, responsible for actual workflow execution and state management, and the YAWL Resource Service, that manages information about the organisation (participants, roles, positions, etc.) and stores the work queues for each participant.

In almost every use case of a workflow management system like YAWL, it is crucial to retain the state of all managed workflows in any case. Usually there are multiple long-living workflows inside the system, loosing information about their state leads to a lot of work and may even result in restarting the case from scratch. Unfortunately every system may crash due to e.g. undiscovered errors, hardware failure or power outage. Then it should at least be possible to roll back the whole system to a consistent state some time before the crash occured.

Therefore a consistent backup of the complete YAWL system should always be kept at a safe place. Please note that this backup must contain the data of all YAWL web services (e.g. Engine and Resource Service) at the same state. For the scope of this article we assume those services all store their data to the same database, called YAWL database. Please note that within the standard configuration of YAWL this is the case.

Backup Database

Depending on your Database Management System (DBMS) there are different ways of doing a consistent backup of a running system. Depending on the available resource for each DBMS the process is described in detail or it is refered to external tutorials.

Backup Log-Files

YAWL offers an integrated logging feature via Log Predicates that can be assigned to tasks, conditions and (sub)-nets. If you don't use this feature, you may skip this section. But especially when a consistent state across distributed external systems is needed, YAWL logging could be very useful. (See below in section additional thoughts)

Additional thoughts

  • If a YAWL workflow interacts with external systems, such as the company’s web services or databases, the situation gets more complicated. Even though it is possible to create hourly backups of YAWLs internal state, rolling back to a consistent state across different distributed systems is far away from trivial. Maybe the logging feature of YAWL can be used as a starting point to recover those information in a case of failure.

  • There is already a PostgreSQL backup script available in the YAWL Wiki at code.google.com.

Backup Microsoft SQL Server

Backup Microsoft SQL Server fmannhardt Thu, 04/19/2012 - 03:14

Introduction

In Microsoft SQL Server there exist two models of doing a backup:

For our purpose, backup the YAWL database on a live production system, the first model is well suited. There is further information available at Microsoft MSDN.

Backup MySQL

Backup MySQL fmannhardt Thu, 04/19/2012 - 03:09

Introduction

In MySQL there is a tool called mysqldump available. To get a consistent backup you need to use the InnoDB storage engine and specify the mysqldump option --single-transaction. The backups generated by mysqldump contain the complete SQL code to recreate the YAWL database.

Backup

For example a full backup of all databases with MySQL is get by:

mysqldump --all-databases --single-transaction > yawlDatabase.sql

To backup only your YAWL database, you can specify the name (usually "yawl") by:

mysqldump --databases yaug --single-transaction > yawlDatabase.sql

Restore

To restore the YAWL database please first shutdown all running YAWL services. Then issue the following command:

mysql < yawlDatabase.sql

You may also supply username and password of a database user.

YAWL generated process log analyzed with Disco

YAWL generated process log analyzed with Disco mstamm Sat, 07/11/2015 - 00:27
YALW - Meal Workflow

In the context of our university project, “Process Mining” at Hochschule Bonn-Rhein-
Sieg
,  we  are  executing  processes  with  YAWL  and  using  Disco  to  analyze  the
process logs. Please read the whole article here YAWL generated process log analyzed with Disco.
 
In  this  article  we  are  describing,  how  we  analyzed  a  compact  YAWL  generated
process  log  with  Disco. First  of  all  we  like  to  explain  the  YAWL  process  and  the
analysis of the resulting process log  with Disco. (MealWorkflow.yawl, Meal Workflow process log and Disco project resources)

Furthermore, we will describe our self-written java tool for replacing YAWL generic resources.
(Download java tool: https://drive.google.com/file/d/0B6VLBli5s2MqSW9uMlFueGIxeUU/view?pli=1)

Creating and using Codelets

Creating and using Codelets ahense Mon, 02/20/2017 - 09:05

In this tutorial we show in three steps how to work with codelets in YAWL. We first create a codelet, install it and then invoke it from a YAWL workflow. We assume that you are familiar with editing and running workflows in YAWL.

Create Codelet

In the attached zip file you can find a codelet RandomNumberCodelet.java. In order to compile it you need the YAWL library jars from here:

https://github.com/yawlfoundation/yawl/releases/download/v4.1/YAWL_Libr…

Unzip and put yawl-lib-4.1.jar in your Java project. Also put jdom2-2.0.5.jar in your Java project (both jars are also in the zip file).

Compile the RandomNumberCodelet.java.

Install Codelet

Put RandomNumberCodelet.class  in /opt/codelets/codelet - you can choose any other directory here. Open file

../YAWL-4.1/engine/apache-tomcat-7.0.65/webapps/resourceService/WEB-INF/web.xml

and change the following parameter accordingly:

    <context-param>
        <param-name>ExternalPluginsPath</param-name>
        <param-value>/opt/codelets</param-value>

Run Codelet

Start the YAWL engine and load codeletInvocation.yawl into the YAWL editor. Run the workflow and see if a random number is displayed in the third task.

 

YAWL and LDAP

YAWL and LDAP ahense Wed, 01/13/2016 - 11:10

treesOrganisational data, user names and passwords are at the centre of the resource perspective of workflow management systems. YAWL has its own organisational model, and in the standard configuration, organisational data are entered via the control centre.

In a realistic setting, the workflow management system runs in an organisation where organisational data are registered in a central directory. The standard used here is the Lightweight Directory Access Protocol or LDAP for short. YAWL is an LDAP-enabled application in the sense that it can be configured to obtain its organisational data from an LDAP directory.

In this short tutorial we show how to configure YAWL to use an LDAP directory. Using a real-life directory can be challenging because of security aspects built into these systems. In order to see how YAWL can be connected it is easier to install an LDAP server for testing purposes locally. An excellent introduction on how to install OpenLDAP on an Ubuntu Linux is contained here:

Butcher M. Mastering OpenLDAP: Configuring, Securing and Integrating Directory Services. Packt Publishing; 2007.  

We assume now that you have installed your own LDAP server or that you know how to access a production server.

YAWL has two files where LDAP can be configured:

.../engine/apache-tomcat-7.0.55/webapps/resourceService/WEB-INF/web.xml

.../engine/apache-tomcat-7.0.55/webapps/resourceService/WEB-INF/classes/LDAPSource.properties


In the web.xml file you must set the value of the parameter OrgDataSource to LDAPSource. And you must set the parameter ExternalUserAuthentication to true.

The file LDAPSource.properties must be adapted to the LDAP server you want to connect to. The file that is shipped with YAWL is well documented and consist of two parts. In the first part, the connection parameters are set. In the second part, the properties of YAWL are mapped to LDAP attributes. We have mapped the roles attribute to employeeType in LDAP:

# Roles Attributes
# the name of the Role attribute name.
roles=employeeType


If everything is configured correctly, you should be able to see the LDAP users in the control centre.

Using Worklets and Exlets to reduce Workflow Complexity

Using Worklets and Exlets to reduce Workflow Complexity ahense Tue, 10/18/2016 - 15:51

Motivation

If you want to explain the essence of a procure to pay workflow you might want to use a diagram like this one:

It shows the "sunshine path" of a process where a request is created by a requisitioner (red), the request is approved by a manager (orange), a purchase order is created by a buyer (yellow), and the goods are selected, shipped and invoiced by a supplier (blue). The requisioner receives the goods and the buyer receives the invoice. Finally, the invoice is payed by accounts payable (blue).

It may happen of course that the request is not approved, that goods are not available or that there are complaints after the reception of the goods or the invoice. If we add this behaviour to the diagram above we get something like this:

 

Although the control flow is depicted here in a very direct way, we lose some of the simplicity and clearness of the original approach. In this tutorial, we will show how the original diagram can be directly used for an implementation that accounts for all the special cases. This can be done by using worklets and exlets.

Developing the solution step by step

The first thing we will add now is a differentiation of the task “Approve request” according to the Max_price:

 

Rules for task Approve Request
Condition Action Worklet
Max_price < 500 No approval ApproveAutomatically
500 <= Max_price < 10.000 Approval by manager -
10.000 <= Max_price < 100.000 Approval by senior manager ApproveSenior
Max_price >= 100.000 Approval by a manager and a senior manager (four-eyes principle) ApproveTwo

In order to do this we have to write and upload the worklets and then create an RDR-tree like this:

Next we want to notify the requester if the request has not been approved and then cancel the case. Since the compensating action is done in a worklet, we cannot use the retain familiar facility of the editor. We must store the userid in a variable and pass it to the worklet. This can be done with a codelet called “TaskCompleterInfo” that comes with the YAWL distrubution.

We will first create a worklet called “CreateRequestWorklet” that will always be used. It serves for hiding the technical task “Store completer of WI”.

Once we have this done we can crete a Workitem post-constraint violation rule. The actions suspend case, compensate by “NoteRejection” and cancel case are executed if the request has not been approved.

We do the same thing for tasks “Create purchase order” and “Select goods”, i. e. notify the requester in case something is not available and cancel the case.

If the goods received are not ok we want to return them and notify the supplier of this fact. For this purpose, a worklet “Return goods” is created that does this.

Furthermore, the SupplierID must be stored as well. This requires another worklet “Select goods worklet”.

 

Overview of the results

The next table shows an overview of all worklets and how they are linked to the specifications. The information is persisted in the files ProcureToPay.xrs and Return_goods.xrs.

 

Specification

Task

Rule type

Worklet

ProcureToPay

Create request

Selection

CreateRequestWorklet

 

Approve request

Selection

ApproveAutomatically

 

 

 

ApproveSenior

 

 

 

ApproveTwo

 

 

WI post-constraint

NoteRejection

 

Create purchase order

WI post-constraint

NoteRejection

 

Select goods

Selection

Select_goods_worklet

 

 

WI post-constraint

NoteRejection

 

Receive goods

WI post-constraint

Return_goods

 

Receive invoice

WI post-constraint

Note_complaint

Return_goods

Return goods

WI post-constraint

Note_complaint

 

Installation

All necessary files are attached here in a zip file. In order to install everything follow these steps:

  1. Load the Organisational data from file YAWLOrgDataExport.ybkp using the control centre.

  2. Load the specification ProcureToPay.yawl using the control centre.

  3. Load all other yawl-files as worklets using the YAWL editor.

  4. Load the rule files ProcureToPay.xrs and Return_goods.xrs using the YAWL editor.

 

Running the workflow

The workitems of the workflow are distributed to the following users:

 

User-ID

First name

Last name

Roles

req

Rudi

Quarz

Requisitioner

man1

Miro

Nantz

Manager, Requisitioner

man2

Marthe

Nox

Manager, Requisitioner

sman

Sean

Nibble

Senior Manager, Manager, Requisitioner

buyer

Berta

Ruddington

Buyer, Requisitioner

supp1

Serge

Partre

Supplier

supp2

Samantha

Picks

Supplier

ap

Amanda

Proffs

Accounts Payable, Requisitioner

All users have the password "pass".

 

Custom forms for beginners

Custom forms for beginners k.schildt Mon, 04/28/2014 - 15:19

Result of  this tutorial:

 

Introduction

This tutorial should help you to create a custom form.

At first what you need is the YAWL Engine and you need a little bit of knowledge about HTML, Java and JSP.

 

 

 

 

Preparation

At first we begin with the example of a custom form and with a workflow for integration.

All necessary files are located in the customform folder .

The first step is that you have one participant in your resource service. You can use your own participant or you create a new one.

The second step is to import the folder “transFormer” at the following folder at your YAWL Engine “…/YAWL4Study/engine/apache-tomcat-7.0.52/webapps”.

Later we will give you an explanation of the file “customformexample.jsp“.

The third and last step is to upload the specification “Custom_form.yawl” to your YAWL Engine.

 

Workflow

Now let’s take a look at the workflow



This workflow has two tasks. The first task “ShowCustomForm” has three task variables that are displayed in a custom form.


Now you have to set the destination of your custom form. In our example the location of the custom form is on the apache server of the yawl engine.

The adress of our custom form jsp-file is http://localhost:8080/transFormer/customformexample.jsp.

If you want to access the custom form from another system, then you have to change the adress to your ip-adress of your computer.


      

The next task “PrintValues” shows that the values are in the task “ShowCustomForm” now and the custom form really works.

 

Creating a custom form

The first step with the workflow is done now, we take a look at the creation of a custom form. In our example it's the file “customformexample.jsp”

To create a custom form, it is useful to use a development environment. In our example we use the development environment “Eclipse”.

Excursion to eclipse

At first we take a little excursion in creating a project in eclipse, because if you create only a jsp-file “Eclipse” doesn’t know many of your code commands.

At first we create a java project named “CustomForm” and create in the folder “src” a jsp-file named “customformexample.jsp” and we don’t use a jsp-template.

To prepare the project we right-click on the folder “JRE System-Library” select “Build Path”->”Configure Build Path”.

At the tab “Libraries”, there is a button “Add External JARs…”. Click on that and select “.../YAWL4Study-3.0beta/editor/YAWLEditor3.0beta.jar”.

Now the library of the YAWL Editor is imported to the project.

Back to the development of the custom form

Now let’s write the code “customformexample.jsp”.

Our first thing is the java code, after that we create the HTML Form, which will show to the end-user.

In order to access the java classes, we import this.



<%@ page import="org.jdom2.Element"%>

<%@ page

import="org.yawlfoundation.yawl.resourcing.rsInterface.WorkQueueGatewayClient"%>

<%@ page import="org.jdom2.output.XMLOutputter"%>

<%@ page import="org.jdom2.output.Format"%>

<%@ page import="org.jdom2.input.SAXBuilder"%>

Getting back, when ready we set the redirect URL.

String redirectURL = (String) session.getAttribute("redirectURL");

if (redirectURL == null) {

       redirectURL = request.getParameter("source");

       session.setAttribute("redirectURL", redirectURL);

}

If the cancel button has been clicked on the HTML form, we clean up any session attributes which are be set, then return to the worklist.

String submit = request.getParameter("submit");

if ((submit != null) && (submit.equals("Cancel"))) {

       session.removeAttribute("itemXML");

       session.removeAttribute("workitem");

       session.removeAttribute("handle");

       session.removeAttribute("redirectURL");

 

       response.sendRedirect(response.encodeURL(redirectURL));

       return;

}

To retrieve the workitem data’s as xml, we use a workqueue gateway client object. The url is the default value, if you use the apache server of the YAWL Server.

If you use another apache you have to place the “YResourceServiceClient.jar” at the same location.

String wqURL = "http://localhost:8080/resourceService/workqueuegateway";

WorkQueueGatewayClient wqClient = new WorkQueueGatewayClient(wqURL);

If the form has refreshed, it will be stored in a session.

String itemXML = (String) session.getAttribute("itemXML");

If the form is not refreshed, it gets the xml from the gateway. For that we get  the workitem id from the request and the user. In the following we set the variables "itemid" and "handle".

The itemXML contains the data of the work item and we save the three variables in a session, if the form would be refreshed.

if (itemXML == null) {

       String itemid = request.getParameter("workitem");

       String handle = request.getParameter("handle");

 

       itemXML = wqClient.getWorkItem(itemid, handle);

       session.setAttribute("itemXML", itemXML);

       session.setAttribute("workitem", itemid);

       session.setAttribute("handle", handle);

}

 

Now, we take a look in our example workflow, what we get in the itemXML to understand and what we have to do next.

<workItemRecord>

     <id>29.1:ShowCustomForm</id>

     <specversion>0.11</specversion>

     <specuri>TestCustomForm</specuri>

     <caseid>29.1</caseid>

     <taskid>ShowCustomForm</taskid>

     <uniqueid>0000000000000000000000004</uniqueid>

     <taskname>ShowCustomForm</taskname>

     <documentation></documentation>

     <allowsdynamiccreation>false</allowsdynamiccreation>

     <requiresmanualresourcing>true</requiresmanualresourcing>

     <codelet></codelet>

     <deferredChoiceGroupid/>

     <enablementTime>Apr:22, 2014 18:00:32</enablementTime>

     <firingTime>Apr:22, 2014 18:00:42</firingTime>

     <startTime>Apr:22, 2014 8:00:42</startTime>

     <completionTime/>

     <enablementTimeMs>1398182432267</enablementTimeMs>

     <firingTimeMs>1398182442892</firingTimeMs>

     <startTimeMs>1398182442902</startTimeMs>

     <completionTimeMs/><timertrigger/>

     <timerexpiry/>

     <status>Executing</status>
     <resourceStatus>Started</resourceStatus>

     <startedBy>admin</startedBy>

     <completedBy/><tag/>
     <customform>http://localhost:8080/transFormer/customformexample.jsp</customform&gt;
     <logPredicateStarted/><logPredicateCompletion/>

     <specidentifier>UID_d89a831b-b84e-4a33-8fce-bfcfa4083b87</specidentifier>

     <data>

          <ShowCustomForm>

                <var>Change my value</var>

                <var2>Hello World</var2>

          </ShowCustomForm>

     </data>

     <updateddata></updateddata>

</workItemRecord>

We see above, we get the “workItemRecord” with many elements, which we can show at our HTML Form for example “id”,”caseid”,”tasked”,...

We see blue coloured the element “data” that contains the element “var” and “var2”. That’s our variables which are from the scope “InputOutput” and “Input”.

Our “var3” is from scope “Output” that’s the reason why we don’t see it as an element. We don’t use it in our example, but the element “updateddata” contains the saved values, if you implement a save button in your custom form.

 

Back to the code. Now we have seen above the content of “itemXML” and  we have to prepare them with JDOM. We create three objects from type Element. “wir” contains all element from the root level from “id”,”caseid”.

 If an save button exists, "updatedData" contains elements. “data” checks updatedData contains content, if that set them as content for the form or set the element “data”.

 

Element wir = new SAXBuilder().build(new StringReader(itemXML)).getRootElement();

Element updatedData = wir.getChild("updateddata");

Element data = (updatedData.getContentSize() > 0) ? updatedData    : wir.getChild("data");

 

Next we go one level down from element data this element we define as wirData.

Element wirData = data.getChildren().get(0);

 

If the itemXML contains an error, we have to check it and put out an error message.

 

String error = null;

if (!wqClient.successful(itemXML)) {

       // show the message to the user in an appropriate way. In this case, we'll

       // simply show it on the form below

       error = itemXML;

}

 

If the itemXML is checked, then we use the else statement. In the else item we put our individual code which is in every custom form fitted to the variables of the task.

At first we read the new values as entered on the HTML form and save it in variables and then we define the names from our variables of the task, which was be modelled in “YAWL Editor”

else {

       String var_input = request.getParameter("var_input");

       String var2_input = request.getParameter("var_input2");

       String varName = "var"; //The value with input and output

       String varName3 = "var3"; //The value with only output

Then we check it. If the values of “var-input” and “var2_input” are not null and in another then we check, if the element “wirData” is not null. In that statement we define our updated Element.

In our “itemXML” example, we see that the variable “var3” is missing, so that we have the create as node.

Important! Here we have to hold the order which is defined in YAWL Editor, that’s the reason why we define the output in the editor at last and saved us a sorting of the element “wirData”.

 Now the new Element we have to add to “wirData”. After that we check in,  if the statement  “dataitem” is not null and set the text of the variable “var” and also check if “dataitem2” is not null and set the text of the variable “var3”.

 

       if (var_input != null && var2_input !=null ) {

             if (wirData != null) {

                    Element dataitem = wirData.getChild(varName); // get data var

                    Element dataitem2 = new Element(varName3); //creating the node for var3

                    wirData.addContent(dataitem2);

                    if (dataitem != null) {

                           dataitem.setText(var_input); // update data var's value

                           if (dataitem2 != null) {

                                  dataitem2.setText(var2_input);

 

The workitem has to be updated via the gateway, with the new values. After that we check, if the update via the gateway was successful and remove the session and redirect.

                                  String itemid = (String) session.getAttribute("workitem");

                                  String handle = (String) session.getAttribute("handle");

                                  String dataString = new XMLOutputter(Format.getCompactFormat()).outputString(wirData);

                                  String result = wqClient.updateWorkItemData(itemid, dataString, handle);

 

                                        // check all is ok - if so, close the form

                                  if (wqClient.successful(result)) {

 

                                        // clean up our stored session attributes

                                        session.removeAttribute("itemXML");

                                        session.removeAttribute("workitem");

                                        session.removeAttribute("handle");

                                        session.removeAttribute("redirectURL");

 

                                        // now we can redirect back to the worklist.

                                        // if you want the workitem to complete when it posts back, add

                                        // the parameter below and set it to 'true'; if it's false or

                                        // missing, the workitem will update but remain on the worklist's

                                        // 'started' queue (a 'save')

                                        redirectURL += "?complete=true";

                                        response.sendRedirect(response.encodeURL(redirectURL));

                                        } else {

                                               error = result;

                                  }//closing if(dataitem !=null)

 

At last we close the last 'if' and give them else statements.                                                                                                  

                           //This else condition gives a feedback if the varName3 is null

                           } else {

                                  error = "This workitem does not contain a variable called '"

                                               + varName3 + "'.";

                           }

                    //This else condition gives a feedback if the varName3 is null

                    } else {

                           error = "This workitem does not contain a variable called '"

                                        + varName + "'.";

                    }

             } else {

                    error = "This workitem does not contain any data for updating.";

             }

       }

}

 

HTML Code

Finally, for the web layout we need the html code. Per html it's possible to set the workitem page to their wish.
For each work item page that has same layout, you can implement a css-file in the html code.

In the following, we declare the HTML code and at which point we can implement the css-file.

 

HTML code first part

At first we determine the title of the html document. This is displayed only on the edge of the browser. Directly under the <title>, we  integrate the link to our "style.css" document.

In order for our html-code can retrieve the settings of the css-document now.

We set the size of the website and the font (in this example) in the head part.

After the <head> part, we start with the <body> for set the specific website structure.

In our example, we use the html command <h1> for our headline.

So that the html code assigned to the settings in the css file, we assign for each pattern piece a fixed id.

The css file references namely to the id. After the header, we want to show the case id and a work instruction. For this we create a table with <table> ( for more variety of our commands).

The the first row <tr> should show the output of Error, if there is one.  In the second row comes the work instruction. The command &nbsp; is used to get a space command.

In the <td> command can you set the width heigth and align for the specific column.

 

 

 

HTML code second part

As next, we divide the parameters into two fields with command <fieldset> . The input values are placed in the first field and the retrieved values in the second field ​​.

The fields we can declare individually with the  <legend> command.

In order to address the individual variables in the rows, we use the command <label>( In this example, we disabled the labels and use the legends for a fictitious example layout). With a unique label or an id, is the variable area for the css-file clearly identifiable.

After both fields, we implement the save and cancel buttons. For that we need the <input> command with the type of "submit".

 

If you have further questions, feel free to comment.

 

(Notice: This tutorial was created with build version 3.0beta.)

Using YAWL 3.0 Repositories (part two)

Using YAWL 3.0 Repositories (part two) ahense Fri, 10/03/2014 - 17:57

In a previous tutorial we showed how to use the repository of YAWL 3.0 for extended attributes. We now want to use the complete workflow of that tutorial in a new workflow as a subnet. We use the repository functionality for that.

The first thing we do is to load the workflow attached to the previous tutorial into the editor and use the net menu to store it in the repository. We also store the datatype definition in the repository.

Then we close the specification and create a new one. We first load the datatype definition from the repository.

In the new specification we load the previous specification from the repository and rename the resulting new subnet "Check post".

Now we go to the root net and connect the subnet to the composite task - the label may have to be adapted.

We proceed by defining a net variable fName:string and by defining postDesc and avail for receiving values from the subnet "Check post". We open the data variable dialog for the composite task and get this:

We change the decomposition variables postDesc and avail to scope output.

We define task Register with fName as output variable and tasks Note rejection and Note acceptance with fName and postDesc as input variables.

 

Testing the workflow shows that the mappings in the subnet are broken.

 

Two questions remain to be answered. Where is the repository stored? How can I save my repository?

The repository is here ../YAWL-3.0/editor/repository. There are a number of XML files with descriptive names. These files can be saved for future use and can be restored. A good idea seems to be to create one repository for each project.

 

 

Stylesheet for removing double complete events in YAWL XES logs

Stylesheet for removing double complete events in YAWL XES logs ahense Sat, 02/04/2017 - 16:34

YAWL creates XES logs directly from the control centre. This makes it easy to do Process Mining with tools like ProM, Disco or Celonis. There is however a little problem: YAWL creates "complete" events twice for every work item. This can be seen in file processMiningSimple0.1.xes in the attachment.

We have created an XSL sheet that removes these double "complete" events. When you apply this like this

$ saxon-xslt processMiningSimple0.1.xes transform.xsl > processMiningSimple0.1.removedDoubleComplete.xsl

you obtain the file processMiningSimple0.1.removedDoubleComplete.xsl which has been uploaded into ProM, filtered on simple heuristics and displays the process model in this picture.

Reusing YAWL specifications as subworkflows (YAWL 4.0)

Reusing YAWL specifications as subworkflows (YAWL 4.0) ahense Sat, 04/23/2016 - 11:19

YAWL 4.0 features an integrated worklet editor that makes the work of  a previous tutorial much easier. Our goal here is to use the worklet service to create a subworkflow that can be reused in many specifications. In order to demonstrate this, we will create two YAWL specifications. MainProcess.yawl is the specification for the workflow that will call the subworkflow. DisplayValue.yawl is the one that will be called. You can find the specs attached below. Let us now start step by step.

Upload the Worklet

Make sure that your YAWL editor is connected to a running YAWL engine. Open DisplayValue.yawl in your YAWL editor and store it as a worklet.

Add a Rule to the Main Workflow

Close this specification and open MainProcess.yawl. Then add a rule to this specification.

The rule type must be set to "Worklet Selection". The task must be set to "ShowValue". Note that the custom service in the decomposition of task "ShowValue"  must be set to the worklet service (this is already the case in our specification).

The condition is set to the constant "true" because we always want to use the same worklet.

In the "Actions" section we have to select the action "select" ...

and choose our worklet DisplayValue as the target.

Now the dialogue should look like this.

We click "Add & Close" and hopefully get the following message of success.

Export the Rule Set

This step is optional. Exporting the ruleset allows you to reuse it later in another YAWL engine. There is a button for exporting the rule set.

The following selection dialogue appears. Note that the rule set is associated to the specification and its version.

Store the file MainProcess.xrs somewhere. It will look similar to this.

The main process is identified by its name, its version, and its unique identifier. The worklet is identified by its unique identifier only.

Deploy the Workflow

Next we will upload MainProcess.yawl using the button in the editor.

Now we are ready to test if it works. We start a case for MainProcess and assign the workitem ShowValue to some existing user. When the user views the work item it should look like this:

It is important that it says "Display value". If it says "ShowValue" it is not the worklet but the default behaviour of the MainProcess that is displayed.

 

Working with Data Gateways

Working with Data Gateways ahense Sun, 03/01/2015 - 15:42

This tutorial is written for YAWL 4.x and replaces a previous tutorial for YAWL 2.3.

In addition to using net variables in YAWL we can also store and fetch data directly from a database. In this tutorial we show how to retrieve data from a simple database table using a YAWL Data Gateway. In the previous tutorial for YAWL 2.3 Microsoft database was used. Here we will demonstrate the case with PostgreSQL. We assume that you are familiar with the basics of databases and have installed PostgreSQL and pgAdmin.

We start by creating a new database with name "CustomerDB" and owner "postgres" having password "postgres". In this database we create a table "Customers" with owner "postgres". We create columns ID:integer (primary key), Name:text, Age:integer and fill it with some data:

When we click on the magnifying glass symbol in pgAdmin while table "Customers" is selected we get the SQLeditor. There we choose the tab "Graphical Query Builder", navigate to table "Customers", select "Name" and "Age", and click on the green triangle. We should get the following query:

SELECT
  "Customers"."Name",
  "Customers"."Age"
FROM
  public."Customers";

Now we create a new Java project named "yawlDataGateway" in Eclipse or Netbeans. We download the YAWL Library Jars, unzip them and add the yawl-lib-4.1.jar and YResourceServiceClient.jar to the build path. Furthermore, you need jdom-2.0.6.jar and hibernate-core-4.3.11.Final.jar in the build path.

The code of the class MyExternalDBGatewayImpl is attached here. We deploy yawlDataGateway.jar to ../webapps/yawl/WEB-INF/lib. We restart the YAWL engine and the editor.

We build a simple YAWL workflow as attached here. If everything works correctly, it should look like this:

 

The Java code is a quick hack - not very robust. Who has a more elegant solution?

riyaz.lakhani

Fri, 07/10/2015 - 13:32

Hi Ahense,

I am getting below error (screenshot attached) while using same .yawl or .java file to retrieve data using Data Gateways.
1.Error_in_browser.JPG
When I am loading (same) dataGateway.yawl

2.Yawl_Specification.jpg
- Java class name is available under Data Gateway properties
-Suggest us location to put .class file (if any fixed location)

3.Error_in_Mapping.JPG
Error while binding

Referring same tutorial suggested by you : http://www.yaug.org/content/working-database-gateways
YAWL Version:3.0.1

Thanks in advance for your help
Riyaz

I get the same "not found" error when the compiled jar file yawlDataGateway.jar (here included in dist.zip) is not in the right place. This file goes to .../webapps/yawl/WEB-INF/lib.

Furthermore, the data gateway is not used at net level as in your screenshot but on task level as below.

data binding

Tutorials till version 2.3.5

Tutorials till version 2.3.5 robert Sat, 11/08/2014 - 21:31

Here you will find all Tutorials which are written for the YAWL 2.3.5

Beginner track

Beginner track fmannhardt Fri, 11/18/2011 - 16:43

Multiple Instance Atomic Task and Composite Task

Multiple Instance Atomic Task and Composite Task k.schildt Mon, 12/16/2013 - 07:43

Multiple Instance Atomic  Tasks or Composite Tasks can be used to create a defined or dynamic number of tasks or subnets in a workflow. This can be used to create a work item or subnet  for every element in a list of elements. In combination with other YAWL mechanisms, this can be used to distribute work items to a dynamic list of users or roles during runtime. In this tutorial however, I will show how to create a Multiple Instance Task, that will have as many instances as there are objects in a given list. The mechanism for Multiple Instance Atomic Tasks and Multiple Instance Composite Tasks is the same and the latter will be used to create a whole net with the instantiated variables instead of just a single task.

First, let’s create data types that can be used. I have created four data types:

  • Object is an abstract container of information with a String an a Boolean variable
  • ObjectContainer holds an unlimited number of Objects
  • ObjectWithComment is the Object data type with an additional String “Comment”
  • ObjectWithStringContainer holds an unlimited number of ObjectWithComment

And here is my data type definition:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="Object">
    <xs:sequence>
      <xs:element type="xs:string" name="String" />
      <xs:element type="xs:boolean" name="check" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ObjectContainer">
    <xs:sequence>
      <xs:element type="Object" name="Object" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ObjectWithComment">
    <xs:sequence>
      <xs:element type="xs:string" name="String" />
      <xs:element type="xs:boolean" name="check" />
      <xs:element type="xs:string" name="comment" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ObjectWithCommentContainer">
    <xs:sequence>
      <xs:element type="ObjectWithComment" name="ObjectWithComment" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The Idea is that there should be as many instances of the task created as there are Objects in the ObjectContainer. In addition these objects should be enriched by a comment  and converted to the ObjectWithComment with it's Container. The words in "name" are the name of the different variable  or task names.

I have created a simple workflow with three tasks. It contains three net variables, one of each container data type named after it and String variable with the name "Test", all three net variables has the usage setting 'local' . The first task("Fill Object Container") is a simple atomic task used to fill the ObjectContainer as an output parameter. Followed by this task should be the Multiple Instance Atomic Task ("Distribute Objects") with the ObjectContainer net variable as input parameter and the ObjectWithCommentContainer net variable as an output parameter. Furthermore the task should contain a task variable("Object") of the Object type and a task variable ("Comment") of the String type. The last task will be used to check if everything worked as intended and has the ObjectWithCommentContainer net variable as an input parameter.

In the editor, the tools for Multiple Instance Atomic Task and Multiple Instance Composite Task can be found next to the symbol for “Add a new Atomic Task” and  Add a new Composite Task” respectively. After a new Multiple Instance Task is created, a right click on it will show the option “Set Instance Detail”. This Option is divided by two tabs. Under “Bounds” you can define the minimum and maximum number of tasks or nets created. Be aware that, if more or less tasks or nets are created then defined error will occur and prevent further execution of the workflow. The "Continuation Threshold" defines after how many completed instances of the task or net the task should be declared as finished to move the the next task in the net. If set to "infinite", then all instances of the multiple instance task or net have to be completed. Instance Creation means, that more instances of the task can be created at runtime after task execution has begun and split into its instances (taken from the YAWL User Manual).

The next tab "Queries" is more complicated to correctly fill in and be aware that all inputs are case sensitive and often source of errors. It consists of two drop downs and four fields:

  • The first drop down "Multiple Instance Variable" is used to define the task or net variable that will contain the instantiated information that is splitted in the following queries. Here it will be a task variable called "Object" with the type "Object".
  • The second field "Accessor Query" points to the information, that is to be splitted. Here it will point to the net variable containing all Objects. 
  • The third field "Splitter Query" should contain the logic to generate the single objects, that can be distributed to the single instances. In this example the query will split the ObjectContainer it its Object elements.
  • The fourth field "Instance Query" should define the output object of the instance and make sure it is formatted correctly. For this example a new element is created named "ObjectWithComment". It contains all information of the Object element, as well as an additional element called "comment", which will contain the contents of the task variable "comment" of the Multiple Instance Atomic Task.
  • The fifth field "Aggregate Query" puts together all information of all instances into a single list. Here every Object created by the Instance Query should be retruned as is.
  • The sixth and last is the Result Net Variable drop down. Here you choose the net variable that, should contain all aggregated information.  As of version 2.2 it is stated in the manual that outer brackets are optional, however leaving the brackets out resulted in errors for me.

So here is a sceenshot of the Query tab of my Multiple Instance Atomic Task:

 

With that finshed, all that is left is to define a resource for the tasks and upload the specification to the engine.

Attached to this tutorial is the workflow specification.

 

(Notice: This tutorial is based on  YAWL version 2.3.x)

k.schildt

Sun, 12/15/2013 - 13:40

 

The tutorial is well understood, but there is a statement that is irritating.
The variables in the multiple atomic task can not be explained exactly. According to the text you think, you should declare four variables, rather than declare two variables.
 

As next the user don't know, how to name the 3 tasks. He learns it only in  part, if you should  set the "Instance queries".

At last the statement in the Aggregate Query isn't correct. The braces must be omitted. For a succesfull statement.

 

Greetings,

Kai Sch.

Using the Twitter service

Using the Twitter service mRoskosch Mon, 07/15/2013 - 11:52

One of the optional services in YAWL is the YAWL twitter service. If properly configured, it can be used to update the statuses of user and inform them of available work items for example. But getting it to work can be tricky, as the current version on sourceforge is not working, because Twitter updated their API. For this reason, there is an .war file attached to this article, that includes a working version of the Twitter service. It was originally written by Michael Adams, I only added a newer version of the twitter4j library and changed one line of code from:

Twitter twitter = new TwitterFactory().getInstance();

to

Twitter twitter = new TwitterFactory().getSingleton();

With that out of the way, now how to make it run with your own twitter account.

Deploying and configurating the twitter service

To deploy the Twitter service on your YAWL installation, simply copy the attached .war file to your YAWL installation folder into the subfolder "engine\apache-tomcat-6.0.18\webapps". After you start the YAWL engine, the tomcat webserver will automatically deploy the Twitter service from that file. The .war file is currently configured for this twitter account.

Now, that the service is properly deployed, you can register it with the YAWL resource service. Log in as an admin and go to ther "Services" tab. There, add a new service with the following parameters:

You can now select the Twitter service in the YAWL Editor and update your status via workflow.

The attached workflow will ask for an update message as input and then update the status of the configured account accordingly.

How to make the twitter service run with your own twitter account, will be explained in the next section.

Setting up the twitter service with another account

First, you will need to add the YAWL service to the allowed applications of your twitter account. To do that, you have to go through the authorization process. Attached to this tutorial, you will also find a jar file, which is the easiest way of obtaining the necessary keys. You can execute the jar file by using the console with the command "java -jar twittering.jar". Inside that jar file is a class "twittering", which is based on the code of the twitter4j examples here. This class will be executed by the command above and when run, it will show a link, that will prompt you to log in to your twitter user and authorize the YAWL app:

After that, a number is shown, and you will need to insert that number in the console to proceed:

If everything is done correctly, you will receive two keys. These keys need to be saved in the twitter4j.properties file of the twitter service, so YAWL can connect to your account. Open the "twitter4j.properties" file in the directory "[YAWL install dirextory]\engine\apache-tomcat-6.0.18\webapps\twitterService\WEB-INF\classes", which should look like this:

Change the values of the keys "oauth.accessToken" and "oauth.accessTokenSecret" with the values you got from executing the twittering.jar file, to make the twitter service work with your account. A restart of YAWL will be necessary to  make the changes take effect. The twitter service should now use your account. Thats it!

 

(Notice: This tutorial is based on  YAWL version 2.3.x)

Advanced track

Advanced track fmannhardt Fri, 11/18/2011 - 16:29

Persistence with the Hyperjaxb3-Framework

Persistence with the Hyperjaxb3-Framework mRoskosch Thu, 06/13/2013 - 20:03

YAWL can be used in rapid prototyping to quickly create workflows with forms, but if you want to persist the data in the workflow, you usally have to create your own persistence layer and classes. The Hyperjaxb3-Framework allows persisting data types defined in the XML-Schema with hibernate. You only need to input a valid XML-Schema of the data types you want to persist and Hyperjaxb3 automatically generates all persistence classes and methods. This tutorial basically builds on top the Hyperjaxb3 tutorial here. In this tutorial, we take the .jar file generated by the Hyperjaxb3 tutorial containing the persistence classes and use it to persist an instance of the data type. The data type will be input by a user in the generated YAWL forms and saved by a very simple codelet. All files will be provided to test on your own YAWL environment and you can try this comfortable persistence method without having to write a line of code.

The first step was adjusting the XML-Schema data type from the Hyperjaxb3 tutorial and make it work with the YAWL automatically generated forms. Basically all "attributes" and "ref" elements have been transformed to normal string type elements:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <xsd:annotation>
    <xsd:documentation xml:lang="en">
      Purchase order schema for Example.com.
      Copyright 2000 Example.com. All rights reserved.
    </xsd:documentation>
  </xsd:annotation>

  <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>

  <xsd:element name="comment" type="xsd:string"/>

  <xsd:complexType name="PurchaseOrderType">
    <xsd:sequence>
      <xsd:element name="shipTo" type="USAddress"/>
      <xsd:element name="billTo" type="USAddress"/>
      <xsd:element name="comment" type="xsd:string" minOccurs="0"/>
      <xsd:element name="items" type="Items"/>
      <xsd:element name="orderDate" type="xsd:date"/>
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
      <xsd:element name="street" type="xsd:string"/>
      <xsd:element name="city" type="xsd:string"/>
      <xsd:element name="state" type="xsd:string"/>
      <xsd:element name="zip" type="xsd:decimal"/>
      <xsd:element name="country" type="xsd:NMTOKEN" fixed="US"/>
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity">
              <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                  <xsd:maxExclusive value="100"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="USPrice" type="xsd:decimal"/>
            <xsd:element name="comment" type="xsd:string" minOccurs="0"/>
            <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
            <xsd:element name="partNum" type="SKU" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>

  <!-- Stock Keeping Unit, a code for identifying products -->
  <xsd:simpleType name="SKU">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="\d{3}-[A-Z]{2}"/>
    </xsd:restriction>
  </xsd:simpleType>

</xsd:schema>

If you completed the Hyperjaxb3 tutorial, you should have a class to test persisting and loading xml-formatted data types. The following class has been created by me and has the method start(..), that can persist a string of the XML-Schema type "purchaseOrderType" defined above and returns the id in the database:

public class Helper {
    
private JAXBContext context;

private ObjectFactory objectFactory;

private EntityManagerFactory entityManagerFactory;
    
public long start(Object o) throws Exception{
    
    setUp();
        
    final Object object;
    final Unmarshaller unmarshaller = context.createUnmarshaller();
    final PurchaseOrderType purchaseOrder;
       
    if(o!=null){
        String purchaseOrderString = (String) o;
        InputStream stream = new ByteArrayInputStream(purchaseOrderString.getBytes("UTF-8"));
        object = unmarshaller.unmarshal(stream);
        purchaseOrder = ((JAXBElement<PurchaseOrderType>) object).getValue();
    }else{
    
    object = unmarshaller.unmarshal(new File("src/test/samples/po.xml"));
    purchaseOrder = ((JAXBElement<PurchaseOrderType>) object).getValue();
    
    }
    
    long id = persist(purchaseOrder);
    
    return id;
    }


public long persist(PurchaseOrderType purchaseOrder){
    try {
        setPersistenceProperties();
    } catch (IOException ex) {
        Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    final EntityManager saveManager = entityManagerFactory
    .createEntityManager();
    saveManager.getTransaction().begin();
    saveManager.persist(purchaseOrder);
    saveManager.getTransaction().commit();
    saveManager.close();
    
    return purchaseOrder.getHjid();
}

public String loadAsString(long id){
    final EntityManager loadManager = entityManagerFactory
        .createEntityManager();
    final PurchaseOrderType beta = loadManager.find(
                    PurchaseOrderType.class, id);
    
    final Marshaller marshaller;
    OutputStream os = new ByteArrayOutputStream();
    
    try {
        marshaller = context.createMarshaller();
        marshaller.marshal(objectFactory.createPurchaseOrder(beta), os);
    } catch (JAXBException ex) {
        Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
    }
    
    loadManager.close();
            
    return os.toString();
}


public void setPersistenceProperties() throws IOException{
    
    final Properties persistenceProperties = new Properties();
    InputStream is = null;
    try {
            is = getClass().getClassLoader().getResourceAsStream(
                            "persistence.properties");
            persistenceProperties.load(is);
    } finally {
            if (is != null) {
                    try {
                            is.close();
                    } catch (IOException ignored) {
                    }
            }
    }

    entityManagerFactory = new Persistence().createEntityManagerFactory("generated", persistenceProperties);
    }  

protected void setUp() throws Exception {
    context = JAXBContext.newInstance("generated");
    objectFactory = new ObjectFactory();
    }
    
public void setUpPersistence() throws Exception {
    entityManagerFactory = Persistence.createEntityManagerFactory("generated");
    }

}

The start(..) method transforms the string into a class, that has been generated by the Hyperjaxb3 framework, and represents it. After initialization, the object is given to the entitiyManager, which saves it in the database. This class loads the information for the database connection from the file "persistence.properties". If you want to try it out on your system, you will have to change the parameters in the file "persistence.properties" in the "hyperjaxb3-ejb-template-basic-maven-0.5.6.jar". In this tutorial, the database used is postgres on the default port 5432 and the name of the database is "hyperjax".

In NetBeans the tutorial project needs to be built and the resulting jar file contains the above helper class, persitence properties and all java representations of the XML-Schema data types. Now a codelet has to call the method in the helper class. We have a tutorial on how to create a codelet here. With the above 'helper' class, the codelet has to get the purchaseOrderType XML-Element, transform it to an XML-String and call the start method:

public class HyperJAXBCodelet extends AbstractCodelet {

    public HyperJAXBCodelet(){
        super();
        setDescription("This is a HYperJAXB test codelet");
    }

    @Override
    public Element execute(Element inData, List<YParameter> inParams,
            List<YParameter> outParams) throws CodeletExecutionException {
        
        super.setInputs(inData, inParams, outParams);
            
        Element order = inData.getChild("purchaseOrder");
        
        Helper h = new Helper();
        
        XMLOutputter xml = new XMLOutputter();        
        
        long id = 0;
        
        try {
            id = h.start(xml.outputString(order));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        setParameterValue("hjid", ""+id);
        
        try {
            
            getOutputData().addContent(new Element("purchaseOrder"));
            
            getOutputData().getChild("purchaseOrder")
                    .addContent(stringToElement(h.loadAsString(id)).cloneContent());
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return getOutputData();
    }

    private Element stringToElement(String string) throws JDOMException, IOException {

        SAXBuilder builder = new SAXBuilder();
        Reader in = new StringReader(string);
        Document doc = null;
        Element root = null;
        
        doc = builder.build(in);
        root = doc.getRootElement();
        
        return root;
    }

}

 

After saving the element via the start(..) method, the element is loaded from the database as an XML-String with the loadAsString(id) method of the 'helper' class using the hyperjax id. The XML-String is converted back to the "Element" type YAWL is using and passed on to use in the workflow. All files, that are needed to this tutorial are attached. If you want to use the Hyperjaxb3 framework with YAWL, you will need to add a few libraries, that are in the libs folder of the attached archive. Add these libraries to the tomcat libs folder. To change the persistence connection, you need to change the persistence.properties file in the "hyperjaxb3-ejb-template-basic-maven-0.5.6.jar" file. A workflow to test the codelet has been included as well. Copy the codelet class file "HyperJAXBCodelet.class" to the codelet folder of the resource service: "\YAWL4Study-2.3final\engine\apache-tomcat-6.0.18\webapps\resourceService\WEB-INF\classes\org\yawlfoundation\yawl\resourcing\codelets" to be able to execute the workflow properly.

In conclusion, it is possible to persist complex XML-Schema data types using the hyperjaxb3 framework. The persistence is not dynamic, because the java objects of the have to be build first, but once that is done, entries can easily be persisted and loaded from the database using the hyperjax id.

 

In the attachment you will find:

  1. NetBeans project with the helper class and adjusted XML-Schema
  2. The workflow you can use to try out persistence with the hyperjaxb3 framework
  3. The codelet, that is execeuted in the workflow to save and load instances of the adjusted purchaseOrder type
  4. The libraries you need to run the hyperjaxb3 framework and this tutorial on YAWL 2.3

(Notice: This tutorial is based on  YAWL version 2.3.x)

Christoph Lehnert

Thu, 10/24/2013 - 20:44

There might be problems with the HyperJAXBCodelet if you are using YAWL4Study 2.3.5. In this case try to compile it with org.jdom2.Element and org.jdom2.Element instead of using org.jdom.Element and org.jdom.Element.

Changing the default port

Changing the default port MDames Tue, 10/22/2013 - 13:45

YAWL runs on Tomcat with the default Port 8080. To change this port to for example 8090 you have to change all of the URLs in the web.xml deployment descriptors in the webapps folder as well. Otherwise the custom services will not find a running YAWL instance.

Attention: Please change all ports before you first startup YAWL. It seems, that YAWL stores URLs within its database and refers to it later. Otherwise you must find the entries and change them also.

Let's assume that YAWL_HOME is C:\YAWL4Study-2.3.5final, then you should change all occurences of port 8080 to 8090 in the following files:

  • YAWL_HOME/engine/apache-tomcat-6.0.18/conf/server.xml - which is the tomcat configuration file.
  • YAWL_HOME/bin/startup.bat / or .sh
  • YAWL_HOME/engine/apache/tomcat-6.0.18/webapps/yawl/WEB-INF/classes/defaultClients.properties
  • YAWL_HOME/engine/apache/tomcat-6.0.18/webapps/yawl/WEB-INF/classes/org/yawlfoundation/yawl/engine/defaultClients.properties
  • All web.xml files under YAWL_HOME/engine/apache-tomcat-6.0.18/webapps must be checked and changed.
    • Under Windows it is easy to find all of these. Just type web.xml within the folder /webapps in the explorer's search box and open the found files to changed the port (see picture below)
  • After YAWL starts up normally (no errors, that services can not be found). You can acces the control panel under http://localhost:8090/resourceService/faces/Login.jsp
  • You should also set the engine connection to the new port in YAWL editor (under Settings menu entry)

 

 

 

(Notice: This tutorial is based on  YAWL version 2.2.x)

Creating a codelet

Creating a codelet mRoskosch Sun, 01/08/2012 - 19:06

A codelet is a simple way of performing operations on task data using Java. In this tutorial, I will create a simple codelet based on the example codelet and explain how to use codelets in workflows. The codelet I am going to create will receive an int as an input variable and the output will be a random number, the maximum being the input number. Of course it is possible to do much more complicated work with codelets, for example load and save data to a database, but the recommended method for that would be an external database gateway.

 

After starting your favourite IDE, you should create a new project and add the standalone .jar of your YAWL version to the libraries of the project. Next you should create a new class and choose a package for the codelet. The default package for YAWL codelets is "org.yawlfoundation.yawl.resourcing.codelets", wich I will be using. The codelet you create should extend the abstract codelet to work properly. We will be creating a constructor for the new codelet and at least two methods. Here is the the constructor for my RandomIntCodelet:

 

    public RandomIntCodelet(){
        super();
        setDescription("This codelet returns a random int, its maximum being the input int.<br> " +
                "Required parameters:<br> " +
                "Input: max (int) - maximum value of randomized number<br>" +
                "Output: r (int)");
    }

The "setDesciption" method lets you define the text, that will be displayed in the codelet menu in the editor for your codelet.

The method, that will be called, when the codelet is executed is "execute":

    public Element execute(Element inData, List<YParameter> inParams,
            List<YParameter> outParams) throws CodeletExecutionException {
        // set the inputs passed in the base class
        setInputs(inData, inParams, outParams);
        
        int max;
        
        try{
            max = Integer.parseInt((String) getParameterValue("max"));
        }
        catch (ClassCastException cce) {
            throw new CodeletExecutionException("Exception casting input values to " +
                                                "int types.") ;
        }
        
        
        //create a random number between 1 and max (input)
        Random generator = new Random();
        int r = generator.nextInt(max) + 1;
        
        //set the value for the output parameter
        setParameterValue("r", String.valueOf(r));
        
        return getOutputData();
    }

As you can see, the method is quite simple in this example. The arguments for the method are the calling workitem's data "inData", the input parameters "inParams", and the output parameters "outParams". If you have input parameter for your codelet, you need to cast or transform them, so you can use them. They are accessed by the "getParameterValue" method (the argument being the name of the input variable). In my codelet, I needed to transform the input to the type "int", which I did in the try block. After that I generated a random number. This is basically the place, where you insert your own code. Finally, if you have output parameters, you need to set them via the "setParameterValue" method for each parameter.

If your codelet will be long running you will need to define the "cancel" method, that will be called if the task is cancelled while being processed. My codelet is rather short so it doesn't really need it:

public void cancel(){}

The last method is the "getRequiredParams" method. It is called when the codelet is selected in the editor and helps to automatically add the needed task variables to the task, so you only need to define the mappings to the task:

    public List<YParameter> getRequiredParams() {
        List<YParameter> params = new ArrayList<YParameter>();

        YParameter param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName("int", "max", XSD_NAMESPACE);
        param.setDocumentation("maximum random number");
        params.add(param);

        param = new YParameter(null, YParameter._OUTPUT_PARAM_TYPE);
        param.setDataTypeAndName("int", "r", XSD_NAMESPACE);
        param.setDocumentation("randomized number");
        params.add(param);
        return params;
    }

One after another, the parameters are created and defined. If the parameter is of the input type, you use "YParameter._INPUT_PARAM_TYPE" in the constructor otherwise "YParameter._OUTPUT_PARAM_TYPE", the first argument stays "null" in this case. Next the data type and name is set, here both parameters are of the type int and their names being "max" for the input parameter and "r" for the putput parameter. Following this is the documentation and adding the parameter to the parameter list.

After you have compiled your codelet, you need to copy it to correct location in your YAWL installation in my case "[YAWL INSTALL DIR]\engine\apache-tomcat-6.0.18\webapps\resourceService\WEB-INF\classes\org\yawlfoundation\yawl\resourcing\codelets". If the editor is connected to the engine, you can select the codelet from the list of codelets and use it in your workflows.

 

(Notice: This tutorial is based on  YAWL version 2.2.x)

I placed the file in the specified directory, but it doesn't appear in the editor. What is required for the new class to appear in the editor?

fmannhardt

Thu, 05/16/2013 - 13:43

Did you restart YAWL?  Which version of YAWL do you use? You also need to start the YAWL Engine as mentioned here:

If the editor is connected to the engine, you can select the codelet from the list of codelets and use it in your workflows.

riyaz.lakhani

Fri, 02/21/2014 - 06:35

I have tried codelet for RandomIntCodelet and SampleCodelet(In built in the list) in latest version of YAWL(2.3.5) It is giving me below error:

Exception in thread "18.1:unnamed:codelet"
java.lang.abstractMethodError:
org.yawlfoundation.yawl.resourcing.codelets.AbstractCodelet.execute(Lord/jdom2/Element;Ljava/util/ListLjava/util/List;)Lord/jdom2/Element;

But the same Specification and Codelet is working in YAWL2.3 version.

Hey,
when i put your RandomIntCodelet.class into the specified folder everything works just fine. But if load the .java into my IDE (Eclipse luna) and create my own .class, put it to the folder again it doesnt work. No more codelets are shown in the editor at all. Same happens if i create my own desired codelet. So what did i do wrong while creating the class file out of the java file? (your .class file is also bigger regarding the kB)

YAWL Version: 2.3.5 (works neither on 2.2.x)
Java Version: 1.7

Creating a custom organisation data source

Creating a custom organisation data source mRoskosch Thu, 08/08/2013 - 23:06

YAWL has its own organisation data with user, roles and much more. But if you already have organisation data in another system and YAWL is supposed to build on top of that, you will need to create your own custom organisation data source to let YAWL use the data from that source instead of the YAWL database.

You can change the implementation of the data source class YAWL is using by changing the parameter value of the parameter "OrgDataSource" in the "web.xml" file in the resourceService folder of your YAWL installation. The new value should match the class name of your implementation and it has to be in the same folder and package as the other DataSources. If you create your own organisation data source, you need to create a class extending the "DataSource" class in the YAWL package "org.yawlfoundation.yawl.resourcing.datastore.orgdata".  What happens is, when YAWL starts up, the resourceManager class uses a DataSourceFactory to create an instance of the data source specified in the web.xml file. After an instance is created, the method "loadResource(...)" is called, which is supposed to return an object of the type "ResourceDataSet" containing all of the organisational data. This is where you will have to put in some work and map the existing data to the YAWL model.

Generally YAWL organisational data can be complex and consist of these data:

  • Roles - roles are used in YAWL to assign work-items to a group of participants having that certain role
  • Capabilities - skills that users have, it is possible to allocate work items to user with certain capabilities
  • Positions - another attribute for users in a system describing a unique job in an organisation
  • OrgFroups -  a functional group of positions
  • Participants - the users of a system containing rights, credentials and references to roles, capabilities and positions that the users have
  • nonHumanResources -  list of non human resources
  • nonHumanCategories - list of categories the nonHumanResources belong to

All of which are objects in the ResourceDataSet the DataSource has to return in the loadResource() method. To create a minimal DataSource not all of the element above are necessary. A working DataSource can consist of as little as users and their roles.

Therefore for this tutorial I have created in simple implementation of the DataSource class that maps existing users and roles from a Liferay database to YAWL. You can find a guide on how to install Liferay here. If you don't want to install Liferay, but still test the DataSource, attached to this tutorial is the file "Liferay-Tables.zip", which contains the backups of these Postgres tables. My DataSource uses a data access object, which loads the required data with SQL scripts and the corresponding JDBC driver. In my case Liferay is running on a Postgresql database and the important information can be found in the tables "user_", "role_" and "users_roles". Since every configuration is different, I will not go into detail about how to set up the JDBC connection. As mentioned above, the loadResource() method is important, and here is my version in my liferay DataSource class:

    public ResourceDataSet loadResources() {

        ResourceDataSet ds = new ResourceDataSet(this) ;

        // These Elements of the org data will be ignored   
        ds.setCapabilities(new HashMap<String, Capability>(), this);
        ds.setOrgGroups(new HashMap<String, OrgGroup>(), this);
        ds.setPositions(new HashMap<String, Position>(), this);

        ds.setRoles(loadRoles(), this);
        
        ds.setParticipants(loadParticipants(ds), this);
        
        ds.setAllowExternalOrgDataMods(false);
        ds.setExternalUserAuthentication(true);
        
        return ds ;
    }

The capabilities, OrgGroups and Positions and filled with empty values and will not be usable in this scenario as you can see from the code. The ResourceDataSet is filled by HashMaps containing the object representing the organisation data. The first method mapping organisational data is "loadRoles()":

private HashMap<String, Role> loadRoles() {
        DAO dao = new DAO();
        HashMap<String, Role> rMap = new HashMap<String, Role>();
        List <Role> rList = dao.getRoles();
        for(Role r : rList){
            rMap.put(r.getID(),r);
        }
        return rMap;
    }

This method receives a list of YAWL roles from my DAO and puts them in the HashMap. The YAWL Roles can be created easily, for a start, lets try to map the roles from the liferay table to the YAWL role object. In my data access object the method "getRoles()" return a list of YAWL roles created with data found in the liferay table. How is it done? See here:

public List<Role> getRoles()
  {
    open();

    ResultSet rs = null;
    PreparedStatement stmtSelect = null;
    List<Role> roleList = new ArrayList();

    StringBuffer sbSelect = new StringBuffer();
    try
    {
      sbSelect.append("SELECT * From role_");

      stmtSelect = this.con.prepareStatement(sbSelect.toString());

      rs = stmtSelect.executeQuery();
      
      while(rs.next()){
          
          Role r = new Role();
          r.setName(rs.getString("name"));
          r.setID(rs.getString("roleid"));
          r.setDescription("A Role");
          roleList.add(r);
      }
    }
    catch (SQLException ex) {
      System.out.println("Error: Executing SQL Statement!");
      ex.printStackTrace();
    }
   
    close();

    return roleList;
  }

In this case it is quite simple. I get a ResultSet object from the sql command using the JDBC connection. A YAWL role is created for each entry in the ResultSet object and the columns "name" and "roleid" of the table are used to fill the attributes "Name" and "ID" of the YAWL role object. After that, they are added to a list for simpler handling.

Next will be the participant list, as seen in the method "loadResources()". The participants are a bit harder to map, because these objects have references to others, in this case the roles. A list of participants is returned by my DAO as you can see in the following method "loadparticipants()":

    private HashMap<String, Participant> loadParticipants(ResourceDataSet ds) {
        DAO dao = new DAO();
        HashMap<String, Participant> pMap = new HashMap<String, Participant>();
        
        List<Participant> pList = dao.getParticipants();
                
        for (Participant p:pList){
            try {

                ResultSet userRoles = dao.getUserRoles();
                
                while(userRoles.next()){
                    if(p.getUserID().equals(userRoles.getString("screenname"))){
                         p.addRole(ds.getRoleByName(userRoles.getString("name")));
                     }
                }
                
            } catch (SQLException e) {
                e.printStackTrace();
            }
            pMap.put(p.getID(), p);
        }
        return pMap;
    }

However after that, I iterate through these participants. By using a ResultSet containing a list of usernames and their roles, I add references of the roles, that already present in the ResourceDataSet, to the user. If the username matches one in the list of user-roles, through which I have to iterate as well and I get by using my DAO method "getUserRoles()", I add the role to the user. The list of participants (users) now have references to the roles and will be returned. With this the minimal information needed to create a functional custom DataSource are present and it can be used. However when using this DataSource, it is no longer possible to manage users via the resource service admin console. Liferay is now responsible for managing user data. If you still want to be able to change user data via the resource service admin console, you will need to implement the responsible methods in the custom DataSource class.

 

How to make this example work on your installation

  • Install Postgres, if not present
  • Install Liferay or import the data tables from the Liferay-Tables.zip
  • Copy the LiferayDataSource.class into the subfolder "engine\apache-tomcat-6.0.18\webapps\resourceService\WEB-INF\classes\org\yawlfoundation\yawl\resourcing\datastore\orgdata" of your YAWL installation
  • Change the value of the parameter "OrgDataSource" to "LiferayDataSource" in the "web.xml" file in the subfolder "engine\apache-tomcat-6.0.18\webapps\resourceService\WEB-INF\" of your YAWL installation
  • Copy the DAO.jar into the libs folder of the resource service found at "engine\apache-tomcat-6.0.18\webapps\resourceService\WEB-INF\lib" of your YAWL installation
  • Copy the file "contet.xml" into the subfolder "engine\apache-tomcat-6.0.18\conf\", which contains configuration parameters for the DAO.jar
  • If your postgres admin user is different or postgres runs on a different port, change the parameters in the context.xml file accordingly
  • Make sure you have a postgres jdbc driver in your libs folder, so the dao will work. You can get it here
  • Start YAWL!

(Notice: This tutorial is based on  YAWL version 2.3.x)

Start case automatically with InterfaceB

Start case automatically with InterfaceB fmannhardt Tue, 11/29/2011 - 12:52

To instantiate a workflow with YAWL, usually an administrator or a user with the privilege "Manage Cases" needs to use the YAWL Resource Service. But often a workflow should be started automatically according to some arbitrary condition (e.g. each month or every time a user submits some inquiry) or by an unprivileged user.

As YAWL is built upon a service oriented architecture it is possible to use an interface of the YAWL Engine to accomplish such tasks. The interface needed in that case is the InterfaceB of the YAWL Engine. YAWL includes already an implementation InterfaceB_EnviromentBasedClient, that provides easy access to this interface. There are two methods available that may be used to start an instance of a specification (i.e. workflow):

 String launchCase(YSpecificationID specID, String caseParams, String sessionHandle, YLogDataItemList logData, String completionObserverURI)
          Override of launchCase to provide the ability to add a listener for the Case-Completion event
 String launchCase(YSpecificationID specID, String caseParams, YLogDataItemList logData, String sessionHandle)
          Launches a case instance of the latest version of the specification loaded.

The first method is only needed, if you an observer completionObserverURI should be notified after the case is completed. Usually, you use the second launchCase method that takes the following parameters:

  • the specID,
  • the caseParams,
  • an empty YLogDataItemLIst
  • and a valid YAWL Engine sessionHandle.

A java servlet that starts a specific YAWL specification may look like this:

    /**
     * Username of an administrative account
     */
    private static final String ADMIN_PASSWORD = "YAWL";

    /**
     * Password of an administrative account
     */
    private static final String ADMIN_USERNAME = "admin";

    /**
     * URL of YAWL Engine InterfaceB
     */
    private static final String INTERFACEB_URL = "http://127.0.0.1:8080/yawl/ib";

    /**
     * A valid specification:<br/>
     * identifier: Can be found in the .yawl file of a specification<br/>
     * version: Can be found with the YAWL Editor in the properties of a
     * specification (Version Number)<br/>
     * uri: Can be found with the YAWL Editor in the properties of a
     * specification (Specification ID)
     */
    private static final YSpecificationID SPECIFICATION = new YSpecificationID(
            "UID_47e1bbf0-7677-4469-ba47-2f77a24bab97", "1.3",
            "SimpleMakeTripProcess.ywl");

    /**
     * XML of the input parameters of the starting net, in this case empty
     */
    private static final String INPUT_PARAMETER = "<Make_Trip_Process></Make_Trip_Process>";

These parameters are constant here for the sake of simplicity and usually the method doPost would be used instead of doGet:

    /*
     * (non-Javadoc)
     *
     * @see
     * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest
     * , javax.servlet.http.HttpServletResponse)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        PrintWriter out = response.getWriter();

        // Engine InterfaceB, usually http://127.0.0.1:8080/yawl/ib
        InterfaceB_EnvironmentBasedClient client = new InterfaceB_EnvironmentBasedClient(
                INTERFACEB_URL);

        String handle = null;

        try {
            // Connect with valid credentials, usually admin / YAWL
            handle = client.connect(ADMIN_USERNAME, ADMIN_PASSWORD);
        } catch (IOException e) {
            out.println("Problem connecting to engine. " + e.getMessage());
        }

        if (handle != null) {
            try {
                // May be empty
                YLogDataItemList yLog = new YLogDataItemList();
                // Launch case from the specification with input parameters
                String caseID = client.launchCase(SPECIFICATION, INPUT_PARAMETER,
                        yLog, handle);
                out.println("Case started! CaseID: "+ caseID);               
            } catch (Exception e) {
                out.println("Case not started. " + e.getMessage());
            }
        }

    }

To use the InterfaceB_EnviromentBasedClient in your own project, you need to include the yawl-lib-2.2.jar (yawl-lib-2.3.jar in case of YAWL 2.3) in the classpath. You can build the YAWL library from the YAWL sources or download YAWL_2.2_LibraryJars.zip at Sourceforge.

An example project with the just presented servlet, which starts the example workflow "Simple Make Trip Process" (distributed with YAWL) can be downloaded below. There is a pre-built WAR-file for immediate deployment to a running YAWL instance. Just copy the InterfaceBServlet.war into the '/engine/apache-tomcat-6.0.18/webapps' directory of YAWL and then open 'http://localhost:8080/InterfaceBServlet/interfaceB' in your web browser.

The sourcecode of the example project is available for download as 'InterfaceB.tgz' and 'InterfaceB.zip'. It is packaged as a Eclipse project that needs Java 1.6 and the Apache Tomcat 6.0 runtime environment.

 

(Notice: This tutorial is based on  YAWL version 2.3.x)

Thank you for uploading this tutorial to help us understand how to use InterfaceB. I downloaded the War file but I could not find the lib to download.

May someone direct me or share another working tutorial with the current version of YAWL or YAWL 4.1 which I am using.

Note: error page is below

Thank you

#################################

HTTP Status 500 - Servlet execution threw an exception

type Exception report

message Servlet execution threw an exception

description The server encountered an internal error that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: Servlet execution threw an exception
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause

java.lang.NoClassDefFoundError: org/apache/commons/codec/binary/Base64
org.yawlfoundation.yawl.util.PasswordEncryptor.encrypt(PasswordEncryptor.java:43)
org.yawlfoundation.yawl.util.PasswordEncryptor.encrypt(PasswordEncryptor.java:50)
org.yawlfoundation.yawl.engine.interfce.interfaceB.InterfaceB_EnvironmentBasedClient.connect(InterfaceB_EnvironmentBasedClient.java:73)
org.yaug.sample.InterfaceBServlet.doGet(InterfaceBServlet.java:79)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

root cause

java.lang.ClassNotFoundException: org.apache.commons.codec.binary.Base64
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285)
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119)
org.yawlfoundation.yawl.util.PasswordEncryptor.encrypt(PasswordEncryptor.java:43)
org.yawlfoundation.yawl.util.PasswordEncryptor.encrypt(PasswordEncryptor.java:50)
org.yawlfoundation.yawl.engine.interfce.interfaceB.InterfaceB_EnvironmentBasedClient.connect(InterfaceB_EnvironmentBasedClient.java:73)
org.yaug.sample.InterfaceBServlet.doGet(InterfaceBServlet.java:79)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

note The full stack trace of the root cause is available in the Apache Tomcat/8.5.5 logs.
Apache Tomcat/8.5.5

Create an externalDBGateway

Create an externalDBGateway mRoskosch Sat, 02/18/2012 - 18:23

Needed Software/Downloads

Tutorial

The external database gateway can be used to populate task and net variables using database connections or update database fields from output parameters. The prerequisites for this tutorial are a correctly configured database and having the corresponding drivers in the "lib" folder of your YAWL-installation. For this particular example, I will be using the Microsoft SQL Server Express 2008 R2 and Microsoft's official JDBC driver to connect to the database. For this configuration I have to make sure, that SQL-authentication is activated on the server and the connecting user has the appropriate rights to access the database.

Let's say we have a list of customers, that we want to display in a task. I have created a database on the server called "DB-NAME" and a very simple table "Customers":

 

To display these three customers in a task, I have created a new datatype in the data type definition of the YAWL workflows specification file using the external database gateway:

  <xs:complexType name="Customers">
    <xs:sequence>
      <xs:element name="Customer" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

Now I will show how to create your own implementation of the externalDBGateway. In the IDE of your choice create a new project and add the YAWL library. Next create a class extending the "AbstractExternalDBGateway". Depending on how you want to use the database gateway, you will need to at least implement one of the following methods:

  • public Element populateTaskParameter(YTask task, YParameter param, Element caseData) {}
  • public void updateFromTaskCompletion(String paramName, Element outputData, Element caseData) {}
  • public Element populateCaseData(YSpecificationID specID, String caseID, List<YParameter> inputParams, List<YVariable> localVars, Element caseDataTemplate) {}
  • public void updateFromCaseData(YSpecificationID specID, String caseID, List<YParameter> outputParams, Element updatingData) {}

When assigned to a variable, the first method will be called at the start of a task if the database gateway is seleceted for the input mapping of a task variable. The second method will be called on completion of a task if the database gateway is assigned to the output mapping of a task variable. The third and fourth methods are the same as the first and second, but are intended for net variables.

In this tutorial I only want to display the database fields and do not intend to update the databse with new values, so I will only work with the "populateTaskParameter" method:

    public Element populateTaskParameter(YTask task, YParameter param,
            Element caseData) {
        
        Element result = new Element(param.getName());
      if (configure()) {
          List resultSet = _dbEngine.execSQLQuery("SELECT CAST(Customer as varchar) FROM Customers");
          
          for (Object row : resultSet) {
              Element content =
                  (Element) JDOMUtil.stringToElement(StringUtil.wrap(row.toString(), "Customer")).clone();
              result.addContent(content);
          }
       }
      return result;
    }

The Select-query gives me a list of Customers from the table shown above. It is also possible to use hibernate query language to access the database with the method "execQuery(String sql)" of the _dbEngine object, but to keep the tutorial simple I chose SQL. As you can see, I cast the column with the customer's name to varchar, because the Microsoft JDBC-Driver has problems with the type "nchar". This results in simple queries being rolled back and not getting any data. Back to the code, I simply transform each row to string and add the xml-tags with the StringUtil.wrap method. Additionally the returned element has to be of the type element so the JDOMUtil.stringToElement-method is used. Remember to use the clone()-method on the element as well or it won't work. The "Customers" data type in YAWL is designed, so that it can display any amount of rows and hence the loop will add any row to the result element.

If you look closely at the code you will see that an additional method to configure the database is needed, boolean configure(){}:

    private boolean configure() {
        if (! configured) {
            configureSession("org.hibernate.dialect.SQLServerDialect",
                            "com.microsoft.sqlserver.jdbc.SQLServerDriver", "jdbc:sqlserver://localhost\\SQLEXPRESS;databaseName=DB-Name",
                            "yawl", "yawl", null);
            configured = true;
        }
        return configured;
    }

The configure()-method makes sure the session to configured and a connection to the database is possible. You will need to call the method "configureSession" to be able to access the database. Its first argument is the database dialect, which depends on the database you use. Second is the driver used to connect to the database, followed by the url of the database server in the third argument. The url string is different on every configuration and should be checked with extra care. The fourth and fifth arguments are username and password needed to connect to the database. The last argument is an optional list of classes, if you are using hibernate.

When the class is compiled, you will need to place it in the correct folder of the YAWL-installation, in my case "[YAWL-dir]\engine\apache-tomcat-6.0.18\webapps\yawl\WEB-INF\classes\org\yawlfoundation\yawl\elements\data\external". After starting the engine, it will automatically detect the file and make it available to the YAWL-editor, if the editor has a connection to the engine.

To select a variable as being populated by an external database gateway, you need to right-click on a task or net in the YAWL-editor, choose "Update parameter mappings..." and there if you either create a new mapping or choose to update an existing mapping you will be see the "Data Gateway" tab showing all available data gateways:

Select the data gateway and hit "Done" and when the task of this workflow is started, the engine will try to connect to the database using the selected database gateway.

The result can be seen here as all three entries in the Customers table are shown in this task:

Attached to this tutorial are the *.class and *.java files of my implementation. The class is modeled on Michael Adams' "SimpleExternalDBGatewayImpl", but working with a concrete Mssql-database.

 

(Notice: This tutorial is based on  YAWL version 2.3.x)

Delete YAWL Orgdata in Postgres DB

Delete YAWL Orgdata in Postgres DB ahense Sat, 01/06/2018 - 13:31

When you want to load organisational data into the YAWL system it is sometimes useful to first delete existing entries. This short tutorial shows how to do this if you have configured YAWL to use a Postgresql DBMS.

Tables

Access the YAWL database with pgAdmin or any other tool. Delete all entries of the following tables - not the tables themselves:

  • rs_participant_role
  • rs_participant_capability
  • rs_participant_position

In the next step delete all entries of the following tables:

  • rs_userprivileges
  • rs_eventlog
  • rs_role
  • rs_capability
  • rs_position
  • rs_participant

Then restart the YAWL engine. All organisational data and users should be gone now.