Archive for November, 2009

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.

Advertisements

Teamsite in debug mode

Posted: 30 November 2009 in Architecture, Teamsite

If you want to know what happens in the teamsite environment and run it in debug mode, then go to the following URL on the teamsite server:

http://teamsite/iw-cc/command/iw.base.loggers

There, click on the debug link and Teamsite will start logging everything to the log files.

CSSimpleFile provides an input stream to access the content of the file. Here’s a utility to read the content from the files, both as text and as binary content:

package piquet;

import com.interwoven.cssdk.common.CSException;
import com.interwoven.cssdk.filesys.CSSimpleFile;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 *
 * @author piquetl
 */
public class CSSimpleFileReader {

 public static String read(CSSimpleFile simpleFile) throws IOException, CSException {
     byte[] fileContent=readBytes(simpleFile);
     return new String(fileContent, "utf-8");
 }

 public static byte[] readBytes(CSSimpleFile simpleFile) throws IOException, CSException {
 if (simpleFile == null) {
     throw new IllegalStateException("Cannot read null file.");
 }
 if (((int) simpleFile.getSize()) > Integer.MAX_VALUE) {
 throw new IOException("File is too large");
 }

 byte[] bytes = new byte[(int) simpleFile.getSize()];
 int offset = 0;
 int bytesRead = 0;
 InputStream inputStream = simpleFile.getInputStream(true);
 while (offset < bytes.length && (bytesRead = inputStream.read(bytes, offset, bytes.length - offset)) >= 0) {
 offset += bytesRead;
 }
 inputStream.close();
 return (bytes);
 }
}

From time to time, your data requirements will change. This cascades down to the data types you use. Adding new fields, removing others, changing values are all part of the evolution of your data so you should be prepared to transform it.

In this article, I will focus on migrating DCRs from one type to another. By way of example, I will use a fictitious intranet article type and something similar but different with portal news.

Intranet article Portal news
Article/type
Article/language
Article/region
Article/global
Article/category
Article/title Article/title
Article/date Article/date
Article/sortdate Article/sortdate
Article/content Article/content
Article/synopsis Article/synopsis
Article/image Article/image
Article/displayImage Article/showImage

The types are similar, as in real life your types will be similar: that’s why you’re changing them.

The plan is to wrtie an XSL stylesheet that wil help us transform DCR XML files of one type into DCR XML files of another type. This will be achieved through a java class that will scan the directory, perform the transformation and declare the resulting files as DCRs of the right type by setting some extended attributes on them. Here’s a sample source intranet article:

<?xml version="1.0" encoding="UTF-8"?>
<article>
 <title>lorem</title>
 <date>01 January 1970</date>
 <sortdate>01 January 1970</sortdate>
 <content><![CDATA[<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>]]></content>
 <synopsis><![CDATA[<p>Morbi feugiat nunc non urna auctor venenatis pulvinar nisi commodo.</p>]]></synopsis>
 <image>/resources/logo.gif</image>
 <displayImage>true</displayImage>
</article>

I create the XSL transformation template. I put it in templatedata/intranet/article/presentation. the file name is toPortalNews.xsl.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml"/>
    <xsl:template match="/article">
        <article>
        </article>
    </xsl:template>
</xsl:stylesheet>

It is best to deal with the fields in order. The missing values will be defaulted:

  • Article/language: en-gb
  • Article/region: emea
  • Article/global: false
  • Article/category: news
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml"/>
    <xsl:template match="/article">
        <article>
            <language>en-gb</language>
            <region>emea</region>
            <global>false</global>
            <category>news</category>
        </article>
    </xsl:template>
</xsl:stylesheet>

For the other fields, I can select them and copy them directly as they are identical, using the xsl:copy command:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output method="xml"/>
 <xsl:template match="/article">
 <article>
 <language>en-gb</language>
 <region>emea</region>
 <global>false</global>
 <category>news</category>
 <xsl:apply-templates select="title|date|sortdate|content|synopsis|image" />
 </article>
 </xsl:template>

 <xsl:template match="*">
 <xsl:copy>
 <xsl:apply-templates select="@*"/>
 <xsl:apply-templates />
 </xsl:copy>
 </xsl:template>

 <xsl:template match="@*">
 <xsl:copy />
 </xsl:template>

