Creating a custom organisation data source

Printer-friendly version

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)