Archive for the ‘URLExternalTask’ Category

When creating a workflow deployment task, you can specify the following Task Variables:

ClassName: (optional)com.interwoven.ui.teamsite.workflow.task.urltask.DeployURLExternalTask. a deployment task is only a URLExternalTask with additional variables.

odDeploymentName: (required)The name of the deployment file to use, without the .xml extension.

odDeploymentInst: (optional)The suffix to uniqely differentiate the deployments. Allows concurrent deployments. I normally set this to a script variable as “_$IW_USER_” + new Date().getTime();

Additional values may be set for odHost, odPort but they have default values for the current environment. You only set these up when you’ve change the defaults.

Deployment specific variables (normally set with a -k on the command line) can also be set in the OD Variables field, or in the normal task variables by prefixing their name with “odSubst_”.

Advertisements

As I have said before, it’s the little things that throw you. It’s how the 80-20 rule got created: you spend 20% of your time developing 80% of the functionality and 80% of your time developing the remaining 20%.

This time, I was attempting to read parameters from a workflow CGI task. Parameters are passed to a workflow task from the command property of the task:

Command: http://$IW_SERVER/iw-cc/urlexternaltask?someparam=somevalue&someotherparam=someothervalue

When reading the map, the parameters are passed as a map of String arrays, not as a map of Strings.

Sometimes, you want to change things in another task before you get to that task. for example, to set the name of the instance of a deployment task.

First, you have to be able to find the other task. For this, you need its name and add call the following method:

/**
 * find a task by name in a workflow job
 * @param job the job to get the task from. use task.getWorkflow() from the current task
 * @param taskName the name of the task to find in the workflow
 * @return the task object found, or null if an exception occured or the task was not found in the workflow
 */
 public static CSTask getWorkflowTask(CSWorkflow job, String taskName) {
 CSTask taskFound = null;
 try {
 for (CSTask task : job.getTasks()) {
 if (task.getName().equals(taskName)) {
 taskFound = task;
 }
 }
 } catch (CSException ex) {
 Logger.getLogger(TaskUtil.class.getName()).log(Level.SEVERE, null, ex);
 }
 return (taskFound);
 }

Then, you can add the follwoing code to update the variable of the target task:

public static void setTargetTaskVariable(CSExternalTask task, String targetTaskVariableValue) throws CSException {
 String targetWorkflowTask = task.getVariable("targetWorkflowTask");
 String targetTaskVariableNameToSet = task.getVariable("targetTaskVariableNameToSet");
 CSTask workflowTargetTask = TaskUtil.getWorkflowTask(task.getWorkflow(), targetWorkflowTask);

 if (workflowTargetTask != null && targetTaskVariableNameToSet != null && targetTaskVariableValue != null) {
 //System.out.println("open deploy task found. Updating variable.");
 workflowTargetTask.setVariable(targetTaskVariableNameToSet, targetTaskVariableValue);
 System.out.println("Setting variable: " + targetTaskVariableNameToSet + "=" + targetTaskVariableValue);
 } else {
 if (workflowTargetTask == null) {
 System.err.println("Target task not found.");

 } else if (targetTaskVariableNameToSet == null) {
 System.err.println("Target task variable name not set.");

 } else if (targetTaskVariableValue == null) {
 System.err.println("Target task variable value not set.");

 }
 }

 }

Add a couple of task variable to the updating task, namely

  • targetWorkflowTask
  • targetTaskVariableNameToSet

Your class must calculate the value of the variable to set and update the variable whose name was passed to the workflow, in the specified task. I have used this to set the instance name of the deployment to the job id of the workflow, making them unique.

URL External tasks are useful for running code on the teamsite server as part of your workflow. The task runs in the background ; users don’t get to see what it does and don’t get to interact with the task. If you want your users to interact, such as fill in a form or view progress, consider CGI tasks instead.

On the workflow modeler canvas, add the url external task. You can find it on the toolbar as the kind of world with a cog type of icon. Once you have added the task, you need to update the properties.

The URI property specifies the teamsite servlet that will grab the request the workflow will make on your behalf to go and execute your class on the server. We don’t have to write one, Autonomy already provides on at http://localhost/iw-cc/urlexternaltask. Enter this value as the property.

The next property we need to enter is the variables (in the Task Variables properties section). There we will add variables that can be passed to our Java code. First, we need to pass a variable to the servlet to tell it which class to go and execute. In the Name box, enter “ClassName” (it’s case sensitive and no, do not include the quotes). In the value, enter the fully qualified name of the class to execute, such as “com.acme.workflow.MyClass”.

Link your task and save your workflow. Now we need to create our class that will be executed during the workflow execution.

In the content center toolkit (customer_src/src), create the package directories. In my case, “com/acme/workflow” and in there, create the java source code file for your class, in my case “MyClass.java”.

The class will be executed by the servlet but we don’t get to specify which method it runs.  Instead, we must abide to the interface CSURLExternalTask, which defines the execute method that we must implement.

package com.acme.workflow;
public class MyClass implements CSURLExternalTask {
    public void execute(CSClient client, CSExternalTask task, Hashtable params) throws CSException {
        System.out.println("Hello world");
        task.chooseTransition("link name","transition comment");
    }
}

the task’s chooseTransition method takes 2 parameters. The first one is the name of the link to transition to the next task. That means your task can make decisions and decide to follow one path of execution over another one during the workflow. If the parameter is an empty string, the workflow engine will transition with the first available link.

The second parameter is the transition comment that the task can leave behind to explain what has happened during its execution.

Compile the class and execute the workflow. In servletd_out.log, your workflow will say hello to you.

