Archive for July, 2010

Who does what in a Web Content Management? Not everyone does the same job when creating a website (or a whole bunch of them).

So let’s have a look at the various roles and responsibilities.

The Content Contributor:

The content contributor mostly fills out forms with content. Titles, dates, description, body of content.

The Site Manager

The site’s manager’s responsibility is to create a shell for the site. It therefore is responsible for the creation of pages and the creation of the sitemap (in Teamsite, the navigation of the site is separated from the physical structure of the site).

The Content Editor:

Just as a magazine or newspaper, someone is responsible for the content. The content editor is responsible for resolving conflicts between people (for access to the content) and versions of the content.

The Teamsite Administrator: Just like the content editor is responsible for create a site shell for pages, the administrator is responsible for creating user areas in the Teamsite environment. These are workareas and branches.

The System’s Administrator: Just like the administrator deals with the branches and workareas, the system’s administrator is responsible for the installation of TeamSite and the services.

The TeamSite Master: Just like a UNIX system has a “root” user that is unrestricted, the “Administrator” on Windows, a Teamsite user who is a Master is unrestricted on the system.

All these roles can be given to TeamSite users and a lot of the time, the lines are blurred. For example, a smaller organisation may have one person filling the role of the content contributor, editor and site manager all at once.


Teamsite is a content management system primarily geared towards web content management. At its core lies a version control system which helps content contributors manage the files that make up the web site and keeps track of the evolution of those files over time.

Access to assets stored in Teamsite requires that a set of permissions be given to each user to manipulate them. Access to Teamsite itself also requires authentication.

To facilitate the work of content contributors, Teamsite FormsPublisher allows users to enter content through forms. Content is completely separated from presentation and is stored as XML files named Data Content Records (DCRs).

The XML content of DCRs can be transformed into static documents (HTML, JSP, ASP, PHP, plain text, RSS, …) through the use of custom PERL templates or XSLT templates.

In addition, SitePublisher allows users to compose a page though a WYSIWYG interface for dragging and dropping (XSL) components (re-useable page parts such as header, footer, stock price, RSS feed…) which can also load the XML content of DCRs. Again, the pages composed this way can be generated as a static document.

The document creation process (or other company processes) can be supported by workflows from creation to publication. This workflow engine is java based and therefore extremely extensible.

Metadata can be applied to any file stored in TeamSite and this follows an extensible model which allows you to define your own metadata tags and their values.

The propagation of documents from Teamsite to the actual web server that delivers the website (Apache, IIS, Tomcat,… ) can be performed by OpenDeploy. This works with a repeatable deployment configuration which allows to configure where the files get deployed (published) to, consistently.

One of the selling points of OpenDeploy is the ability to deploy the files to a database. Known as DataDeploy, this can be useful is you want to use this data from JSP and you are more comfortable with database queries than loading XML files. This is also often used for search engine indexing.

In addition to this, an event system allows you to detect when content changes and take additional action (custom notification for example). This event system is leveraged by OpenDeploy to perform database auto-synchronisation and automatically perform database update when content changes.

Datasources allow mainly to select things from drop-down lists in forms publisher forms and workflow forms.

Datasources are nothing but java classes that get executed when a form loads. The class must implement one of the following interfaces:


As part of the implementation, the class must therefore have an execute method which gets passed a DataSourceContext object. The return value and type vary depending of which datasource class you implement.

A SimpleDataSource implementation returns a single value. Forms publisher will use the value for example in a text field.

