Untitled Document
Table of contents | Next | Previous
Workflow
A
workflow is a process that is used to control item state and
security. In Web content management, workflows are designed by combining three
kinds of elements:
- Status: Controls whether the item is displayed in the
rendered site
- Stages: Represent a step in a workflow
- Actions: Can be triggered when the user enters or exists
a workflow stage
Workflows are assigned by site designers to one or more authoring templates.
Workflows have access permissions with which content authors can choose among
any of the visible workflows assigned to the current authoring template.
In this article, we illustrate how to create both a basic workflow and a custom
workflow using the River Bend sample site as the example.
Creating a basic workflow for the River Bend sample site
In this section, we explain how to create a basic workflow within the context
of the River Bend sample site.
River Bend wants two different ways to publish information:
- Approval: This method should be the default working
mode. Items may have four different states (draft, approval, published, and
expired).
- Express: This method covers exceptions items that may be
directly published from draft to published.
The following figure illustrates both workflows:
- Stages are represented by rectangular shapes.
- State is represented by the shape color: orange for daft items, green for
published items, and blue for expired items.
- Actions are displayed before and after each shape to represent what is
executed when the item enters or exits that stage.
| Note: As we mentioned
previously, workflows have their own security setting with which you can define
alternative ways to publish the same content. River Bend site designers use
this feature to restrict the use of express publishing to a group of users who
were created for this task called “contentWFExpressUsers”. These users can
short cut the content publishing processing when dealing with exceptions.
|
Item status
Item status controls whether a WCM item is visible in the rendered site. A WCM
"workflowed" item has three states:
- Draft: The item has not yet been published and will not
be rendered on the live site. The draft status is represented by an orange icon
close to the content.
- Publish: The item is rendered on the live site. The
publish status is represented by a green icon close to the content.
- Expired: The item is no longer published. The status is
represented by a blue icon close to the content.
A WCM "non-workflowed" item has only one state, which is published . A
non-workflowed item is represented by a gray icon close to the item.
Note: When progressing
through a workflow, item status can only change in a linear fashion:
- Draft to published to expired
- Published to expired
- Draft to published
|
Stages
Stages represent a step in the overall workflow process. With the use of
stages, site designers can define the actions that will happen with a content
and the necessary conditions (approvals) from the time it is created to the
time it expires:
- Workflows can have one or more stages.
- Content states happens when a content item reaches a new stage.
More actions can be performed when an item enters or leaves a stage:
- Workflow stages determine the content security for a particular stage.
(Do not confuse this with the security of the stage itself.)
- Setting approve access is only available through the workflow stage.
- Such options as "Joint approval" and "Enter comment on approval" are set
in the workflow stage. (Enter comment on approval can be across the workflow.)
Workflow stages for the River Bend site
The stages in the following table make up the approval workflow.
| Stage
| Actions upon
entering
| Security
| Description
|
| Draft
|
| User:
Contributor:
Editor:
Manager:
Approver: [authors]
| All content begins the workflow in this stage.
All content authors groups are authorized to use the draft stage
inheriting the permission settings at the library resource level.
|
| Approval
|
| User:
[authors], contentApproversLegal, contentApproversHQ, contentApproversHR
Contributor:
Editor:
Manager:
Approver (*): contentApproversLegal, contentApproversHQ,
contentApproversHR
* Joint approval
| Content requires a review stage before being published.
Three groups of people are authorized to approve content.
People of all three groups must joint approve a content item before its
published
|
| Publish
| Generate thumbnail
Publish
Move content on expiry date
| User:
[anonymous portal user], [all authenticated portal users]
Contributor:
Editor:
Manager:
Approver: contentApproversLegal, contentApproversHQ, contentApproversHR
| This is the stage where content from the workflow is published.
A workflow custom action generates a thumbnail from an existing image for
Products and News.
The Publish action is triggered and the content is visible on the Web
site.
The Scheduled Move action is also triggered when the Expire Date is
reached
|
| Expired
| Expired
| User:
Contributor:
Editor:
Manager:
Approver: contentApproversLegal, contentAuthorsMarketing,
contentAuthorsOps, contentApproversHQ, contentApproversHR,
contentAuthorsStoreMgr
| The Scheduled Move action moves the content into this stage, where the
Expire action stops the document from being visible on the Web site
|
| Reject
| E-mail for rejected content
| User:
Contributor:
Editor:
[authors]
Manager:
Approver:
| Rejected content reaches this stage. Authors are
able to create a new draft from the rejected content.
|
Actions
Workflow actions can be triggered when an item enters or leaves a workflow
stage. The Lotus Web Content Management application ships several types of
actions that you can extend by writing your own action and packaging them as
EAR or JAR files:
- Scheduled move action : Used to move workflow items to the next stage
based on date
- E-mail action : Used to e-mail users when an item reaches the stage
- State change actions : Change the item state to publish or expire
- Version actions : Create a new version of the item when this action is
executed
- Scheduled move action : Moves an item to the next workflow stage at a
specified date and time
- Custom actions : Allows the ability to create new actions by using Java
code and packaging them as EAR or JAR files
River Bend workflow actions
| Action
| Description
|
| Publish
| Makes a content item visible on the Web site
|
| Move content on expiry date
| This scheduled move action detects when a document has passed its
expire date and moves the document into the expired stage
|
| Expired
| Stops a document from being visible on the Web site
|
| E-mail for rejected content
| Schedules the move of any content that meets the items expiration
date
|
| Generate thumbnail
| Creates a thumbnail for use in menus by using a Java-based custom
action
|
Creating workflow actions
To create the workflow actions:
1. Click New and select
Workflow Action Publish Action .
2. In the name field, type
Publish .
3. Click Save …, and then click
Save and Close .
For the remaining actions, repeat steps 1 through 3. Refer to the following
table for the action names and action types.
| Action
| Action type
|
| E-mail for rejected content
| Email action
|
| Expired
| Expire action
|
| Move content on expiry date
| Scheduled move action
|
| Generate thumbnail
| Custom action
|
For the
Move content on expiry date , select Expiry Date from
the Date Type list and choose an appropriate date, for example tomorrow's date,
to see this action.
For the E-mail for rejected content, select E-mail authors . E-mail Stage
Approvers is selected by default. Add an apology message in Additional e-mail
text.
Creating workflow stages
To create the workflow stages:
- Click New and select Workflow Stage .
- In the name field, type Draft .
- Click Save …, and then click Save and Close .
- Repeat steps 1 through 3 for the Approval stage.
- Click New and select Workflow Stage .
- In the Name field, type Published.
- In the Properties section, under Execute on Entering Stage, click Select
Actions to select an action that is performed on any content that enters this
stage of the workflow.
- Click Add.
- In the Execute on Entering Stage window that lists all the available
actions, from the list, choose Publish , Generate thumbnail , and Move content
on expiry date . (Note: Generate thumbnail can be ignored if it is not
added yet.)
- Click Save …, and then click Save and Close .
- Repeat steps 5 through 10 to create the Expired stage. Set the Execute on
Entering Stage action to Expired .
- Repeat steps 5 through 10 to create the Reject stage. Set the
Execute on Entering Stage action to Email for rejected content .
Creating the Express Workflow
Express Workflow is the express workflow that publishes content immediately
without approval. We use this workflow for this exercise to avoid
time-consuming approval activities. To create the Express workflow:
- Click New and select Workflow .
- In the Name field, type Express.
- In the Properties section, click Select Workflow Stages .
- Click Add .
- From the list of workflow stages, select Draft and Published .
- Click OK .
Creating the Approval Workflow
This guided practice creates a workflow that publishes content with
approval, expiry, and reject stages. To create the Approval workflow:
- Click New and select Workflow .
- In the Name field, type Approval.
- In the Properties section, click Select Workflow Stages .
- Click Add .
- Select the following options:
- Approval
- Draft
- Expired
- Published
- Select the Draft stage.
- Use the Move arrows, located to the right of the Workflow Stages list, to
move the Draft stage to the top of the list.
- Repeat steps 6 and 7 to rearrange the workflow stages as follows:
- Draft
- Approval
- Published
- Expired
- Click OK .
- Click Select Reject Stage .
- Select the Reject stage.
- Click OK .
- Click Save ..., and then click Save and Close .
Creating a custom workflow action for the River Bend sample site
In this section, we explain how to create a custom workflow action for the
River Bend sample site.
Description of the customization to be created
River Bend wants to optimize the page size of their Web site. To achieve this
goal, they generate a smaller image for products and news to be used in menus
and navigators. Several options are available to do this, but the site designer
has decided to implement a custom workflow action that reads the product image,
generates a reduced image using Java APIs, and saves the new image as part of
the content item before it is published.
Custom workflow actions
Custom workflow actions are a new feature of Lotus Web Content Management 6.1
with which you can execute your custom code as part of a workflow process. This
new functionality has been implemented by using the Eclipse Plug-in framework
that is integrated in WebSphere Application Server, enabling you to hot deploy
your code without even restarting portal.
You can use Web content management (WCM) APIs inside custom actions to read
or update the content items that are being processed or any other content
items.
The creation process of a custom action has three steps, which are outlined
in the following table.
Step |
Description |
Development |
Develop Java code for the action, two
classes will be necessary, the actual code that will be executed everytime the
action runs (based on the CustomWorkflowAction interface) and a factory that
will be manage the creation of instances for this actions (based on
CustomWorkflowActionFactory)
Create a plugin descriptor file (plugin.xml) to register the workflow
action within a WCM extension point |
Deployment |
Package and deploy your code either as an
EAR or JAR file. An EAR file will allow you to hot deploy your code whereas JAR
files require a server restart. |
Configuration |
Create custom workflow actions in WCM in
same way as any other actions |
Using a custom action on the River Bend Web site
River Bend wants to optimize the page size of their Web site. To achieve
this goal, they generate a smaller image for products and news to be used in
menus and navigators. Several options are available to do this, but the site
designer has decided to implement a custom workflow action that reads the
product image, generates a reduced image using Java APIs, and saves the new
image as part of the content item before it is published.
Development steps
Developers create a new Dynamic Web project.