When you generate sitepublisher pages in the out of the box workflow, it runs as a CGI script invoking /iw-cc/Workflow/Webtask.do. This requires the user to start the input task in certain circumstances which may not always be desirable. In those cases, we want to run the page generation as a URLExternalTask, not as a CGI script.

how does it work?

In the Teamsite web application, *.do requests are intercepted by struts and so is our /iw-cc/Workflow/Webtask.do request. No exception… A task variable with a name of TaskBeanId is passed to the task and struts will instantiate an object of the corresponding class by resolving the bean entry from the file httpd/webapps/content_center/WEB-INF/conf/livesite/resources/workflow-resource-config.xml.

The TaskBeanId in question in the original task is workflow.task.PageConversionTask and, looking in the file workflow-resource-config.xml, we can translate it to com.interwoven.livesite.workflow.web.task.PageConversionWebTask.

<bean id="workflow.task.PageConversionTask"
    class="com.interwoven.livesite.workflow.web.task.PageConversionWebTask">
 <property name="viewPath" value="/livesite/Workflow/PageConversionWebTask.jsp"/>
 <property name="suffixVariableName" value="Suffix"/>
 <property name="processorVariableName" value="Processor"/>
 <property name="destinationDirectoryVariableName" value="DestinationDirectory"/>
 <property name="filterPatternVariableName" value="FilterPatterns"/>
 <!-- if you want a custom delimiter for the filter patterns, default is comma -->
 <property name="filterPatternDelimiterVariableName" value="FilterPatternDelimiter"/>
 </bean>

When an object of that class is instantiated, the other properties associated with the bean are set with the values given. These will allow the object to query the task and find the task variable with a name of Suffix, Processor, DestinationDirectory,FilterPatterns and FilterPatternDelimiter.

Creating a URLEXternalTask

Inside workflowModeler, add a URL Task to the canvas of the workflow model. set the predecessor by linking to the task from another task or the start event icon. Set the name of the task to be “Generate HTML”. This name can be whatever you want but it is quite significant elsewhere as we will see later. Set the URI to be http://localhost/iw-cc/urlexternaltask.

In the Task Variables, we will specify the class to execute and no, we will not use the class com.interwoven.livesite.workflow.web.task.PageConversionWebTask because that class expects some JSP to forward the request to. No, instead we shall look at the other bean defined by the following XML:

<bean id="workflow.task.HeadlessPageConversionTask"
    class="com.interwoven.livesite.workflow.task.PageConversionTask">
 <property name="suffixVariableName" value="Suffix"/>
 <property name="processorVariableName" value="Processor"/>
 <property name="destinationDirectoryVariableName" value="DestinationDirectory"/>
 <property name="servicePath" value="/iw-cc/livesite/PageConversionServlet"/>
 <property name="sessionStringParameterName" value="iw_sessionstring"/>
 <property name="filterPatternVariableName" value="FilterPatterns"/>
 <!-- if you want a custom delimiter for the filter patterns, default is comma -->
 <property name="filterPatternDelimiterVariableName" value="FilterPatternDelimiter"/>
 </bean>

The reason we choose this one is because it does not require to forward any requests anywhere. we will duplicate the original task variables for Suffix, Processor, DestinationDirectory, FilterPatterns, FilterPatternDelimiter.

However, when we have the original CGI script task WebTask.do activated, struts will instantiate the bean for us, with the right values for the properties. Our external task currently does no such thing. Waht we shal do is create a custom CSURLExternalTask that extends the bean class specified and, upon instantiation sets the property values.

package com.acme.workflow;

public class PageConversionTask extends com.interwoven.livesite.workflow.task.PageConversionTask {

    private String mSuffixVariableName="Suffix";
    private String mProcessorVariableName="Processor";
    private String mDestinationDirectoryVariableName="DestinationDirectory";
    private String mFilterPatternVariableName="FilterPatterns";
    private String mFilterPatternDelimiterVariableName="FilterPatternDelimiter";
    private String mSessionStringParameterName="iw_sessionstring";
    private String mServicePath="/iw-cc/livesite/PageConversionServlet";

    public PageConversionTask() {
        super();
        super.setProcessorVariableName(mProcessorVariableName);
        super.setDestinationDirectoryVariableName(mDestinationDirectoryVariableName);
        super.setFilterPatternVariableName(mFilterPatternVariableName);
        super.setFilterPatternDelimiterVariableName(mFilterPatternDelimiterVariableName);
        super.setSessionStringParameterName(mSessionStringParameterName);
        super.setServicePath(mServicePath);
        super.setSuffixVariableName(mSuffixVariableName);
        System.out.println("instantiated com.acme.workflow.PageConversionTask");
    }

}

Compile the class into the customer_src toolkit and set the task variable ClassName to com.acme.workflow.PageConversionTask. The class will be executed by the workflow but as it stands will fail to transition properly. This is because the transition link names must be whatever the name of the task is plus “Success” or “Failure”. In our case it should be “Generate HTML Success” and “Generate HTML Failure”.

Another thing, this time concerning task paramerers. The way the task has been implemented, it is shomehow expecting task parameters, otherwise it reports an excpetion and fails. We need to pass some parameters to the task and it doesn’t even matter what they are. so for the URI, we can specify http://localhost/iw-cc/urlexternaltask?someParam=someValue. The task itself doesn’t even seem to use those parameters at all(!).

This little thing could be used to our advantage. If you look in our custom class, the names of the variables are hard-coded. This should be modified in the constructor to look ath the values of equivalent parameters, which could be passed with http://localhost/iw-cc/urlexternaltask?suffixVariableName=Suffix&destinationDirectoryVariableName=DestinationDirectory etc… To read the values would be done with a task.getParameter(“suffixVariableName”) statement.

Conclusion

You now can invoke page generation in workflows automatically without the intervention of users, in complete silence of the background process in the depth of your workflows.  Genius.