</xsl:stylesheet>

For the last field which has the same value but a different name, I can use a simple xsl:value-of and encase that in the new field. this goes after the xsl:apply-template command in my example.

<showImage><xsl:value-of select="displayImage"/></showImage>

and the result is

<?xml version=”1.0″ encoding=”UTF-8″?>
<article>
<language>en-gb</language>
<region>emea</region>
<global>false</global>
<category>news</category>
<title>lorem</title>
<date>01 January 1970</date>
<sortdate>01 January 1970</sortdate>
<content>&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&lt;/p&gt;</content>
<synopsis>&lt;p&gt;Morbi feugiat nunc non urna auctor venenatis pulvinar nisi commodo.&lt;/p&gt;</synopsis>
<image>/resources/logo.gif</image>
<showImage>true</showImage>
</article>

SimpleDateFormat in javascript

Posted: 3 November 2009 in Javascript
/**
 * SimpledateFormat javascript class
 *
 * var reverseDateFormat = new SimpleDateFormat("YYYYMMdd");
 * var reverseDate = reverseDateFormat.format(new Date());
 * http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
 *
 * **/
function SimpleDateFormat(formatString){
 this.formatString = formatString;
 this.monthNames = ["January","February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
 this.dayNames =   ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];

 this.format = function(aDate){
 var localFormatString = formatString;
 // The order is significant
 /* YYYY */  localFormatString = localFormatString.replace(/Y{3,}/g,     "\" + (aDate.getFullYear()) + \"");
 /* YY   */  localFormatString = localFormatString.replace(/Y{2}/g,      "\" + ((aDate.getFullYear()).toString().substring(2)) + \"");
 /* MMMM */  localFormatString = localFormatString.replace(/M{4,}/g,     "\" + (this.monthNames[aDate.getMonth()]) + \"");
 /* MMM  */  localFormatString = localFormatString.replace(/M{3}/g,      "\" + ((this.monthNames[aDate.getMonth()]).substring(0,3)) + \"");
 /* MM   */  localFormatString = localFormatString.replace(/M{2}/g,      "\" + (aDate.getMonth()+101).toString().substring(1) + \"");
 /* ww   */  /* don't have time to implement this today */
 /* WW   */  /* don't have time to implement this today */
 /* DD   */  /* don't have time to implement this today */
 /* dd   */  localFormatString = localFormatString.replace(/d{2}/g,      "\" + (aDate.getDate()+100).toString().substring(1) + \"");
 /* FF   */  localFormatString = localFormatString.replace(/F{2}/g,      "\" + (aDate.getDay()+100).toString().substring(1) + \"");
 /* EEEE */  localFormatString = localFormatString.replace(/E{4,}/g,     "\" + (this.dayNames[aDate.getDay()]) + \"");
 /* EEE  */  localFormatString = localFormatString.replace(/E{3}/g,      "\" + ((this.dayNames[aDate.getDay()]).substring(0,3)) + \"");
 /* EE   */  localFormatString = localFormatString.replace(/E{2}/g,      "\" + (aDate.getDay()+100).toString().substring(1) + \"");
 /* a    */  /* don't have time to implement this today */
 /* HH   */  localFormatString = localFormatString.replace(/H{2}/g,      "\" + (aDate.getHours()+100).toString().substring(1) + \"");
 /* kk   */  localFormatString = localFormatString.replace(/k{2}/g,      "\" + (aDate.getHours()+101).toString().substring(1) + \"");
 /* KK   */  /* don't have time to implement this today */
 /* hh   */  /* don't have time to implement this today */
 /* mm   */  localFormatString = localFormatString.replace(/m{2}/g,      "\" + (aDate.getMinutes()+100).toString().substring(1) + \"");
 /* ss   */  localFormatString = localFormatString.replace(/s{2}/g,      "\" + (aDate.getSeconds()+100).toString().substring(1) + \"");
 /* SS   */  localFormatString = localFormatString.replace(/S{2}/g,      "\" + (aDate.getMilliSeconds()+1000).toString().substring(1) + \"");
 /* z   */   /* don't have time to implement this today */

 localFormatString = "\"" + localFormatString + "\"";
 //prompt("localFormatString", localFormatString);
 var formatedDate = eval(localFormatString);
 return(formatedDate);
 }
}