After the project is created, they add three classes:
- com.ibm.itso.redwiki.wcm.wf.Thumbnail: This is a utility class for
scaling images.
- com.ibm.itso.redwiki.wcm.wf.CWFAction: This class holds the actual
action. It should implement the CustomWorkflowAction interface.
- com.ibm.itso.redwiki.wcm.wf.CWFActionFactory: This class manages the
creation of action instances. It should implement CustomWorkflowActionFactory
interface.
Thumbnail.class:
package com.ibm.itso.redwiki.wcm.wf;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
public class Thumbnail {
public static byte []
scale( byte [] data, int width, int
height) {
// Get system temp
String tmp = System. getProperty ( "java.io.tmpdir"
);
String src = tmp + "/" + new
java.util.Date().getTime() + "_in.jpg" ;
String dest = tmp + "/" + new
java.util.Date().getTime() + "_out.jpg" ;
// Temporay file names
File srcFile = new File(src);
File destFile = new File(dest);
// Generate temporary file for input
FileOutputStream fs;
try {
fs = new FileOutputStream(src);
fs.write(data);
// Convert byte array to buffered image
BufferedImage imgSrc = ImageIO. read (srcFile);
BufferedImage imgDest = new BufferedImage(width,
height,
BufferedImage. TYPE_INT_RGB );
Graphics2D g = imgDest.createGraphics();
AffineTransform at = AffineTransform. getScaleInstance (
( double ) width / imgSrc.getWidth(), ( double
) height
/ imgSrc.getHeight());
g.drawRenderedImage(imgSrc, at);
// Generate result image
ImageIO. write (imgDest, "JPG" , destFile);
InputStream is = new FileInputStream(destFile);
// Convert result image to byte array
long length = destFile.length();
// Will hold resulting byte array
byte [] result = new byte
[( int ) length];
if (length < Integer. MAX_VALUE ) {
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < result. length
&& (numRead = is.read(result, offset, result. length - offset))
>= 0) {
offset += numRead;
}
// Close the input stream and return bytes
is.close();
}
// Delete temporary files
srcFile.delete();
destFile.delete();
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
}
CWFAction.class:
package com.ibm.itso.redwiki.wcm.wf;
import
java.util.Date;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.ibm.workplace.wcm.api.Content;
import com.ibm.workplace.wcm.api.Document;
import com.ibm.workplace.wcm.api.ImageComponent;
import
com.ibm.workplace.wcm.api.WebContentCustomWorkflowService;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
import
com.ibm.workplace.wcm.api.custom.CustomWorkflowActionResult;
import com.ibm.workplace.wcm.api.custom.Directive;
import com.ibm.workplace.wcm.api. custom .Directives;
import
com.ibm.workplace.wcm.api.exceptions.AuthorizationException;
import
com.ibm.workplace.wcm.api.exceptions.ComponentNotFoundException;
import
com.ibm.workplace.wcm.api.exceptions.IllegalTypeChangeException;
import
com.ibm.workplace.wcm.api.exceptions.OperationFailedException;
import
com.ibm.workplace.wcm.api.exceptions.PropertyRetrievalException;
public class CWFAction implements
CustomWorkflowAction {
public CustomWorkflowActionResult execute(Document arg0) {
Directive directive = Directives. CONTINUE ;
String message = "Action succesfully executed" ;
if
(arg0 instanceof Content) {
// Get current image
try {
Content wcmItem = (Content) arg0;
// Get image element
ImageComponent bigImage = (ImageComponent) wcmItem
.getComponent( "Image" );
// Check if there is an attached image
if (bigImage.getImageFileName()!= null )
{
// Get image bytes
byte [] arrImg = bigImage.getImage();
// Scale it
byte [] arrImgTmb = Thumbnail. scale (arrImg,
100, 50);
// Load new image
ImageComponent thumbnail = (ImageComponent) wcmItem
.getComponent( "Thumbnail" );
thumbnail.setImage( "tmb_" + bigImage.getImageFileName(),
arrImgTmb);
// Put new width and height
thumbnail.setWidth( "100" );
thumbnail.setHeight( "50" );
wcmItem.setComponent( "Thumbnail" , thumbnail);
}
} catch (ComponentNotFoundException e) {
// Dont rollback if a component is not found
directive = Directives. CONTINUE ;
message = "Image or thumbnail element not found" ;
} catch (AuthorizationException e) {
directive = Directives. ROLLBACK_DOCUMENT ;
e.printStackTrace();
message = e.getMessage();
} catch (PropertyRetrievalException e) {
directive = Directives. ROLLBACK_DOCUMENT ;
e.printStackTrace();
message = e.getMessage();
} catch (OperationFailedException e) {
directive = Directives. ROLLBACK_DOCUMENT ;
e.printStackTrace();
message = e.getMessage();
} catch (IllegalTypeChangeException e) {
directive = Directives. ROLLBACK_DOCUMENT ;
e.printStackTrace();
message = e.getMessage();
}
}
WebContentCustomWorkflowService webContentCustomWorkflowService =
null ;
try {
// Construct and inital Context
InitialContext ctx = new InitialContext();
// Retrieve Custom Workflow Service
webContentCustomWorkflowService = (WebContentCustomWorkflowService)
ctx
.lookup( "portal:service/wcm/WebContentCustomWorkflowService" );
} catch (NamingException ne) {
// Exception retrieving Service
ne.printStackTrace();
return null ;
}
// Create a result object
CustomWorkflowActionResult result = webContentCustomWorkflowService
.createResult(directive, message);
return result;
}
public Date getExecuteDate(Document arg0) {
return DATE_EXECUTE_NOW ;
}
}
| Note: It is not
necessary to save the current content item in the action. Directive.CONTINUE
will do that for you. |
CWFActionFactory.class:
package com.ibm.itso.redwiki.wcm.wf;
import java.util.Locale;
import com.ibm.workplace.wcm.api.Document;
import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
import
com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory;
public class CWFActionFactory
implements CustomWorkflowActionFactory {
public CustomWorkflowAction getAction(String arg0,
Document arg1) {
if (arg0.equalsIgnoreCase(
"generate_thumbnail" )) {
return new CWFAction();
}
return null ;
}
public String getActionDescription(Locale arg0, String
arg1) {
return "Generates a thumbnail from existing
content" ;
}
public String[] getActionNames() {
String names[]={ "generate_thumbnail" };
return names;
}
public String getActionTitle(Locale arg0, String
arg1) {
if (arg1.equalsIgnoreCase(
"generate_thumbnail" )) {
return "generate_thumbnail" ;
}
return null ;
}
public String getName() {
return "CWFActionFactory" ;
}
public String getTitle(Locale arg0) {
return "ITSO WCM 6.1 Redwiki Custom Workflow
Action Factory" ;
}
}
Finally, River Bend developers created the configuration file that
registered the action in WCM by creating a new empty file under WEB-INF, called
plugin.xml with this content:
<?xml version="1.0" encoding="UTF-8"?>
<plugin id= "com.ibm.workplace.wcm.api.custom"
name= "Sample Custom Workflow Action Factory"
version= "1.0.0"
provider-name= "IBM" >
<extension-point id= "CustomWorkflowActionFactory" name=
"CustomWorkflowActionFactory" />
<extension
point=
"com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory"
id= "SimpleCustomWorkflowActionFactory" >
<provider class=
"com.ibm.itso.redwiki.wcm.wf.CWFActionFactory" />
</extension>
</plugin>
Packaging & Deployment
River Bend developers exported their code as an EAR file and deploy it in
WCM using WebSphere Administrative Console.
Note:
When deploying your application you can use default settings in all
steps but step 2 (Map modules to servers). In this step be sure to select the
WebSphere_Portal server. |
Finally, they located the new installed application and started it by
selecting it and clicking the “Start” button. Once the application was started
Portal's console displayed a message showing the new action was avalilable:
00000c38 ExtensionPoin I
CWXRS0034I: Extension
com.ibm.workplace.wcm.api.custom.SimpleCustomWorkflowActionFactory connected
with Extension Point
com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory |
Configuration
To make the action available for content creators, River Bend developers
created a custom workflow action in the same way than any other action (New ?
Workflow Actions ? Custom Action) with the following configuration:
