May 272009
 

As I was testing the functionality of the user based workflow status reporting API that I posted about recently, I discovered that the Javascript API for workflow in Alfresco only enabled viewing workflow related information for the authenticating user.  I however would like to enable monitoring by other users who are either administrators or members of a designated group, such as a “Managers” group of users who will monitor workflow statistics.  Fortunately, there is a convenient way to handle this thanks to the magic of the Spring Framework (upon which Alfresco is built).

As described on the wiki, you can add custom Javascript APIs that are backed by Java implementations.  In fact, it is via this mechanism that the documented Javascript API is exposed.  But for our workflow status reporting scenario, we want to replace the implementation of the exposed “workflow” object with an implementation that allows for our new authorization requirement.  Therefore we need to find where the current “workflow” object is configured.  A simple grep command revealed that this object (along with all of the others) is configured via the script-services-context.xml Spring configuration file, which has the following bean entry for workflow:

    <bean id="workflowScript" parent="baseJavaScriptExtension"
            class="org.alfresco.repo.workflow.jscript.WorkflowManager">
        <property name="extensionName">
            <value>workflow</value>
        </property>
        <property name="serviceRegistry">
            <ref bean="ServiceRegistry"/>
        </property>
    </bean>

Ideally, we would want to have all of the current capabilities that the WorkflowManager class already implements plus whatever our extension class would add to it via the ‘workflow’ object (including handling for our new authorization requirement in this case).  For some reason though, which I chose not to investigate thoroughly, extending an existing class intended for exposure via Javascript isn’t working the way I would have expected (see here for the JIRA report I filed about it).  Only the new public methods in my class were being exposed, despite the extension of the existing WorkflowManager class.

Since it’s not terribly critical though, we’ll just build a new class and expose a new object via Javascript.  We’ll call it WorkflowStatusManager and configure it via Spring as follows:

    <bean id="workflowScript" parent="baseJavaScriptExtension"
            class="org.alfresco.repo.workflow.jscript.WorkflowStatusManager">
        <property name="extensionName">
            <value>workflowstatus</value>
        </property>
        <property name="serviceRegistry">
            <ref bean="ServiceRegistry"/>
        </property>
    </bean>

Now we’re free to add parameterized accessors for assigned tasks and completed tasks (where the parameter will be the user authority for which to obtain results for).  As you can see, this class will have a reference to the ServiceRegistry from the Alfresco Java API, which can be used to gain access to a variety of services, including the WorkflowService which will be used in this case.

One addition that I’m considering adding into the Spring configuration would be a property to set the name(s) of the group(s) that should have access to other users’ workflow data.  If you have ideas for other workflow status reporting capabilities to expose to Javascript, please share!

May 122009
 

Now that I’ve had a chance to dig into implementing some of the workflow status reporting capabilities, it’s time to get a little more specific.  First, let’s take a look at the architecture.

workflow_status_architecture1

As you can see from the image above, the workflow reporting web scripts will run on the Alfresco server, exposing information via JSON (and/or other formats) to other presentation layer technologies like Alfresco Share, JBoss Portal, etc.  Later on in this process Share dashlets or JSR-168 portlets can be written to consume and present the exposed data.

Because a lot of workflow information is already exposed via the Workflow JavaScript API, I’ll use JavaScript backed web scripts to expose the data as appropriate for the reports I want to generate.  I suspect that as I progress further, I may need to extend the workflow service at the Java level to expose additional workflow information.  If/when that happens, I’ll have a couple of choices for exposing that new information:

For now though, I need to flesh out what the API will look like.  At this point I’m assuming that most custom workflows will extend the out of the box models, and will thus have certain metadata available for extraction and reporting.  Note that only JSON will be exposed for now.  Exposing XML, RSS, ATOM, or even an HTML representation of the data is easily possible though by using the Alfresco web scripts templating capabilities.

User

Returns current and historical workflow information for the authenticating user.  It’s also possible to request another user’s workflow information via the id parameter.

URL

http://yourhost:8080/alfresco/service/api/workflow/status/user.format

Formats

