Pima Community College makes extensive use of workflows and has made some enhancements to the Cascade Server workflow system. This presentation will cover:
-Types of workflow used
-Interesting applications of stock Cascade Server workflow features
-New feature: customizing the email messages that are generated by workflows
-New feature: allowing the webmaster to manually escalate a neglected workflow
2. WORKFLOWS AT PCC
We love workflow!
Pages edited by subject matter experts
Content must be approved by administrator
responsible for content area
Nobody gets publish permissions -- all publishing done
by workflow
3. NIFTY FEATURE: WORKFLOW REPORT
Created from index block and format
This came with the system install
5. NIFTY FEATURE #2: APPROVER EDITS
• What if the approver wants to make a simple change to
a page?
• The page is locked, so they can only send it to another
step in the workflow
• Don't want to generate emails to any other user or have
the chance that another user will jump on the file
• With the right trigger, you can send a workflow
exclusively to yourself
7. NIFTY FEATURE #3: ESCALATIONS
• Escalations - If a workflow is ignored for a set period
of time, automatically send it to the webmaster
• This is not the same as the due-date / end-date on
a workflow
<step type="transition" identifier="review"
label="Approver review" default-group="Administrators"
escalate-to="escalate" escalation-hours="336">
9. CUSTOM FEATURE: WORKFLOW EMAILS
• Our users go through a lot of workflows
• Notfication email needs more information than that
a workflow "needs attention"
• Need to re-edit one I submitted?
• Approve one sent by someone else?
• Not very helpful to say that a workflow has ended
• Do I really have to log into CMS just to see if it was
approved or rejected?
11. CUSTOM WORKFLOW TRIGGERS
Create a new class:
public class EmailProvider2 extends
com.cms.workflow.function.EmailProvider
We put this class in a JAR file that contains all our
custom Java (pccCustom.jar)
Put new JAR in:
[cascade home]/tomcat/webapps/ROOT/WEB-INF/lib/
12. WRITING A CUSTOM TRIGGER
Calling any trigger executes:
public boolean process() throws
TriggerProviderException, FatalTriggerProviderException
Override the process() method, while allowing most
everything else to be inherited from superclass
Useful variables available inside process() method:
com.hannonhill.cascade.model.workflow.adapter.PublicWorkfl
owAdapter workflow
com.hannonhill.commons.util.string.StringMap parameters
String mode = parameters.get("mode");
13. ADD TRIGGER TO WORKFLOW
DEFINITION
• Triggers are defined in the <triggers> section of
each workflow definition
• Cannot be added in GUI workflow builder, must edit
XML
<!-- default trigger -->
<trigger class="com.cms.workflow.function.EmailProvider"
name="EmailProvider"/>
<!-- custom trigger -->
<trigger name="email"
class="edu.pima.cascade.workflow.EmailProvider2" />
15. DEFINING EMAIL MESSAGES
• Messages are defined in a Java properties file
• Could just as well have been text, XML, etc…
• Use placeholders for common fields like workflow
name and generating HTML links to the CMS
• Depending on workflow step type, emails are
targeted to workflow owner (submitter) or the group
owning the asset
• Messages about approval being required go to the group
owning the asset, but limited to the Approval role
16. SAMPLE EMAIL DEFINITIONS
email.needs-approval.mailApproversOnly = 1
email.needs-approval.subj = Web page needs approval - [WORKFLOW_NAME]
email.needs-approval.msg = <p>A web page or document is waiting
for your review and approval - [WORKFLOW_NAME]</p>
<p>Use the link below to access the web workflow:<br />
<a href="[VIEW_WORKFLOW_URL]">View the workflow screen</a></p>
email.was-approved.subj = Web page was approved - [WORKFLOW_NAME]
email.was-approved.msg = <p>A web page or document that you
submitted to CMS workflow has been approved - [WORKFLOW_NAME]</p>
<p>Use the link below to view the document in the web content
management system:<br />
<a href="[VIEW_ASSET_URL]">View document</a></p>
17. CUSTOM FEATURE: ESCALATIONS
• What if you know an approver is on vacation, and
you don't want to wait for the escalation timeout?
• Want to be able to find and "steal" their workflows
• The webmaster should be able to take any
workflow at any time!
19. ESCALATION TOOL UI
• Written in JSP
• Placed in:
• [cascade install]/tomcat/webapps/ROOT/pccCustom/wkflow
• Access at:
• https://your.cms/pccCustom/wkflow
• Putting custom components in separate directory
for safety during upgrades
20. ACCESS CONTROL
LoginInformationBean login =
(LoginInformationBean)session.getAttribute("user");
if
(!ServiceProviderHolderBean.getServiceProvider().getRole
Service().userHasRoleByRolename(login.getUsername(),
"Administrator"))
{
errMsg = "Only administrators can do that!";
}
21. SEARCHING WORKFLOWS FOR USER
Results powered by
com.hannonhill.cascade.model.service.WorkflowService
Must fetch both active and waiting workflows for user
List<Workflow> wkflows =
wkflowService.getActiveWorkflowsForUser(usernam
e);
wkflows.addAll(wkflowService.getWaitingWorkflow
sForUser( username));
22. HAVE WORKFLOW, WILL ESCALATE
WorkflowService has method to escalate all overdue
workflows, but no method to escalate just one
We will have to do the escalation ourselves!
Find current
step of the Find
workflow escalation
step of Advance
current step workflow to
the escalation
step
23. AND NOW, A WORD ABOUT HIBERNATE
• By default, Hibernate uses lazy collection fetching
• If an object has an associated collection, the collection
is retrieved from DB only when it is specifically requested
• If property is "many-to-one" in Hibernate XML config, it is
affected unless we override lazy fetching
• The current step of a workflow is many-to-one
• As is the escalation step of a workflow step
24. SO WE HAVE TO MESS WITH HIBERNATE?
• We could alter the Hibernate configuration XML files
• Set lazy="false" on chosen properties
• But this affects every workflow/step load in the
system
• And is likely to be overwritten in an upgrade
• But it's easy to do
25. OR…
• Generate additional DB queries for properties as
needed
• How often will you manually escalate a workflow?
• No performance hit to system in general
• No modifications to existing CMS components
• This is more complicated to do!
26. USING JOINS
• Bean getters get lazily-initialized objects
• workflow.getCurrentStep()
• workflowStep.getEscalationStep()
• By default both of these will yield LazyInitializationException!
• We can request objects with additional properties
joined from most DAOs
• HashSet<Join> joins = new HashSet<Join>();
joins.add(new Join(Workflow.PROPERTY_CURRENT_STEP));
workflow = workflowDao.get(workflowId, joins);
step = workflow.getCurrentStep(); // success!
27. EXCEPT…
The Hibernate DAO for workflow steps does not
expose a way to join properties.
package edu.pima.cascade.model.dao.hibernate;
public class HibernateWorkflowStepDAO extends
com.hannonhill.cascade.model.dao.hibernate.HibernateWorkflowStepDAO
implements WorkflowStepDAO {
/***************************************************
* Parent class assumes you would not want to join
* wkflow steps. This is probably just an oversight.
*/
public WorkflowStep get(String id, Set<Join> joins)
{
//fetch() is a protected method on BaseHibernateDAO.
return ((WorkflowStep)fetch(id, WorkflowStep.class,
joins));
}
}
28. ADD NEW BEAN TO CASCADE
• Spring looks for configuration files in the classpath:
• com.hannonhill.cascade.config.spring.applicationContext*.xml
• Add a new configuration file
• applicationContextPcc.xml
• Not overwritten when upgrading Cascade Server
• Want to remove all the custom components? Just remove
the XML config file from the classpath
<bean id="pccWorkflowStepDAO" class=
"edu.pima.cascade.model.dao.hibernate.HibernateWorkflowStepDAO"
/>
29. FINALLY: ESCALATE THE WORKFLOW
• Since we are forcing early escalation, reset the
"normal" escalation timeout
escalateStep.setStartedOn(Long.valueOf(System.currentTi
meMillis()));
• Do the actual escalation
workflow.setCurrentStep(escalateStep);
workflowService.save(workflow);
workflowMgmtService.advanceWorkflow(workflow.getId(),
"system", null, "Workflow escalation forced by
administrator");