public String execute(String sessionId, String context, Map params) {
String datasource="value";

A ListDataSource implementation will return a List of strings. Forms publisher will use the same value for the form’s value and label.

public List<String> execute(DataSourceContext context) {
List<String> datasource = new ArrayList<String>();

The context contains some information about the session id, the server context (the vpath of the current node) and the other custom parameters passed to the datasource.

A MapDataSource implementation will return map of strings. Forms publisher will use one value for the label and the other for the value. The key is the value string.

public Map<String, String> execute(DataSourceContext context) {
Map<String,String> datasource = new HashMap<String,String>();
datasource.put("value","label"); // make sure you convert numbers to proper strings

The SortedMapDataSource implementation returns the same as a MapDataSource, except Forms Publisher will sort the results alphabetically.

public Map<String, String> execute(DataSourceContext context) {
Map<String, String> datasource = new HashMap<String, String>();
datasource.put("value", "label"); // make sure you convert numbers to proper strings
return (datasource);

In order to create a new datasource, we need to edit the local/config/DataSourceConfig.xml file. This file is an XML document which defines which datasources are available to the system as a whole.

For the example that follows, we will create a datasource that will allow a user to select an edition from the current branch. We need to add our datasource to the list by adding the following:

<name>Main Branch Editions</name>
<param name="branch">/default/main</param>

We will build a class with that name as follows:

package com.acme.util;

import com.interwoven.cssdk.factory.CSLocalFactory;
import com.interwoven.cssdk.filesys.CSBranch;
import com.interwoven.cssdk.filesys.CSEdition;
import com.interwoven.cssdk.filesys.CSVPath;
import com.interwoven.datasource.core.DataSourceContext;
import com.interwoven.datasource.SortedValuesMapDataSource;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

public class BranchEditionsDataSource implements SortedValuesMapDataSource {

 public Map<String, String> execute(DataSourceContext context) {
 Map<String, String> parameters = context.getAllParameters();
 Map<String, String> datasource = new HashMap<String, String>();
 String sessionString = context.getSessionId();
 String configFilePath = "/apps/interwoven/teamsite/cssdk/cssdk.cfg";
 Properties localProperties = new Properties();
 localProperties.setProperty("cssdk.cfg.path", configFilePath);
 CSLocalFactory csLocalFactory = (CSLocalFactory) CSLocalFactory.getFactory(localProperties);
 CSClient client = null;

 try {
 client = csLocalFactory.getClient(sessionString, Locale.ENGLISH, "BranchEditionsDataSource", "localhost");
 if (client != null) {
 String branchParameter = parameters.get("branch");
 CSVPath branchVPath = null;
 if (branchParameter != null) {
 branchVPath = new CSVPath(branchParameter);
 } else {
 branchVPath = new CSVPath(context.getServerContext());
 if (branchVPath != null) {
 branchVPath = branchVPath.getBranch(); // make sure we have a branch, really...
 CSBranch branch = client.getBranch(branchVPath, true);
 if (branch != null) {
 CSEdition[] editions = branch.getEditions(true, false, -1);
 for (CSEdition edition : editions) {
 datasource.put(edition.getVPath().toString(), edition.getName() + " - " +                                             edition.getDescription());
 } else {
 throw new NullPointerException("branch is null");
 } else {
 throw new NullPointerException("branch vpath is null");
 } else {
 throw new NullPointerException("client is null");
 } catch (Exception ex) {
 datasource = new HashMap<String, String>();
 datasource.put("error", "An error occured. Please contact your administrator");
 Logger.getLogger(BranchEditionsDataSource.class.getName()).log(Level.SEVERE, null, ex);

 return (datasource);

The context gives you all you need to connect to the local Teamsite server using the session id. From there, we can either grab the editions of the branch passed as a parameter or the current branch. You can also extend


This will give you the ability to grab the client with a simple method call of:

CSClient client=getClient(context);

You will have to use the parameters that the class expects to make the connection:

<param name="servername">teamsite</param>
<param name="csFactory">com.interwoven.cssdk.factory.CSLocalFactory</param>

Once the class has been compiled into the toolkit, we can then tell out formspublisher item to use it.

we can use a “inline” element, with a Datasource “pseudo-command” (note that this is case sensitive). This works for text instances and select, radio and checkbox instances.

    <inline command="Datasource:executeComponent:Main Branch Editions" />

All you now need to do is check the work in the form’s drop down list..

Today, there’s a webinar on multilingual sites. Here’s what I found.

They started talking about “dependency management”, with bi-directionally relation of assets to each other. This require use of the metadata. MediaSurface has been very good at doing this for a long time. This is good for a “where used” functionality, and by extension see the impact of moving a piece of content. Note that Teamsite will not update the related files when you move/delete a piece of content. You’ve got to do that yourself.

They then talked about globalised content management as globalisation in Teamsite leverages this dependency management as it clones a site and adds “locale” dependencies.

Pages and DCRs have dependencies and you can create a localised copy of the content (if you maked the content piece as localisable), forming a site “family”. Branches get additional configurations where you add the supported locale.

In order to achieve this, additional extended attributes have been created. Also, the site name gets the locale appended to its name (e.g. mysite and mysite_fr).

There is also a “translation monitoring dashboard” (accessible from the actions menu), which helps you track how far along the localisation process you are. The translation workflow can be internal (in iw-cc) or integrated with an external process. Changes can be propagated to specific sites.

As far as upgrades are required, they mentioned upgrade scrips that creates the used dependencies trees, although the localisation will require manual work (they didn’t go into too much details there…). The publish livesite content workflow has been updated to take care of some additional tasks. This should work with Teamsite v7.1 and 7.2

In the runtime, each site is an independent geography runtime. Locales can be prioritised when the visitors access the site (browser, language preferences, query parameters, visitor profile). The Q & A session afterwards didn’t reveal anything earth shattering.

My view on this? If you’re a big global organisation, this may be for you. I don’t know how it will handle your sites if you already have lots of localised content since it needs to build dependency trees but if you’re just starting out, it could help you along.

This evening is the autonomy webcast on multi-lingual websites. The webcast is entitled “Multilingual Site Management with Teamsite”. I hope to see how they think we should do it.

I will take the opportunity to compare their best practice with one solution I offered way earlier (see this post). Note that you can also use the localisation key in the sitemap in the same manner.

This is the solution I implemented when creating the for the Russian offices. It works well for us.

I am not expecting a ground-breaking webcast, but since they’re nice enough to invite me, I believe I will attend.