JSON

HTTP Method(s)

GET

Requires Authentication

Yes, as the user for which workflow information is being requested or as an administrative role otherwise

Parameters

  • id.  Optional.  Specifies the id of the user whose workflow information is being requested.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json
  • startDate.  Optional.  Specifies the start date after which to retrieve workflow information.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json?startDate=01-01-2008
  • endDate.  Optional.  Specifies the end date before which to retrieve workflow information.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json?endDate=12-31-2008 or http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json?startDate=01-01-2008&endDate=12-31-2008
  • timePeriod.  Optional.  Specifies the time period to use to delimit data, for example in a table or graph.  The value must be one of {daily, weekly, biweekly, bimonthly, monthly, quarterly, biannually, annually}. When specified, this parameter must be accompanied by either startDate, endDate, or both
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json?startDate=01-01-2008&endDate=12-31-2008&timePeriod=monthly
  • taskName. Optional. Specifies a taskName to filter by. Workflow information related to any other task will NOT be included if this parameter is specified.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/user/brobinson.json?taskName=wf:reviewTask
  • sortBy.  Optional.  Specifies the parameter to sort by.  Must be one of {taskName, priority, duration, status, percent, dueDate, created, description}.
  • showProperties.  Optional.  Specifies whether task properties should be included in the output for every task.

Response

{
      user: "brobinson",
      assignedTasks: [
            {
            	name: "wf:reviewTask",
                description: "Take a look",
                priority: 3,
                due: null,
                percent: 0,
                completed: null,
                status: "Not Yet Started",
                duration: null,
                created: "2009-05-12 10:25:52.51",
                properties: [
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}startDate",
                            value: null
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}packageItemActionGroup",
                            value: "edit_package_item_actions"
                        },
						{
                            key: "{http://www.alfresco.org/model/bpm/1.0}completionDate",
                            value: null
                        },
						{
                            key: "{http://www.alfresco.org/model/bpm/1.0}percentComplete",
                            value: 0
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}context",
                            value: "workspace://SpacesStore/707f218a-0967-4ebc-9bb4-872e9cb67597"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}priority",
                            value: 3
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}pooledActors",
                            value: "[]"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}package",
                            value: "workspace://SpacesStore/f602c326-ea5f-40f0-91b4-21f27249aff7"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}packageActionGroup",
                            value: ""
                        },
                        {
                            key: "{http://www.alfresco.org/model/content/1.0}owner",
                            value: "admin"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}dueDate",
                            value: null
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}hiddenTransitions",
                            value: ""
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}description",
                            value: "Take a look"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}outcome",
                            value: ""
                        },
                        {
                            key: "{http://www.alfresco.org/model/content/1.0}created",
                            value: "2009-05-12 10:25:52.51"
                        },
                        {
                        	key: "{http://www.alfresco.org/model/bpm/1.0}status",
                            value: "Not Yet Started"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}taskId",
                            value: 6586373
                        }
                  ]
            }, ...(truncated)...
      ],
      completedTasks: [
            {
            	name: "wf:submitReviewTask",
                description: "Hey, take a look at this, will you?",
                priority: 3,
                due: null,
                percent: 0,
                completed: "2009-04-15 16:22:49.808",
                status: "Completed",
                duration: 17.468,
                created: "2009-04-15 16:22:49.128",
                properties: [
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}startDate",
                            value: null
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}packageItemActionGroup",
                            value: "start_package_item_actions"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}completionDate",
                            value: "2009-04-15 16:22:49.808"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}percentComplete",
                            value: 0
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}context",
                            value: "workspace://SpacesStore/6c5bf7d2-806c-4f04-99bc-3a4b84ed7073"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}workflowDueDate",
                            value: null
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}priority",
                            value: 3
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}pooledActors",
                            value: "[]"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}package",
                            value: "workspace://SpacesStore/6c5bf7d2-806c-4f04-99bc-3a4b84ed7073"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}packageActionGroup",
                            value: "add_package_item_actions"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}assignee",
                            value: "workspace://SpacesStore/9a4684c8-18ef-4f3e-a119-e5bb08c9da52"
                        },
                        {
                            key: "{http://www.alfresco.org/model/content/1.0}owner",
                            value: "admin"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}workflowPriority",
                            value: 2
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}dueDate",
                            value: null
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}hiddenTransitions",
                            value: ""
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}description",
                            value: "Hey, take a look at this, will you?"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}outcome",
                            value: ""
                        },
                        {
                            key: "{http://www.alfresco.org/model/content/1.0}created",
                            value: "2009-04-15 16:22:49.128"
                        },
                        {
                            key: "{http://www.alfresco.org/model/bpm/1.0}status",
                            value: "Completed"
                        },
                        {
                        	key: "{http://www.alfresco.org/model/bpm/1.0}taskId",
                            value: 2785280
                        },
                        {
                        	key: "{http://www.alfresco.org/model/bpm/1.0}workflowDescription",
                            value: "Hey, take a look at this, will you?"
                        }
                  ]
            }, ...(truncated)...
      ]

}

Group

Returns current and historical workflow information for the identified group

URL

http://yourhost:8080/alfresco/service/api/workflow/status/group.format

Formats

JSON

HTTP Method(s)

GET

Requires Authentication

Yes, as an administrative role

Parameters

  • id.  Required.  Specifies the id of the user whose workflow information is being requested.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering
  • startDate.  Optional.  Specifies the start date after which to retrieve workflow information.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering&startDate=01-01-2008
  • endDate.  Optional.  Specifies the end date before which to retrieve workflow information.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering&endDate=12-31-2008 or http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering&startDate=01-01-2008&endDate=12-31-2008
  • timePeriod.  Optional.  Specifies the time period to use to delimit data, for example in a table or graph.  The value must be one of {daily, weekly, biweekly, bimonthly, monthly, quarterly, biannually, annually}. When specified, this parameter must be accompanied by either startDate, endDate, or both
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering&startDate=01-01-2008&endDate=12-31-2008&timePeriod=monthly
  • taskName. Optional. Specifies a taskName to filter by. Workflow information related to any other task will NOT be included if this parameter is specified.
    • Example: http://yourhost:8080/alfresco/service/api/workflow/status/group.json?id=Engineering&taskName=wf:reviewTask
  • sortBy.  Optional.  Specifies the parameter to sort by.  Must be one of {taskName, priority, duration, status, percent, dueDate, created, description}.
  • showProperties.  Optional.  Specifies whether task properties should be included in the output for every task.

Response

To be implemented, but is intended to contain tasks assigned to group members, group pooled tasks (which are by definition unassigned), and completed tasks, all of which will have the following fields associated with each task: taskName, priority, duration, status, percent, dueDate, created, description.

Task

Returns current and historical workflow information for the identified task.  Further details TBD.

Workflow

Returns current and historical workflow information for the identified workflow.  Further details TBD.

If you have any feedback on what I’ve presented so far, as always, please speak up.

Reblog this post [with Zemanta]
Apr 202009
 

As part of the Alfresco Consulting team, I’ve done some work on web scripts for reporting workflow status, keyed off of custom workflow metadata.  At the AIIM conference a few weeks ago, I was asked multiple times about Alfresco’s ability to expose workflow reports. Last week I came across a post from Kas Thomas who wondered, “Does workflow always have to suck?“, which touched on workflow reporting.  My conclusion after all of this: we need to build workflow status reporting. And I’m going to start on it.

Now there are a lot of ways in which we could build this out.  First, we need to consider the reporting context.  Do we want to report based on:

  • the system as a whole (“show me all workflow status in the entire system”)
  • web content management use (“show me all workflow status for web project X”)
  • user (“show me how user ‘bobsmith’ is involved in workflow”)
  • group (“show me how group ‘marketing’ is involved in workflow”)
  • asset type (“show me all workflow status pertaining to ‘.jpg’ files”)
  • asset (“show me all workflow status related to this particular document”)
  • path (“show me all workflow status related to assets in/under this path”)
  • workflow (“show me all status related to all instances of this named workflow”)
  • workflow task (“show me all status related to all instances of this named workflow task”)
  • something else I haven’t thought of yet (please comment here if you have other suggestions)

Since I want to get something going that will be of the most use to the most people, I’m going to start with reporting by user, then by group.  My next consideration will be exactly what to report.  I have not used any other workflow software besides Alfresco, so if you’ve got input on this, I would love to hear it (please comment below).  That said, so far I’m thinking that given a user id, the report will show:

  • the number of currently active workflows the user is/may be involved it (i.e. this would be inclusive of pooled tasks assigned to a group that the user is a part of)
  • the number of currently active workflow tasks the user has assigned to them

Given a user id and a date range, the report will show:

  • the number of completed tasks
  • the number of completed workflows
  • the average duration of each completed task

Better still, given a user id, date range (Jan 1, 2008 – December 31, 2008), and recurring time period (monthly), the report could show a bar chart or line graph of the aforementioned metrics.  Perhaps you can even add the ability to compare one user to another on those metrics.

A few things are notably missing so far.  Nowhere have I mentioned the ability to key off of custom workflow metadata, or report on custom workflow metadata. Perhaps the former could be addressed via the inclusion of a name/value pair that serves as a filter.  For example, providing {http://www.mycompany.com/model/my-workflow/1.0}/customId=42 could serve to filter out any workflow that does not have that custom metadata set on the workflow’s start task.  Reporting custom workflow metadata probably doesn’t make sense as part of a “by user” oriented report, but probably does make sense as part of a named workflow report.  What do you think?

Hopefully this post will drum up some food for thought, and ideally some feedback on what Alfresco users might want from a workflow reporting perspective.  Please feel free to share your thoughts on the subject by commenting here or participating in the workflow forum at http://forums.alfresco.com/en/viewforum.php?f=34.

Mar 152009
 

When dealing with workflows, a commonly requested feature is the ability to have automated E-Mails sent out from the workflow.  Alfresco documents a way to do this via the AlfrescoJavaScript action, by writing some Javascript code to send out the E-Mail.  While this approach provides great flexibility, it also requires your Javascript skills to be up to par.  Wouldn’t it be great to have a specialized E-Mail action instead that could be configured via XML?  Of course it would.

Here’s a simple example of how such an action could be used:

<action class="org.alfresco.repo.workflow.jbpm.Mailer" config-type="bean">
   <to>alfresco@localhost</to>
   <from>info@alfresco.com</from>
   <subject>Content awaiting review!</subject>
   <text>New changes have been submitted and are awaiting your review!</text>
</action>

This is a bit easier to work with as a workflow author than having to code an E-Mail action being sent via Javascript. It does have some limitations though in this simple form, so let’s enhance it a little further. A few things that might be desirable include:

  • Comma and/or semicolon separated E-Mail addresses
  • Variable resolution of E-Mail addresses
  • Variable resolution of task assignee E-Mail addresses (bpm:assignee)
  • Variable resolution of multiple task assignee E-Mail addresses (bpm:assignees)
  • Variable resolution of task group assignee E-Mail addresses (bpm:groupAssignee)
  • Variable resolution of multiple task group assignee E-Mail addresses (bpm:groupAssignees)
  • Variable resolution within the subject and body text

By implementing an Alfresco jBPM action to handle these various requirements, one could ultimately specify a quite dynamic E-Mail action, such as the following:

<action class="org.alfresco.repo.workflow.jbpm.Mailer" config-type="bean">
   <to>bob@example.com, ${bpm_groupAssignees}, ${somewf_somePersonsEmail}, jane@example.com</to>
   <from>info@alfresco.com</from>
   <subject>Content awaiting review!</subject>
   <text>New changes have been submitted and are awaiting your review!</text>
</action>

Further enhancements could include leveraging E-Mail templates already registered with the repository.  To get your hands on an implementation of the E-Mail action described here, see improvement ALFCOM-2555 in Alfresco’s JIRA.  If you have suggestions for how to further improve this simple extension, please comment here!

Reblog this post [with Zemanta]