Você está na página 1de 110

Interwoven®

ContentServices™ for TeamSite


Cookbook
Release 2.5
© 2003, 2004 Interwoven, Inc. All rights reserved.

No part of this publication (hardcopy or electronic form) may be reproduced, translated into another
language, or transmitted, in any form or by any means, electronic, mechanical, photocopying, recording,
or otherwise, without the prior written consent of Interwoven. Information in this manual is furnished
under license by Interwoven, Inc. and may only be used in accordance with the terms of the license
agreement. If this software or documentation directs you to copy materials, you must first have permission
from the copyright owner of the materials to avoid violating the law which could result in damages or other
remedies.

Interwoven, TeamSite, Content Networks, OpenDeploy, MetaTagger, DataDeploy, DeskSite, iManage,


MailSite, MediaBin, MetaCode, MetaFinder, MetaSource, OpenTransform, Primera, TeamPortal,
TeamXML, TeamXpress, VisualAnnotate, WorkKnowledge, WorkDocs, WorkPortal, WorkRoute,
WorkTeam, the respective taglines, logos and service marks are trademarks of Interwoven, Inc., which
may be registered in certain jurisdictions. All other trademarks are owned by their respective owners.
Some or all of the information contained herein may be protected by patent numbers: US # 6,505,212, EP
/ ATRA / BELG / DENM / FINL / FRAN / GBRI / GREC / IREL / ITAL / LUXE / NETH / PORT /
SPAI / SWED / SWIT # 1053523, US # 6,480,944, US# 5,845,270, US #5,384,867, US #5,430,812,
US #5,754,704, US #5,347,600, AUS #735365, GB #GB2333619, US #5,845,067, US #6,675,299,
US #5,835,037, AUS #632333, BEL #480941, BRAZ #PI9007504-8, CAN #2,062,965, DENM / EPC
/ FRAN / GRBI / ITAL / LUXE / NETH / SPAI / SWED / SWIT #480941, GERM #69020564.3,
JAPA #2968582, NORW #301860, US #5,065,447, US #6,609,184, US #6,141,017, US #5,990,950,
US #5,821,999, US #5,805,217, US #5,838,832, US #5,867,221, US #5,923,376, US #6,434,273,
US #5,867,603, US #4,941,193, US #5,822,721, US #5,845,270, US #5,923,785, US #5,982,938,
US #5,790,131, US #5,721,543, US #5,982,441, US #5,857,036, GERM #69902752.7or other
patents pending application for Interwoven, Inc.

This Interwoven product utilizes third-party components under the following copyrights with all rights
reserved: Copyright 1997 Eric Young; 2000-2003, Apache Software Foundation (www.apache.org);
Copyright 1999, ExoLab Group; Copyright 1999-2001, Intalio, Inc. If you are interested in using these
components for other purposes, contact the appropriate vendor.

Interwoven, Inc.
803 11th Ave.
Sunnyvale, CA 94089

http://www.interwoven.com
Printed in the United States of America

Release 2.5.0
Part # 90-15-00-250-201
October 2004
Table of Contents
About This Book 5
Tip on Using This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Prerequisite Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
ContentServices for TeamSite J2EE Sample Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Other Samples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Online Documentation Errata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Chapter 1: Overview 9
ContentServices. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
ContentServices Deliverables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
ContentServices for TeamSite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
The Java Client Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Behind the Scenes: SOAP and WSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Where to Go From Here. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Chapter 2: Developer’s Overview 17
TeamSite Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Additional Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Programming Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Part I: Getting Started 23
Chapter 3: Basics 25
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Creating a Factory Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Creating a Client Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Chapter 4: Files, Directories, and Workareas 31
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Creating and Deleting Workareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Renaming a Workarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Accessing Workarea Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Displaying Files in a Workarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Filtering the File List. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Reading and Writing Entire Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Creating and Deleting Files and Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Writing to a File. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Copying and Moving Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Part II: The Sample Application 51
Chapter 5: Getting Started with the
Sample Application 53
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Starting and Shutting Down Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Adding a JSP Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

3
Adding a Servlet or Bean. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Chapter 6: Extending the Sample Application 59
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Accepting Login Values from the User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Filtering Login Values for the Controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Creating a Factory Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Authenticating Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Allowing Users to Log Out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Handling Exceptions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Chapter 7: More on the Sample Application 79
Retrieving a User’s Workarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Downloading a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Displaying a List of Modified Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Allowing Direct Submits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Appendix A: Working with WSDL Files 95
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Generating and Using a C# Client Stub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Appendix B: Status Codes 101
Appendix C: Mapping ContentServices 1.1 to 2.5 107

4 ContentServices for TeamSite Cookbook


About This Book

We are aware that this guide is incomplete. We will be providing additional chapters and code examples
on the Interwoven download site after the TeamSite 6.5 release. Please check there for updates.

If you have opened this guide, you want to use the ContentServicesTM for TeamSite. This
SDK is designed for many different types of developers. The client applications you can
build with it fall into three main groups:

„ Local Java applications running on the same host as the TeamSite server
„ Remote Java applications running on a different host, most likely a web or application
server, that use content or functionality in the TeamSite server
„ Any other application, written in any language and running on any platform (that
supports SOAP version 1.1 or earlier), that uses the TeamSite server

If you want to develop one of these applications using ContentServices for TeamSite, this
guide is for you.

Tip on Using This Book


This guide is a cookbook. Each section (called a task) generally stands on its own. Mostly,
you can read any task that is relevant to what you are doing, without reading its previous
tasks. However, sometimes it’s helpful to read the Introduction to a chapter for
background, even if you only look at one task in that chapter.

Prerequisite Knowledge
Before you use this cookbook, you should know:
„ The type of client application you want to build
„ The language, platform, and technologies you plan to use for your application
„ Java, for reading the code examples presented here

This guide teaches you how to use ContentServices for TeamSite, along with a little about
SOAP (Simple Object Access Protocol) and WSDL (Web Services Description Language).
Most of the examples are written in Java, with a few in other languages.

5
If you are interested in reading more about industry standard web services, the
ContentServices SDK uses these technology versions:
„ SOAP 1.1
„ WSDL 1.1
„ Java, based on JDK 1.4

ContentServices for TeamSite J2EE Sample Application


This release of ContentServices for TeamSite includes a sample application that runs on a
Tomcat web server. The sample application shows how you might build a corporate Intranet
site with some TeamSite functionality, using either ContentServices JNI or ContentServices
SOAP. It uses a model-view-controller architecture that can easily be migrated to a J2EE
application server.

The sample application has JSP files, servlets, and beans written in JSP 1.2, Java Servlet API
2.3, and JSTL 1.0.3, all running on Apache Tomcat 4.1.27 (the release known as Catalina).
The sample is distributed as an exploded web application that you can run and as free,
supported source code that you can extend.

For this release, the sample application is distributed in a zip file. Install it according to the
instructions in quick_install_j2ee.html within the zip file. Once you install the sample
application, you might want to read the Quick Tour in tour.html to understand what it does.

About JSP, Servlets, and JSTL

As you work with the sample application, you may want to refer to an industry trade book
on the JSP, JSTL, or servlet technologies. Discussing those technologies in depth is beyond
the scope of this guide. You may have your own favorite books, but if not, these are a few
popular ones to help you:

„ JavaServer Pages, Second Edition, Hans Bergsten, O’Reilly, 2002


„ Core Servlets and JavaServer Pages, Marty Hall and Larry Brown, Prentice-Hall, 2003
„ JSTL in Action, Shawn Bayern, Manning Publications, 2002
„ Java Servlet Programming, Second Edition, Jason Hunter, O’Reilly, 2001

Participating in JSP and servlet developer forums is also quite educational. If you get stuck,
you can often get your questions answered by your fellow developers.

„ JavaServer Pages Forum


(http://forums.java.sun.com/forum.jsp?forum=45)
„ Java Servlet Technology Forum
(http://forums.java.sun.com/forum.jsp?forum=33)

You might find other favorite forums on the Internet as well.

6 ContentServices for TeamSite Cookbook


Other Samples

Other Samples
This release also has a short C# example for .NET developers. It’s in the samples zip file, in
the directory samples/dotnet. You can find its installation instructions in the zip file, in
quick_install_j2ee.html. You will also find more information about WSDL files in the
WSDL chapter of this guide.

If you are a Java programmer, you can learn about ContentServices for TeamSite by running
the short Java examples in the samples zip file. You can install them and set up runtime and
development environments by following the instructions in quick_install_java.html.

Conventions
This manual uses the following notation conventions:

Convention Definition and Usage


Bold Text that appears in a GUI element (for example, a menu item,
button, or element of a dialog box) and command names are shown in
bold. For example:

Click Edit File in the Button Bar.


Italic Book titles appear in italics.
Terms are italicized the first time they are introduced. Important
information may be italicized for emphasis.
Monospaced Example code, commands, command-line output, and file names are
in monospaced type. For example:

The iwextattr command-line tool allows you to set and look up


extended attributes on a file.
Monospaced Monospaced italics are used for command-line variables.The most
italic
common example of this is iw-home, which refers to the directory
where TeamSite is installed. For example:

iw-home\etc\iw.cfg

is the path to the main TeamSite configuration file, iw.cfg, which is


located in the etc directory under the TeamSite installation directory.

iwckrole role user

means that you must insert the values of iw-home, role and user
yourself.
Monospaced Monospaced bold, used in an example, represents a line of code that
bold
we want to call your attention to.

7
Online Documentation Errata
Additions and corrections to this document (when available) can be downloaded in PDF
format from the following Web site: https://support.interwoven.com.

8 ContentServices for TeamSite Cookbook


Chapter 1

Overview

Welcome to the Interwoven® ContentServices™ for TeamSite™ (formerly known as


ContentServices SDK). This software developer’s kit provides tools for building
applications on TeamSite® Content Server.

ContentServices
ContentServices is Interwoven’s line of developer tools and SDKs. ContentServices SDKs
expose certain Interwoven capabilities as web services across the internet.

Web services expose the functionality of a server to client application programs. An


Interwoven server is a host running one or more Interwoven programs, such as TeamSite,
WorkSite, MediaBin, or OpenDeploy.

Each web service is described by a WSDL, an XML formatted Web Services Definition
Language document. This file defines the requests used to invoke certain server program
capabilities and the possible responses and errors returned by that server.

Web service requests and responses are wrapped in SOAP (Simple Object Access Protocol)
messages, sent across HTTP or HTTPS connections.

These SOAP requests can either be generated directly by a client program or by invoking
client stubs in a specific programming language, such as Java or C#, that in turn generate the
SOAP requests and then translate the SOAP responses back to the application program.

Industry standard J2EE or .NET tools exist to automatically generate client stubs from
WSDL files. By supplying a WSDL file, a software vendor can potentially enable programs
in many different languages to access a given web service.

ContentServices Deliverables
ContentServices SDKs vary in their deliverables.

In some cases, such as the ContentServices for OpenDeploy, the SDK consists of the web
service server (for the host machine) and a commented WSDL, plus sample client stubs and
example programs for at least one programming language.

9
Overview

In other cases, such as ContentServices for TeamSite, the SDK also includes a supported and
documented client library for at least one language.

A client library has an additional layer built on top of its client stubs to provide caching,
iterators, client-side convenience calls, and other features designed to improve client
application performance when accessing those web services. Such libraries are generally
only useful when extensive context and data transfers are often needed before invoking the
services’ primary functionality (which is not the case for all web services).

In these cases, customers who wish to use other languages can still use the supplied WSDLs
to generate client stubs but may want to consider building additional client side
functionality on top of these generated stubs in order to efficiently use those web services.

This release of ContentServices for TeamSite does not use ContentServices Foundation.
Instead, ContentServices for TeamSite continues to use its own access service, as it did in
earlier versions.

ContentServices for TeamSite


ContentServices is language neutral and platform independent. Because it has a service-
oriented architecture, you can develop applications in almost any language or on any
platform (as long as the platform supports SOAP, the Simple Object Access Protocol).
These are some examples:

„ Java or J2EE applications that run on a web or application server, use TeamSite content,
and integrate some TeamSite functionality such as workflow or version control. This
type of application might be, for example, a corporate Intranet site with a TeamSite
mini-UI.
„ Microsoft .NET applications that use technologies such as ASP, Visual Basic, or C#, run
on an external host, and include some TeamSite content or features
„ Standalone desktop applications written in Java, C++, C#, or other languages that
integrate TeamSite features and use UI components built with a toolkit specific to the
language or platform, such as Java Swing or a Windows UI toolkit
„ Portals and portlets that run on a centralized portal server. Portlets are typically
developed using the portal vendor’s toolkit, but can use TeamSite functionality through
the ContentServices SDK.

For Java developers, the developer’s kit offers an easy-to-use Java interface and the choice
of local or remote communication with the TeamSite server. For developers working in
other languages, the SDK provides WSDL (Web Services Description Language) files that
can be used to generate client stubs. The stubs provide access for non-Java applications.

This guide describes how to use the ContentServices to build TeamSite client applications.
You might also be interested in the ContentServices UI Toolkit, which allows you to

10 ContentServices for TeamSite Cookbook


Architecture

customize the TeamSite server’s out-of-the-box user interface. Using Content Services for
TeamSite programmatically as described in this guide is a bit more involved, but also more
powerful.

Architecture
ContentServices for TeamSite has two basic modes. The first uses Java Native Interface (JNI)
as its transport, for local applications running on the same host as the TeamSite server.

The second mode uses SOAP to allow either local or remote applications to use the
ContentServices SDK and access the TeamSite server. Your application can use a single
setting in a properties file to indicate the transport, SOAP or JNI. Otherwise, the
ContentServices methods your application uses are the same.

ContentServices JNI
Applications that run on the same host as the TeamSite server (called local applications)
typically use ContentServices JNI for better performance. JNI allows Java code to work
with libraries written in other languages. The ContentServices JNI module is built directly
on top of the TeamSite server. Your application calls the ContentServices Java client
library, and the JNI module converts those calls for the internal TeamSite C++ library.

Java Calls
ContentServices
Local Java Applications
Java Client Interface

JNI Calls

ContentServices JNI Layer

Internal C++ Library

TeamSite Content Server

Figure 1: How ContentServices JNI Works

ContentServices SOAP
Remote applications use the service-oriented architecture of ContentServices SOAP. A
remote application functions as a web service client, sending automatically generated SOAP
requests to a web service built into ContentServices for TeamSite.

11
Overview

A web service is a software component with two main features. It is accessible through
SOAP, and it has a WSDL file that defines how clients access it. SOAP allows one
application to send an XML message to another application, regardless of language or
platform. This feature allows almost any application to use the ContentServices for
TeamSite.

Java or J2EE Applications Microsoft .NET Applications

Java Calls
Local Calls

Generated Client Stub


ContentServices
Java Client Interface Microsoft .NET Framework

SOAP SOAP

Web Server

FastCGI

SOAP Server ContentServices


Web Service

Internal C++ Library

TeamSite Content Server

The Java Client Interface


The simplest possible ContentServices for TeamSite application would establish
communication with the TeamSite server using ContentServices JNI or ContentServices
SOAP. This is very easy to do with the Java client interface.

12 ContentServices for TeamSite Cookbook


The Java Client Interface

com.interwoven.cssdk

access Defines users and how they access the TeamSite server

common Defines classes used across packages

factory Defines factories that create client objects

filesys Defines objects in the TeamSite filesystem

workflow Manages workflows and tasks

util Provides compatibility with ContentServices SDK 1.1

Figure 2: Packages in the ContentServices SDK Java Client Interface

The first step in any ContentServices for TeamSite Java application is creating a factory
object that determines how the application will communicate with the TeamSite server.
The factory object is specific to JNI, or specific to SOAP, or a generic object that reads the
transport type from a properties file.

Keeping things very simple, you might want to create a factory object and then say Hello,
World (a longer version of this example, with a properties file, is described in Chapter 3,
“Basics”).

13
Overview

Example 1: Creating a Factory Object

import com.interwoven.cssdk.factory.*;
import java.util.*;
import java.io.*;

public class CSHelloWorld {

public static void main(String[] args) {

CSFactory factory;
String name;

// read the factory type from a properties file


Properties props=new Properties();
try {
props.load(new FileInputStream("samples.properties"));
} catch ( FileNotFoundException fnf ) {
System.out.println( "The properties file was not found" );
} catch ( IOException io ) {
System.out.println( "Some type of I/O exception has occurred" );
}

// get the factory type we created


factory=CSFactory.getFactory(props);
name = factory.getClass().getName();

// display messages
System.out.println( "Factory of type " + name + " created" );
System.out.println( "Hello, World!" );
}
}

If you run this simple Java program on ContentServices SOAP, you will see this output:

Factory of type com.interwoven.cssdk.client.axis.common.AxisFactory created


Hello, World!

This shows that our sample application is using the ContentServices for TeamSite SDK. To
run this sample on ContentServices JNI, you would update the properties file at runtime,
with no need to update code.

14 ContentServices for TeamSite Cookbook


Behind the Scenes: SOAP and WSDL

Behind the Scenes: SOAP and WSDL


Suppose that you write a Java application that uses the SOAP transport. The Java client
interface packages your Java method calls into a SOAP message to send to the
ContentServices web service. The web service makes a call to the TeamSite server. The
TeamSite server returns a response to the SOAP server, which builds a SOAP response
message and returns it to your application.

The SOAP message has a body and an optional header. The ContentServices method calls
are packaged within the body.

SOAP Envelope

This entire structure is a SOAP message


SOAP Header

SOAP Body

SOAP Block The ContentServices method calls are


here, translated according to a WSDL file

Figure 3: Structure of a SOAP Message

When the SOAP message is created, the method calls are translated according to a
definition in a WSDL file. WSDL files define how a client calls a web service. The translated
WSDL call appears in the body of the SOAP message and is the same no matter what
language the application is written in.

The SOAP message is long, but starts like this:

<?xml version="1.0" encoding="UTF-8"?>


<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body> ...

The translated Java method call is part of the SOAP body.

The SOAP server receives the message and sends it to the C++ library and the TeamSite
server. The TeamSite server, when it receives the request, returns a response. The SOAP

15
Overview

server then packages the TeamSite response into a SOAP response and sends it back to your
client application.

Where to Go From Here


To start with simple Java command-line examples, move directly to the next chapter,
Chapter 3, “Basics.”

To get started extending or developing with the J2EE sample application, go to Chapter 6,
“Extending the Sample Application.”

To understand WSDL files and how to create a stub for the Java client interface so that you
can use C#, .NET, or other technologies, go to Appendix A, “Working with WSDL Files.”

To get detailed information about the classes and methods in the Java client interface, use
the ContentServices SDK Javadoc, available in the TeamSite server installation, on the
product CD, or from the download site.

16 ContentServices for TeamSite Cookbook


Chapter 2

Developer’s Overview

This chapter presents a brief overview of TeamSite as exposed by ContentServices for


TeamSite and some programming tips for developers.

TeamSite Overview
TeamSite is an Interwoven product that provides access to:
„ The Interwoven Content Server, a content repository and virtual file system.
„ Workflow capabilities, used to automate and control content creation.
„ TeamSite Templating, used to define, enter, and view structured content as forms.

The ContentCenter user interfaces, ContentCenter Standard and Professional, are browser
entry points into the web application that provides end user access to these and other
capabilities. Not all functionality that exists in the ContentCenter user interfaces, such as
their search and reporting capabilities, are exposed programmatically as APIs in
ContentServices for TeamSite.

Interwoven Content Server


ContentServices for TeamSite’s file system APIs provides access to the Interwoven
ContentServices. This content repository provides persistent stores for files containing
content and extended file attributes, with both versioning capabilities and the ability to
provide virtual copies of this file system to different users.

Each Interwoven file store partitions its content into areas, each of which is organized in a
directory structure that can be navigated as an ordinary file system.

Each workarea contains a virtual copy of that portion of the Interwoven file system. Each
virtual file copy is automatically replaced by an actual copy as needed. Workareas can be
provided for each user or shared by groups of users. Within a workarea, a file’s content can
be successively modified before being submitted.

Each group of related workareas has one staging area that contains the latest integrated
version of each file in that portion of the Interwoven file system. An integrated file version
reflects, successively, all past submissions of modified versions of that file from the staging
area’s related workareas.

17
Developer’s Overview

Submitting a file from a workarea logically copies the file from that workarea to the staging
area, updating its content and creating a new version. A modified file in a workarea is one
whose content has changed but which hasn’t yet been submitted to the staging area.
Updating a file in a workarea typically replaces it with the latest version currently in the
staging area.

A hole represents an absence of a file or directory. After deleting a file in a workarea, its hole
(with the same name) must be submitted to delete that file from the staging area.

An edition is a logical “snapshot” of the contents of a staging area at a given point in time.

A file’s extended attributes is the series of name-value pairs associated with that file, also
stored within the Interwoven file system but not visible through the directory structure.

TeamSite Workflows
A workflow or job process is used, for example, to assign work to a user or to implement a
review and approval process before submitting a modified file to the staging area.

A workflow consists of a series of tasks. A task can have a number of files attached to it,
allowing them to be part of an assignment or, after being edited, to be easily viewed by an
approver.

Each successive task in a workflow has a series of task comments associated with it, which can
be extended by users involved with that workflow’s execution. This allows users to specify,
for example, the content changes that were made or why a submission was not approved
and what further edits need to be done.

Each file attached to a task has its own comment series as well, allowing detailed
instructions or comments to be made on a per file basis.

Each workflow is a specific instantiation of a general workflow template. A workflow


template—a .wft file—describes all possible tasks, and the potential transitions between
them, that could occur in workflows instantiated from it.

Note: Do not confuse workflow templates with TeamSite Templating, described below.

Until a given workflow is done executing, its current status can be queried. After a
workflow is done executing, it can no longer be queried. In addition, all its comments (both
task comments and file comments) are no longer stored.

Even though it is possible to submit files from a workarea directly to the staging area, files
are typically submitted for approval by initiating a submit workflow. This workflow does the
actual submit to the staging area as part of its final task (assuming the reviewer actually
approves the content changes).

18 ContentServices for TeamSite Cookbook


Additional Concepts

A workflow can be designed to achieve many other effects as well, such as generating a
template output file when a given DCR is submitted.

TeamSite Templating
Structured data is represented by a series of data content record files or DCRs. Structured data
is captured by filling out forms or data capture templates. Each set of related DCRs is
associated with a different data type. These are organized into a hierarchy of data categories
and data types, which can be browsed by end users.

For a given data type and DCR, different presentation templates will generate different
formatted output files, which can be previewed. Each template output file contains, in its
extended attributes, the name of the DCR and presentation template from which it was
generated. Similarly, each DCR contains its data type in its extended attributes.

TeamSite Roles
TeamSite users also have one or more roles assigned to them. A user acting as a given role
may be prevented from doing certain TeamSite operations available to other roles. In
increasing order of capability, the standard TeamSite roles are Author, Editor,
Administrator, and Master.

Additional Concepts
The following sections describe more advanced features of the Interwoven file system. You
may wish to return to this section after studying the file system package Javadoc.

Specifying VPaths
An Interwoven file system consists of a default store (multiple stores are supported in
TeamSite 5.5 and later), each subdivided into one or more branches, each possibly subdivided
into sub-branches. Each branch has its own staging area, zero or more workareas, and a
series of editions.

The path describing a workarea is its workarea VPath. The path describing a file’s location
within an area is its area relative path. Combined together, a file’s full VPath describes its
precise location in the Interwoven file system.

A vpath (“version path”) is a path within the TeamSite content repository, specified as one
of the following:

/store/branch+/EDITION/edition
/store/branch+/WORKAREA/area/directory*/file
/store/branch+/STAGING/directory*/file

where “+” indicates 1 or more; * indicates 0 or more, and a path may omit the elements
below it in order to specify just a directory, area, branch, or store.

19
Developer’s Overview

A branch may not be named EDITION, WORKAREA, or STAGING. STAGING is a special area
that every branch has. Thus, a URL command parameter that is an area requires either a
workarea (specified as WORKAREA/workareaname) or STAGING.

The following are all valid vpath specifications:

„ /default, a
store.
„ /default/main, the branch main.
„ /default/main/pubs, the branch pubs.
„ /default/main/pubs/EDITION/initial, the edition initial.
„ /default/main/pubs/STAGING, the STAGING area for the pubs branch.
„ /default/main/pubs/WORKAREA/uitk, the workarea uitk.
„ /default/main/pubs/WORKAREA/uitk/guide/examples, a directory.
„ /default/main/pubs/WORKAREA/uitk/guide/examples/example1, a file.
„ /default/main/pubs/WORKAREA/uitk/README, a file directly under a workarea.

The path delimiter can be either “/” or “\” when specifying a TeamSite path, but will be
output as: “/” (Unix) or “\” (Windows).

Optionally, a vpath can include the server name by prepending //servername to it, though
doing so is generally not needed.

For more information on specifying a vpath, see the TeamSite Command-Line Tools manual.

Versions and Version Conflicts

A version conflict occurs when a modified file in a workarea is out of date with respect to the
integrated version of that file in the staging area, due to a submission of an equivalent file
(with the same area relative path) from a different workarea associated with the same
staging area.

A file’s version conflict can be resolved either by overwriting the version in the staging area
with the version in the workarea or by overwriting the version in the workarea with the
version from the staging area.

The content of two files in version conflict may or may not be in conflict in the sense of being
able to trivially merge their content differences (in certain circumstances their content
could be identical).

Content merging, if performed, is a client side operation. A client application can read the
content of a modified file in a workarea, update that file by overwriting it with the latest
version from the staging area, read the latest version of the file, perform the content merge
(typically relying on user input for decisions that arise), write the file’s newly merged
content, and then submit that file normally.

20 ContentServices for TeamSite Cookbook


Additional Concepts

Locks
A lock is placed on a file in a workarea and establishes a privileged status for that particular
file with respect to all equivalent files located in different workareas (i.e., with respect to
those files with the same area relative paths in workareas associated with this staging area).

These files may be viewed but can neither be edited nor submitted to the staging area until
either the lock is released or the locked file itself is submitted to the staging area. A lock on a
file is automatically released when that file is submitted (no client side operation is needed).

Potential version conflicts can be avoided if all users always lock and then get the latest
version of a file from the staging area before opening files for modification.

While this avoids versioning conflicts and the need to possibly merge content, end users
may encounter lock conflicts instead, when a file is unavailable for editing due to an
outstanding lock. However, if end users are informed who holds a lock when a lock conflict
occurs, the end user locked out can request (via e-mail or other means) that the user with
the lock either submits the modified file or releases its lock.

Note: Simply releasing the lock in this case creates a potential version conflict. To avoid
this, combine releasing the lock with undoing the unsubmitted changes to the
released file.

Locking Models
When a TeamSite branch is first created, its locking model is specified. There are three
branch locking models supported by TeamSite:
„ Submit locking—if a file is locked, only users within the workarea where it is locked
may submit the file to the staging area. Users within other workareas are still allowed to
edit their copies of this locked file but may not submit any of them until the user who
holds the lock either submits their version of the file or releases the lock upon it.
„ Optional write locking—if a file is locked, only users within the workarea where it is
locked may edit (or submit) the file to the staging area. Users within other workareas
are still allowed to view their copies of this locked file but may not open them for
editing (or submit them) until the user who holds the lock either submits their version
of the file or releases the lock upon it.
„ Mandatory write locking—a file must be locked before it can be edited. Once locked,
users within other workareas can view their copies of this file but may not open them
for editing (or submit them) until the user who holds the lock either submits their
version of the file or releases the lock upon it.

Submit locking is the default and least restrictive locking model. If a file is not locked under
either submit locking or optional write locking, then different copies of the same file can be
freely edited in different workareas, resulting in versions that are in conflict once one copy
has been submitted and then an attempt is made to submit another copy. Within the
ContentCenter GUIs, the merge tool then appears to allow a user to resolve any conflicts in
the actual content of the conflicting files before resolving the version conflict.

21
Developer’s Overview

Programming Tips
Programming to ContentServices for TeamSite poses challenges similar to programming to
any client-server architecture:
„ Minimize the number of calls from your client application to the TeamSite server.
Client to server calls (“across the wire”) are much more expensive than other calls that
your application program will make.
„ Avoid stale data. While caching data can reduce the need to make extra calls to the
server, it can occasionally result in an incomplete or inaccurate view of the TeamSite
server’s state. When it is important that the state be accurate, refresh your cached data.
ContentServices provides methods to do so.
„ Minimize end-user waiting (latency) when transferring a large file or list, by breaking it
into smaller chunks or using an iterator. ContentServices for TeamSite provides
methods for breaking a file stream into chunks and to iterate over collections of objects.
Use them.
„ Don’t transfer huge amounts of data that you don’t use. This is often the biggest cause
of poor client application performance. ContentServices for TeamSite provides
numerous methods that return only a “skeletal” object, not a fully fleshed out object
with all its members populated. If you’re only using an object to navigate to another
object (say, from a branch to one of its workareas), then request only the skeletal object.
Similarly, whenever possible, filter collections of objects on the server side, before
transferring the objects you need to the client application.

22 ContentServices for TeamSite Cookbook


Part I: Getting Started

23
24 ContentServices for TeamSite Cookbook
Chapter 3

Basics

Introduction
To start building ContentServices SDK applications, you need to learn certain basic tasks.
The first and most basic is how to create a factory object, which determines whether your
application uses ContentServices JNI or ContentServices SOAP (this chapter presents more
detail than the Overview chapter). This task is part of building any ContentServices SDK
application.

Of course, all applications exist for users. The second basic task you need to learn is how to
accept login values (a user name, password, and role) and use them to authenticate a user on
the TeamSite server.

Creating a Factory Object

Task
You need to create a factory object as the first step in building a ContentServices SDK
application. You know whether you want to use ContentServices JNI or ContentServices
SOAP, although this can be configured at runtime.

Solution
Use a generic CSFactory.getClient method and configure the settings for JNI or SOAP in
a properties file that is read at runtime.

Examples
CSMoreHelloWorld.java
Usage:
java CSMoreHelloWorld

Discussion
The first step in any ContentServices SDK application is creating a factory object. The
factory object is an instance of com.interwoven.cssdk.factory.CSFactory or one of its
subclasses, CSLocalFactory or CSSOAPFactory, and determines how your application will
communicate with the TeamSite server.

25
Basics

Because you want to configure the transport (SOAP or JNI) at runtime, create a properties
file first. The next example shows a minimal properties file, with settings for both JNI and
SOAP, but presently set for SOAP (as those lines are uncommented).

Example 1: A Samples Properties File (samples.properties)

# creates a CS JNI factory


# com.interwoven.cssdk.factory.CSFactory=com.interwoven.cssdk.factory.
# CSLocalFactory
# cssdk.cfg.path=c:/iw-home/cssdk/cssdk.cfg

# creates a CS SOAP factory


com.interwoven.cssdk.factory.CSFactory=com.interwoven.cssdk.factory.CSSOA
PFactory
# use the machine name and HTTP port of the TeamSite server
serviceBaseURL=http://mteverest:90

For JNI, set com.interwoven.cssdk.factory.CSFactory to the fully qualified


CSLocalFactory name and cssdk.cfg.path to the location of cssdk.cfg on the TeamSite
host (remember that a ContentServices JNI application runs locally, on the same host as
TeamSite).

To summarize, these are the JNI properties:

Property Value
com.interwoven.cssdk.factory. com.interwoven.cssdk.factory.
CSFactory CSLocalFactory
cssdk.cfg.path Location of the cssdk.cfg file
data.cache.timeoutms Number of milliseconds until data cache timeout.
Default is -1, meaning never time out. A JVM-wide
property affecting the way all CS SDK objects in
the same class loader behave.

For SOAP, set com.interwoven.cssdk.factory.CSFactory to the fully qualified


CSSOAPFactory name and serviceBaseURL to the base URL of the TeamSite server. The
base URL is http://, followed by machineName:httpPort. These are the required
properties for SOAP.

You can also add any of these SOAP factory properties:

Property Value
com.interwoven.cssdk.factory. com.interwoven.cssdk.factory.
CSFactory CSSOAPFactory
serviceBaseURL The base URL of the ContentServices SOAP
server:
http[s]://host:port

26 ContentServices for TeamSite Cookbook


Creating a Factory Object

accessBaseURL The base URL of the ContentServices SDK


access service, if different from
serviceBaseURL:

http[s]://host:port
data.cache.timeoutms Number of milliseconds until data cache
timeout. Default is -1, meaning never time out.
A JVM-wide property affecting the way all
ContentServices SDK objects in the same class
loader behave.
keystore.location The keystore location. Required if you use SSL
access over HTTPS.

27
Basics

Once you have written the properties file, you can use it to create a generic factory object.

Example 2: Creating a Generic Factory Object (CSMoreHelloWorld.java)

import com.interwoven.cssdk.factory.*;
import com.interwoven.cssdk.common.*;
import java.util.*;
import java.io.*;

public class CSMoreHelloWorld {

public static void main(String[] args) {

CSFactory factory;
String name;
CSVersion version = null;
int major;
int minor;

// read the factory type from a properties file


Properties props=new Properties();
try {
props.load(new FileInputStream("samples.properties"));
} catch ( FileNotFoundException fnf ) {
System.out.println( "The properties file was not found" );
} catch ( IOException io ) {
System.out.println( "Some type of I/O exception has occurred" );
}

// get the factory


factory=CSFactory.getFactory(props);
name = factory.getClass().getName();

// get the ContentServices SDK version number


try {
version = factory.getServerVersion();
major = version.getMajorNumber();
minor = version.getMinorNumber();
// display messages
System.out.println( "Factory of type " + name + " created" );
System.out.println( "Running on ContentServices SDK version "
+ major + "." + minor );
System.out.println( "Hello, World" );

} catch ( CSException e ) {
System.out.println( "An exception occurred" );
e.printStackTrace();
}
}
}

When you run this sample, you see this output:

28 ContentServices for TeamSite Cookbook


Creating a Client Object

Factory of type com.interwoven.cssdk.client.axis.common.AxisFactory create


Running on ContentServices SDK version 2.0

Hello, World

From the output, you know that CSMoreHelloWorld is communicating with the
ContentServices SDK using SOAP (as indicated by AxisFactory).

See Also
„ “Creating a Client Object” on page 29” to learn how to make your application start
communicating with the TeamSite server
„ “Creating a Factory Object” on page 68” to see how the factory object is created in the
J2EE sample application

Creating a Client Object

Task
Now that you have a factory object, you want to create a client object to begin
communicating with the TeamSite server.

Solution
Use the factory object to create a client object using one of the forms of getClient. Then,
use the client object getClient returns to retrieve objects from the TeamSite filesystem.

Example
CreateClient.java
Usage:
java CreateClient username password role

Discussion
The client object represents the user’s session on the TeamSite server. The server returns
the client object if it can authenticate the user with the credentials the user supplies
(typically, a username, password, and role).

If creating a factory object is the first coding step in a ContentServices SDK application,
creating a client object is the second. Once you have the client object, you use it to retrieve
branches, workareas, files, workflows, or anything else relating to the user. You also use it
to end the user’s session.

29
Basics

The factory package has two basic forms of getClient. The getClient method used
most often takes a username, role, and password to identify the user, along with a locale,
application context string, and server name:

public CSClient getClient( String name,


String role,
String password,
String locale,
String appContext,
String serverName)
throws CSAuthenticationException,
CSRemoteException,
CSInvalidRoleException,
CSException

To use this form of getClient in your application, you would request a username,
password, and role from your user.

Example 3: Creating a Client Object with User Name, Password, and Role

// create a factory object first


.
.
try {
client = factory.getClient( username, role,
password,
Locale.getDefault(),
"mydemo", null );
System.out.println( "Client object obtained" );
}

The other form of getClient takes a session string to identify the user, along with the three
other items:

public CSClient getClient(String sessionString,


Locale locale,
String appContext,
String server)
throws CSInvalidSessionStringException,
CSExpiredSessionException,
CSInvalidRoleException,
CSRemoteException,
CSException

Use this form of getClient when the user has already been authenticated and has a valid
TeamSite session.

See Also
„ “Creating a Factory Object” on page 25” to see how to create a factory object.

30 ContentServices for TeamSite Cookbook


Chapter 4

Files, Directories, and Workareas

Introduction
In the ContentServices SDK, all files are subtypes of CSFile. The most common file type is
CSSimpleFile, which represents any file that has content and is stored at a specific vpath
(this is TeamSite terminology; short for version path). Files also include directories,
symbolic links, and holes.

com.interwoven.cssdk.filesys
CSFile CSDir

CSSimpleFile

CSSymlink

CSHole

...

Files are stored in workareas and have both a vpath, represented by CSVPath, and an area
relative path, represented by CSAreaRelativePath. A vpath starts with a leading slash,
followed by the name of a store, then the name main, with optional extra information
before and after. These are all valid vpaths:
/default/main/web/WORKAREA/demo
//everest/default/main/web/WORKAREA/demo
/default/main
/default/main/STAGING

The file’s area relative path is the part of the path after WORKAREA, STAGING, or EDITION and
is available for operations you perform within an area. For the first two vpaths listed above,
the area relative path is demo.

31
Files, Directories, and Workareas

Files have both attributes and content. Attributes contain information about the file, such as
the file’s name, size, last modification date, and so on. You can see the type of attributes you
can retrieve by looking at the getter methods defined in CSFile:

getArea getAttributeModificationDate
getCommonPredecessor getContentModificationDate
getFileRevision getFileRevisionHistory
getLastModifier getLockArea
getLockAreaVPath getLockComment
getLockCreationDate getLockCreator
getLockOwner getName
getPermissions getPredecessors
getRelatedTaskIds getRevisionBranch
getRevisionComment getRevisionNumber
getRevisionString getSubmitRecord
getSuccessors

Once you display the attributes in your application, you can provide a link, icon, or other
mechanism a user clicks to view or edit the file content. Your application can then read an
individual file’s content with CSSimpleFile.read or CSSimpleFile.getInputStream.

A workarea contains files and directories and is contained within a branch. The workarea is
an object that implements CSWorkarea, which inherits from CSArea.

CSCacheableObject

CSArea CSWorkarea

CSNode

A workarea can be updated at any time from the staging area, an edition, or another
workarea. A user can also edit files in a workarea and then submit them to staging, either
directly or for workflow approval.

Workareas always have access rights. The workarea’s owner (of type CSUser) can always
make changes in a workarea. Other users can make changes if the workarea was created
with group access and the users belong to the group. For example, this command creates a
workarea named demo, owned by the user bob, but granting access to any user in the group
webdev:

iwmkwa main/web demo 'comment' INITIAL bob webdev

32 ContentServices for TeamSite Cookbook


Creating and Deleting Workareas

The tasks you typically want to perform with workareas are displaying a list of files in
workarea’s root directory, displaying all files and directories in the workarea, and
submitting a file directly from the workarea to staging.

Creating and Deleting Workareas

Task
You want to create or delete a workarea in the TeamSite filesystem from your application, in
response to some input a user has entered.

Solution
To create a workarea, use the client object to get the branch where the workarea will be
created. Then, from the branch, use createWorkarea.

Deleting a workarea is easy. From the client object, get the workarea. Then, from the
workarea, call the delete method.

Examples
CreateWorkarea.java
Usage:
java CreateWorkarea username password role branch-vpath wa-name group

DeleteWorkarea.java
Usage:
java DeleteWorkarea username password role wa-vpath

Discussion
Remember to always create a workarea from a branch.

When you create a workarea, you must specify CSUser and CSGroup objects as arguments
to createWorkarea. The CSUser is the workarea owner, and the CSGroup is a group that
has access to the workarea.

You are allowed to enter null for either. If you enter null for CSUser, the workarea is
owned by the current session user (specified in the client object). A null value for CSGroup
means that the workarea is private and not shared with a group.

createWorkarea also requires an edition on which the workarea is based. Editions are
readily available from the getBaseEdition, getFirstEdition, and getLastEdition
methods.

Example 4: Creating a Shared Workarea (CreateWorkarea.java)

33
Files, Directories, and Workareas

try {
System.out.println( "Getting client with username " + username
+ ",
password " + password + ", and role " + role );
client = factory.getClient( username, role,
password, Locale.getDefault(),
"mydemo", null );

System.out.println( "Client object obtained" );

CSVPath branchVPath = new CSVPath( branchName );


CSBranch branch = client.getBranch( branchVPath, false );

// get a group for workarea access


// false means a shallow object is returned
CSGroup group = client.getGroup( groupName, false );

// create the workarea based on the most recent edition


CSEdition mostRecent = branch.getLastEdition();

// create the workarea


// null means owned by the current user
// accessible by the group
// and based on the most recent edition
CSWorkarea wa = branch.createWorkarea( waName, null, group,
"my new workarea", mostRecent );

} catch ( CSException e ) {
System.out.println( "An exception occurred" );
e.printStackTrace();
}

When deleting a workarea, first use CSClient.getWorkarea to retrieve the workarea with
a vpath. getWorkarea (like many methods in CSClient) uses a Boolean validate
parameter that determines whether the vpath is validated when the workarea is retrieved.

Example 5: Deleting a Workarea (DeleteWorkarea.java)

34 ContentServices for TeamSite Cookbook


Renaming a Workarea

try {
System.out.println( "Getting client with username " + username + ",
password " + password + ", and role " + role );
client = factory.getClient( username, role,
password, Locale.getDefault(),
"mydemo", null );
System.out.println( "Client object obtained" );

CSVPath waVPath = new CSVPath( waName );

// false means a shallow object is returned


CSWorkarea wa = client.getWorkarea( waVPath, false );
System.out.println( "About to delete " + waName );
wa.delete();

} catch ( CSException e ) {
System.out.println( "An exception occurred" );
e.printStackTrace();
}

See Also
„ “Renaming a Workarea” on page 35 to see how to change a workarea’s name
„ “Accessing Workarea Properties” on page 36 to display information such as the
workarea name or creator

Renaming a Workarea

Task
You want to rename a workarea, leaving it in the same branch.

Solution
Get the client object, then call getWorkarea from it to get the workarea. From the
workarea, use CSWorkarea.rename. The new workarea name must be unique in the branch,
or the TeamSite server throws a CSObjectAlreadyExistsException.

Example
RenameWorkarea.java
Usage:
java RenameWorkarea username password role old-wa-vpath new-wa-name

Discussion
Renaming a workarea is easy and uses the same pattern as deleting a workarea. You need the
vpath of the existing workarea (to create a CSVPath object) and a String for the new name.
Example 6: Renaming a Workarea (RenameWorkarea.java)

35
Files, Directories, and Workareas

try {
System.out.println( "Getting client with username " + username + ",
password " + password + ", and role " + role );
client = factory.getClient( username, role,
password, Locale.getDefault(),
"mydemo", null );

System.out.println( "Client object obtained" );

CSVPath waVPath = new CSVPath( oldVPath );

// false means a shallow object is returned


CSWorkarea wa = client.getWorkarea( waVPath, false );
System.out.println( "About to rename " + oldVPath );
wa.rename( newName );

} catch ( CSException e ) {
System.out.println( "An exception occurred" );
System.out.println( "The workarea was not renamed" );
e.printStackTrace();
}

See Also
„ “Creating and Deleting Workareas” on page 33 to see how to delete a workarea

Accessing Workarea Properties

Task
You want to display information about the workarea, such as the creator, creation date, or
description, or you want to check if the current user has write access.

Solution
Obtain the factory object, then the client object, as usual. Use the client object with a
CSVPath (converting a String to a CSVPath, if necessary) to get the workarea, a
CSWorkarea object. Then, use the methods in CSArea to get information about the
workarea.

Example
GetWorkareaInfo.java
Usage:
java GetWorkareaInfo username password role wa-vpath

Discussion
Once you have the client object, use getWorkarea to return the workarea. getWorkarea
takes two arguments and has this signature:

36 ContentServices for TeamSite Cookbook


Accessing Workarea Properties

public CSWorkarea getWorkarea(CSVPath path,


boolean validate)
throws CSAuthorizationException,
CSExpiredSessionException,
CSRemoteException,
CSException

Many of the methods in CSClient take a validate argument. The validate argument
specifies whether the object should be validated before it is returned.

If validate is true, the vpath is validated when the workarea is returned, and if the vpath
does not exist, getWorkarea returns null. If validate is false, the vpath is not validated.
If the vpath does not exist, getWorkarea returns a shallow object that is not null. When
you call a method such as getName from the shallow object, the getter method returns an
exception.

Example 7: Getting a Workarea Without Validating (GetWorkareaInfo.java)

try {
System.out.println( "Getting client with username " + username +
", password " + password + ", and role " + role );
client = factory.getClient( username, role,
password, Locale.getDefault(),
"mydemo", null );
System.out.println( "Client object obtained" );

CSVPath vpath = new CSVPath( path );


// we use false here to avoid a null return value
CSWorkarea wa = client.getWorkarea( vpath, false );

Once you have the workarea, use the getter methods in CSArea to get information about it.

Example 8: Getting Information About the Workarea (GetWorkareaInfo.java)

String waName = wa.getName();


String owner = wa.getCreator().getName();
Date date = wa.getCreationDate();
String description = wa.getDescription();
boolean canWrite = wa.isWritable();

System.out.println( "Here's the workarea info" );


System.out.println( waName + "\t" + owner + "\t" + date + "\t"
+ description + "\t" );
System.out.println( "isWritable returns " + canWrite );

The isWritable method refers to the user authenticated in the client object. When you
run GetWorkareaInfo, it displays workarea information something like this:

37
Files, Directories, and Workareas

Here's the workarea info


demo2 INTERWOVEN\saahmed Wed Sep 17 15:36:44 PDT 2003
'comment'

isWritable returns true

Displaying Files in a Workarea

Task
You want to retrieve file attributes from a user’s workarea and display a file list.

Solution
Use one of the forms of CSArea.getFiles. The getFiles method retrieves the file
attributes and returns a CSIterator.

You can then iterate through the returned files, using the getter methods in CSFile to
display the file name, size, and other attributes. The actual display is defined by the type of
application you are writing. The example in this task displays file attributes in a command
window.

Example
GetWorkarea.java
Usage:
java GetWorkarea username password role wa-vpath

Discussion
The getFiles method has two forms, a short form and a long one. Use the short form
when you have a specific list of area relative paths and want to return just those files:
public CSFile[] getFiles(CSAreaRelativePath[] filePaths)

Use the long form when you want to return all the files in the root directory of a workarea or
specify some that should be filtered and not returned:

public CSIterator getFiles(int fileTypes,


CSSortKey[] sortKeys,
int fileTypesForNameRegex,
java.lang.String nameRegex,
int offset,

int maxElements)

38 ContentServices for TeamSite Cookbook


Displaying Files in a Workarea

The CSIterator object returned by the long form works like a standard Java iterator, with
hasNext() and other methods.

Example 9: Getting the Files in the Root of the Workarea (GetWorkarea.java)

// path is a command-line argument the user enters

CSVPath waPath = new CSVPath ( path );


System.out.println( "Getting workarea with " + path );
CSWorkarea wa = client.getWorkarea(waPath, false);

CSSortKey[] sortArray = new CSSortKey[1];


sortArray[0] = new CSSortKey(CSSortKey.NAME, true);

Iterator i = wa.getFiles( CSFileKindMask.ALLNONHOLES,


sortArray,
CSFileKindMask.ALLNONHOLES,
null,
0,
-1);

Then, use the getter methods defined in CSFile to retrieve, and display various attributes
like file name, size, last modifier, and last modification date.

Example 10: Then, Displaying Them (GetWorkarea.java)

// iterate through the files


// for each file ..
while (i.hasNext()) {
CSFile file = (CSFile) i.next();
// get each file's kind
long fsize = 0;
// if it's a simple file, get its size
if (file.getKind() == CSSimpleFile.KIND) {
fsize = ((CSSimpleFile) file).getSize();
}

// get the name, last modifier, and lastModDate


String name = file.getName();
String lastModifier = file.getLastModifier().getName();
String modDate = file.getContentModificationDate().toString();

// and display the file's info


// we use the file name instead of the vpath here
System.out.println(name + "\t" + modDate + "\t" + lastModifier + "\t"
+ fsize);
}

The displayed files (from the root of the workarea, displayed in order by name) look like
this:

39
Files, Directories, and Workareas

new.txt Wed Sep 17 14:46:40 PDT 2003INTERWOVEN\saahmed17


Report-Cosmetics-Canada.docSun Mar 16 18:47:22 PST 2003INTERWOVEN\saahmed
117760
Research-Chemicals-Canada.docSun Mar 16 18:49:34 PST 2003INTERWOVEN\saahmed
122880
Research-Telecom-Canada.docSun Mar 16 18:43:04 PST 2003INTERWOVEN\saahmed
118784
Research-Telecom-MSO-US.docSun Mar 16 18:54:06 PST 2003INTERWOVEN\saahmed
120320
Research-Thailand.docSun Mar 16 18:59:12 PST 2003INTERWOVEN\saahmed
115200

See Also
„ “Filtering the File List” on page 40 if you want to display only some files in the workarea
„ “Retrieving a User’s Workarea” on page 79 to see how a user’s workarea is displayed
using JSP and the JSP Standard Tag Library (JSTL) in the J2EE sample application

Filtering the File List

Task
You want to list only some files in a user’s workarea.

Solution
You need to know the name of the workarea you want to retrieve. In the samples used in this
task, you specify the workarea name on the command line.

Example
GetWorkareaWithRegex.java
Usage:
java GetWorkarea username password role wa-vpath

Discussion
Once you have the workarea name, you can retrieve the file attributes with
CSArea.getFiles. If you want to filter and list only a subset of files in the workarea, you
need to use the long form of getFiles:

40 ContentServices for TeamSite Cookbook


Filtering the File List

public CSIterator getFiles(int fileTypes,


CSSortKey[] sortKeys,
int fileTypesForNameRegex,
String nameRegex,
int offset,
int maxElements)
throws CSAuthorizationException,
CSObjectNotFoundException,
CSExpiredSessionException,
CSRemoteException,
CSException

The getFiles method filters twice when it returns files, using a combination of
fileTypes, fileTypesForNameRegex, and nameRegex. Both fileTypes and
fileTypesForNameRegex take constants defined in CSFileKindMask that define a group of
files, such as ALLTYPES, DIR, SIMPLEFILE, and so on.

The first filter finds the large group of files that matches fileTypes. From this group, the
second filter finds the small group that matches fileTypesForNameRegex and applies the
regular expression to them. This group can be the same as or smaller than the fileTypes
group. The regular expression applies only to the files in this list.

getFiles returns attributes for:

„ All files in fileTypes that aren’t part of the fileTypesForNameRegex group


„ The files in the fileTypesForNameRegex group that match the regular expression in
nameRegex

The regular expression in nameRegex is Perl-compatible. You need to write it according to


the rules at www.pcre.org.

The files are sorted according to the value of sortKeys, by name, owner, size, or other
values, in ascending or descending order.

A simple example (from GetWorkareaBean in the J2EE sample application) would return
all files in a workarea except holes.

Example 11: Returning All Files Except Holes

Iterator i = wa.getFiles( CSFileKindMask.ALLNONHOLES,


null,
CSFileKindMask.ALLNONHOLES,
"*",
0,
-1);

41
Files, Directories, and Workareas

Another example might return attributes for all files in the root of the workarea that end in
.doc.

Example 12: Returning All Simple Files That End in .doc


(GetWorkareaWithRegex.java)

CSVPath waPath = new CSVPath ( path );


System.out.println( "Getting workarea with " + path );
CSWorkarea wa = client.getWorkarea(waPath, false);

CSSortKey[] sortArray = new CSSortKey[1];


sortArray[0] = new CSSortKey(CSSortKey.NAME, true);

// get all simple files in the workarea ending with .doc

Iterator i = wa.getFiles( CSFileKindMask.SIMPLEFILE |


CSFileKindMask.DIR,
sortArray,
CSFileKindMask.SIMPLEFILE,
"\\.doc$",
0,
-1);

The getFiles method in Example 12 on page 42 returns only simple files and directories.
It would apply the regular expression to the simple files and return only those that match
(that is, all files ending in .doc). It would also return all directories, without applying the
regular expression.

Suppose the workarea contains these files:

The getFiles method in Example 12 on page 42 would return just the files ending in .doc.
Even more, because sortArray uses CSSortKey.NAME and true, the files are returned in
ascending order by file name.

42 ContentServices for TeamSite Cookbook


Reading and Writing Entire Files

Report-Cosmetics-Canada.doc Sun Mar 16 18:47:22 PST 2003


INTERWOVEN\jsmith117760
Research-Chemicals-Canada.doc Sun Mar 16 18:49:34 PST 2003
INTERWOVEN\jsmith122880
Research-Telecom-Canada.doc Sun Mar 16 18:43:04 PST 2003
INTERWOVEN\jsmith118784
Research-Telecom-MSO-US.doc Sun Mar 16 18:54:06 PST 2003
INTERWOVEN\jsmith120320
Research-Thailand.doc Sun Mar 16 18:59:12 PST 2003
INTERWOVEN\jsmith115200

See Also
„ “Reading and Writing Entire Files” on page 43 to see how to read a file’s content
„ “Displaying Files in a Workarea” on page 38 to learn how to retrieve and display
attributes for all files in the root of the workarea

Reading and Writing Entire Files

Task
You want to read a file from the TeamSite server and copy it to another location, such as an
external filesystem for a user to edit.

Solution
Reading a file reads its content, not its attributes (remember that getFiles retrieves
attributes, not content). Bringing content from an external source (the TeamSite server)
and sending it to an external destination (your user’s filesystem) uses input and output
streams. The methods to use are getInputStream and getOutputStream in
CSSimpleFile.

Example
FileDownloadServlet.java
(in the J2EE sample application)

Discussion
Reading and writing file streams reads the entire file. Whether you are reading a stream or
writing a stream, the technique is almost the same:
„ Open a stream
„ As long as there is more information, read it or write it
„ Close the stream

43
Files, Directories, and Workareas

The getInputStream and getOutputStream methods in CSSimpleFile are similar to


those in the JDK, except that they both take boolean arguments to specify whether you
want the stream to be thread safe:

public java.io.InputStream getInputStream(boolean threadSafe)


public java.io.OutputStream getOutputStream(boolean threadSafe)

First, let’s look at an example of using getInputStream to read a file’s content from the
TeamSite server, through the ContentServices SDK, to your client application. Typically, a
user will download a file from your client application to a local directory for editing, either
explicitly or implicitly through a user interface.

This example comes from FileDownloadServlet in the J2EE sample application. This
servlet causes the browser to display a dialog box, which the user can use to open or
download the file. The browser does part of the work, so this example doesn’t need to use
an output stream.

The basic technique for reading files is to call getFile with a CSVPath, then use the
returned CSSimpleFile to get the file’s input stream.

Example 13: Reading a File (FileDownloadServlet.java)

public static void returnFile( CSVPath vpath,


CSClient client,
OutputStream out )
throws FileNotFoundException, IOException {

InputStream in = null;

try {
// use the csvpath to get the file
CSSimpleFile f = (CSSimpleFile) client.getFile( vpath );

// a true argument to getInputStream makes it thread safe


in = new BufferedInputStream( f.getInputStream(true) );

// do the buffering
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
out.write(buf, 0, bytesRead);
}
// catch any exceptions
catch (CSException e) {
throw new CSWebAppException(e);
}
// and clean up
finally {
if (in != null) in.close();
}
}

44 ContentServices for TeamSite Cookbook


Creating and Deleting Files and Directories

Writing a file copies updated content from a local directory, through your application, then
through the ContentServices SDK, to a workarea on the TeamSite server. (Remember that
it needs to be submitted to staging to be available to users who don’t have access to the
workarea.)

See Also
„ “Filtering the File List” on page 40 to see how to retrieve and display file attributes

Creating and Deleting Files and Directories

Task
Your application needs to create or delete a file or directory in a workarea, in response to
user input.

Solution
It is easy to create files and directories in a workarea with CSWorkarea.createDirectory
or CSWorkarea.createSimpleFile methods. You can delete a file or directory from a
workarea with CSFile.delete. If the file has been submitted to staging, you also need to
submit its hole to delete the file from staging.

Examples
CreateFile.java
Usage:
java CreateFile username password role wa-vpath file-area-rel-path

DeleteFile.java
Usage:
java DeleteFile username password role vpath

Discussion
Once you have the client object, you can use it to get the workarea. Then, from the
workarea, call createDirectory and createSimpleFile. In this example, the directory
and file names created are hard-coded.

In your application, however, you will want to provide a mechanism for users to enter or
choose a file or directory name to create. When you receive the file or directory name from

45
Files, Directories, and Workareas

the user, convert it to a CSAreaRelativePath object. In Example 14 on page 46, the area
relative path is within the demo workarea you created during the samples setup.

Example 14: Creating Files and Directories (CreateFile.java)

// get the workarea


System.out.println( "Getting the workarea at " + path );
CSVPath waPath = new CSVPath( path );
CSWorkarea wa = client.getWorkarea(waPath, false);

// convert the file path to an area-rel-path


CSAreaRelativePath fileAreaRelPath = new CSAreaRelativePath( filePath );

// create the file


// the user must be authorized to create files in the workarea
System.out.println( "Creating the file " + fileAreaRelPath );
wa.createSimpleFile( fileAreaRelPath );

Deleting files is a similar process. You get the area relative paths as strings from your user;
convert them to CSAreaRelativePath objects and build an array; use the array with the
short form of getFiles to get an array of CSFile objects; then, delete each file in the array
with CSFile.delete.

Example 15: Deleting Files and Directories (DeleteFile.java)

CSVPath vpath = new CSVPath( path );


CSFile file = client.getFile( vpath );
System.out.println( "About to delete " + path);
file.delete();

The easiest way to test this example is to run CreateFile, without submitting the file to
staging, then DeleteFile to delete it from the workarea.

See Also
„ “Filtering the File List” on page 40 to see how to use the long form of getFiles

Writing to a File

Task
You want to write something to a specific point in a file, either an arbitrary string or a user’s
edit. You want to lock the file before you write to it and unlock it after.

46 ContentServices for TeamSite Cookbook


Writing to a File

Solution
The file you write to must be a simple file, not a directory, symbolic link, or hole. First,
lock the file with CSFile.lock; then, write some edits to it with CSSimpleFile.write.
When you are done, unlock it with CSSimpleFile.unlock and end the user’s TeamSite
session.

Example
WriteToFile.java (run CreateFile first to create an empty file)
Usage:
java CreateFile username password role wa-vpath file-area-rel-path
java WriteToFile username password role source-path target-vpath

You can use comment.txt (in the same directory as WriteToFile) as source-path.

Discussion
Use CSSimpleFile.write when you want to place some edits at a certain point in a file.
The write method has this signature:

public void write(byte[] fileContents,


long offset,
int numBytes,
boolean truncate)
throws CSAuthorizationException,
CSObjectNotFoundException,
CSReadOnlyFileSystemException,
CSRemoteException,
CSUnsupportedOpException,
CSExpiredSessionException,
CSException

This method asks you to write an array of bytes to the file, starting a specific point and
extending for a specific length. You can also choose whether to truncate the file’s existing
content after the write.

A simple way to demonstrate this is to create an empty file, then read a comment from a
text file and write it to the empty file. Of course, you want to lock the file before writing
and unlock it after.

Example 16: Writing a Comment to a Simple File


(WriteToFile.java)

47
Files, Directories, and Workareas

// create a csvpath from the target path passed in


CSVPath targetPath = new CSVPath( target );
// create a csfile from the csvpath
CSFile targetFile = client.getFile( targetPath );

// lock the file


targetFile.lock( "Locking the target file" );
System.out.println( "The file " + target + " is locked" );

// read the source text file into a byte array


System.out.println( "Reading from the source file" );
File f = new File( source );
int filesize = (int) f.length();
byte[] data = new byte[filesize];
DataInputStream in = new DataInputStream( new FileInputStream(f) );
in.readFully(data);
in.close();

// set a variable to position 0 of the target file


long offset = 0;

// write the content to position 0 of the target file


// false means we preserve the content of the target file
CSSimpleFile simpleFile = (CSSimpleFile) targetFile;
System.out.println( "Writing to the target file " + target );
simpleFile.write( data,
offset,
data.length,
false );

// unlock the file


targetFile.unlock();
System.out.println( target + " is now unlocked" );

} catch ( CSException e ) {
System.out.println( "An exception occurred" );
e.printStackTrace();
} catch ( IOException io ) {
io.printStackTrace();
} finally {
if ( client != null ) {
client.endSession();
}
}

Example 15 on page 46 reads text from a file (the file suggested for the example is
comment.txt) and writes it to position 0 of the named file. The false value specifies not to
truncate the file after the write.

If you run this example as suggested, creating an empty file and then reading comment.txt
into it, your new file has this content:

a comment to write

48 ContentServices for TeamSite Cookbook


Copying and Moving Files

See Also
„ “Reading and Writing Entire Files” on page 43 to see how to read entire files

Copying and Moving Files

Task
You want to copy or move files from one workarea to another.

Solution
Use the copy and move methods in CSFile. They both take boolean arguments specifying
whether to overwrite files of the same name in the target location. The example used in this
task takes one source vpath (for CSClient.getFile) and copies the file or directory to a
target area relative path (for CSFile.copy or CSFile.move).

Example
CopyFile.java
Usage:
java CopyFile username password role source-vpath target-area-rel-path
All paths must exist in the TeamSite filesystem.

MoveFile.java
Usage:
java MoveFile username password role source-vpath target-area-rel-path
All paths must exist in the TeamSite filesystem.

Discussion
The copy and move methods both require that you have the source file as a CSFile object.
Your application will probably accept the source vpath as a String from your user. If you
accept one source file name and use getFile to retrieve the file, convert the String to a
CSVPath object, then from the CSVPath get the CSFile.

49
Files, Directories, and Workareas

Then, convert the target location to a CSAreaRelativePath and call copy on the source
CSFile.

Example 17: Copying a File (CopyFile.java)

// create the client object


try {
client = factory.getClient( username, role, password,
Locale.getDefault(), "mydemo", null );
System.out.println( "Client object obtained" );

// create a vpath from the source path


CSVPath sourcePath = new CSVPath( source );
// create a CSFile from the source vpath
CSFile sourceFile = client.getFile( sourcePath );
// create an area-rel-path from the target path
CSAreaRelativePath targetPath = new CSAreaRelativePath( target );

// true overwrites existing files of same name in the target


sourceFile.copy( targetPath, true );
client.endSession();

Moving files works the same way, except that you use CSFile.move instead of
CSFile.copy.

Example 18: Moving a File

// do the move; true overwrites existing files of same name in the target
sourceFile.move( targetPath, true );

For copy and move to work, the target location must be valid on the TeamSite server. If the
target location is a file, the boolean parameter specifies whether to overwrite the file. If the
target is a directory, the file is copied or moved into the directory.

See Also
„ “Creating a Client Object” on page 29 to see how to create the client object needed to
get a single file

50 ContentServices for TeamSite Cookbook


Part II: The Sample Application

51
52 ContentServices for TeamSite Cookbook
Chapter 5

Getting Started with the


Sample Application

Introduction
The ContentServices SDK sample application demonstrates some ContentServices
functionality, but more important, gives you a place to build JSP pages, servlets, beans, or
other classes to play with the ContentServices SDK or build your own application. The
sample application has a modular model-view-controller design and is built according to
design patterns outlined in the J2EE Blueprints (see http://java.sun.com/blueprints).

This means it’s easy for you to get started and add your own components. The sample
application uses Tomcat 4.1.18, JSP 1.2, the Java Servlet 2.3 API, and the JSP Standard Tag
Library (JSTL) 1.0, as well as the Interwoven ContentServices SDK 2.0 and Teamsite 6.0.

If you are working with the ContentCenter Standard or ContentCenter Professional


customizable interfaces, you may be curious about using JSP files, servlets, or beans from
this sample application in one of those interfaces. After all, they are both web applications
that run on the Tomcat servlet container.

In a phrase—don’t do it. Moving components from one application to another is very


likely to cause problems, because the applications are built with different frameworks and
designs. Remember that the ContentServices SDK sample application is a J2EE application
that runs on an external server, communicates remotely with the TeamSite server, and
includes a few TeamSite features. The TeamSite customizable user interfaces are designed
to run exclusively on TeamSite. Moving components from one to the other is not
supported.

Starting and Shutting Down Tomcat

Task
You want to start Tomcat, or shut it down gracefully. You also want to be able to see error
messages or any status messages your application sends you in the Tomcat console window.

53
Getting Started with the Sample Application

Solution
After installing Tomcat and setting environment variables correctly, you start Tomcat by
opening a command window and entering:
> catalina run

When you’re ready, you can shut down Tomcat gracefully by opening a second command
window and entering:

> shutdown

Discussion

After you start Tomcat, you should see messages in the console window like this:

Starting service Tomcat-Standalone


Apache Tomcat/4.1.18
[INFO] Http11Protocol - -Starting Coyote HTTP/1.1 on port 8080
[INFO] ChannelSocket - -JK2: ajp13 listening on 0.0.0.0/0.0.0.0:8009
[INFO] JkMain - -Jk running ID=0 time=10/741 config=c:\jakarta\jakarta-
tomcat-4.1.18\conf\jk2.properties

You know you’ve started Tomcat successfully if you see these messages. You can now view
the Tomcat index page by opening a web browser and entering http://localhost:8080. You
should see this window.

Figure 1: The Tomcat Startup Page

The reason to use catalina run to start Tomcat, rather than startup, is to keep the
console window open. If errors occur during startup, you want to see them so that you can
resolve them. In addition, the sample application has informative System.out.println
messages that appear in the console window at certain points. (If you’re wondering about
the names of commands, the servlet container is called Catalina, and the JSP container is
called Jasper; together they make up the Tomcat server.)

To start your own web application, enter http://localhost:8080/webapp_name/


file_name, using the name of the context root directory for webapp_name. If you define a

54 ContentServices for TeamSite Cookbook


Adding a JSP Page

welcome file in web.xml, a URL ending in webapp_name will automatically route there, so
that you don’t need to enter the file_name:

<!-- define welcome files -->


<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

Always shut down Tomcat with the shutdown command, rather than using Control-C to
stop the Tomcat process. This allows web applications to shut down gracefully and release
any connections to external resources such as databases or the TeamSite server.

Adding a JSP Page

Task
You want to add a JSP page to the sample application.

Solution
A complete web application has various types of resources, which can include JSP pages,
HTML pages, images, style sheets, servlets, applets, beans, custom tag libraries, and other
Java classes. The web.xml deployment descriptor is required.

You can deploy these resources as a group of files in a directory structure (called exploded
form), or you can archive them into a WAR (web application archive) file and deploy just
the archive. Whether you use exploded or web archive form, the directory structure is the
same. During development, we recommend that you use exploded form, so that you can
add one or more components at a time. In addition, some servlet methods work in an
application in exploded form, but not in web archive form. (Please refer to the Java Servlet
2.3 API documentation for details.)

Discussion

The directory structure for an exploded web application looks like this:

/tomcat
/webapps
/your_webapp # this level is the context root
*.jsp
*.html
spring/*.jsp
summer/*.jsp
/images
/WEB-INF
web.xml
/classes
/lib

55
Getting Started with the Sample Application

Directory names within this structure are case-sensitive. You may want to double-check
that you have used WEB-INF, and not web-inf or another variation. On Windows, you can
check this from a command prompt.

The first step is to set up separate development and test directories with the same structure.
This helps ensure a stable test environment. Do your JSP authoring and coding in your
development directory. When components are complete, move them to your test
directory. Your development directory can be anywhere. The test directory must be in
tomcat/webapps.

The top level of the web application (in this example, called your_webapp) is the context
root. In files within your web application, a path beginning with a / refers to a file in the
context root and is known as a context-relative path.

JSP and HTML files can be placed anywhere within the context root except in the WEB-INF
directory. They are usually placed at the top level of the web application or in a directory
under the context root. Images, styles, and other resources the JSP and HTML files use are
placed relative to the JSP and HTML files.

The web application also requires a deployment descriptor, a web.xml file that describes the
application’s resources. The DTD for web.xml is described in the Java Servlet 2.3 API
specification. The sample application that comes with this developer guide has a working
web.xml file. You do not need to update the web.xml when you add a JSP file.

To add a JSP file to the sample application, be sure the file has the right JSP directives,
usually placed at the top, something like these:

<!--
<%@ page contentType="text/html" %>
<%@ page errorPage="error.jsp" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
-->

In this example, the JSP directives are placed within HTML comment tags. This way you
can view the page in an ordinary web browser during development, but the servlet
container still interprets them as JSP tags.

Next, copy the JSP page from your development directory and place it in the right location
in the /webapps directory. There is no need to restart Tomcat when you deploy a JSP page.

Adding a Servlet or Bean

Task
You want to add a servlet or bean to the sample web application. A servlet is a Java class that
extends javax.servlet.http. A bean is a Java class that stores data for a JSP (a value bean)
or takes some action and returns data to a value bean (a utility bean).

56 ContentServices for TeamSite Cookbook


Adding a Servlet or Bean

Solution
First, compile the servlet or bean, then place the class file in a directory structure that
matches the servlet or bean package under /WEB-INF/classes. If you add or replace a
servlet, you need to register it in web.xml, copy the updated web.xml to the web
application directory, and shut down and restart Tomcat. If you replace a bean, you need to
shut down and restart, but you don’t need to change web.xml. If you add a bean, you don’t
need to do either.

Discussion
If you add a servlet in the package com.interwoven.cssdk.examples.servlets, you
would need to use this directory structure under WEB-INF/classes:
/com
/interwoven
/cssdk
/examples
/servlets
your_servlet.class

If you are adding a servlet, you also need to add elements to web.xml. The <servlet>
element describes a servlet, names its class, and gives it initialization parameters, and the
<servlet-mapping> entry maps the servlet to a URL so that you can access it directly from
a browser, or a JSP page can link to it.

Example 1: Mapping a Servlet in web.xml

<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>
com.interwoven.cssdk.examples.servlets.Controller
</servlet-class>
<init-param>
<param-name>authorPage</param-name>
<param-value>/author_editor_console.jsp</param-value>
</init-param>
<init-param>
<param-name>masterPage</param-name>
<param-value>/master_console.jsp</param-value>
</init-param>
<init-param>
<param-name>errorPage</param-name>
<param-value>/error.jsp</param-value>
</init-param>
</servlet>
.
.
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>/controller</url-pattern>
</servlet-mapping>

57
Getting Started with the Sample Application

After you edit web.xml, make sure the file is well-formed and validates before you add it to
the Tomcat web application directory. If the XML file isn’t valid, Tomcat will throw an
exception, and you won’t be able to use the application correctly.

The error can be as simple as entering a comment tag within a comment in the XML file.
You can validate web.xml with any XML validation tool (there are many good ones on the
market) or with the TeamSite iwxml_validate.ipl command-line tool. Using
iwxml_validate.ipl, you would enter:

iw-home/bin/iwxml_validate.ipl filename

When the files are ready, place the servlet class in WEB-INF/classes and the updated
web.xml in WEB-INF. Because you have updated web.xml, you need to shut down and
restart Tomcat.

> shutdown # in one command window


> catalina run # in another command window

After you do this, you should be able to access the servlet by opening a web browser and
going to http://localhost:8080/servlet-url-pattern. On many web servers, you can also
use a URL like http://localhost:8080/servlet/servlet-url-pattern. In most cases, you
wouldn’t access a bean directly from a browser. Instead, a JSP or servlet would use it and
return the data you need.

See Also
„ “Adding a JSP Page” on page 55 to learn how to add a JSP page to the sample application

58 ContentServices for TeamSite Cookbook


Chapter 6

Extending the Sample Application

Introduction
This guide includes a sample J2EE application (the Ajuba Corporate Intranet) that
demonstrates how to build a remote application that uses ContentServices SOAP.

The sample is a JSP-and-servlet web application with a TeamSite mini-UI. It has a model-
view-controller architecture based on the J2EE Blueprints. The main reason for this design
is to separate presentation from business logic, put more Java code in reusable components,
and keep the amount of Java code in JSP files to a minimum.

This makes the application much easier to maintain, avoiding the ripple effect that occurs
when a change is made in one file. Another benefit is that programmers can write code and
web designers can design presentation. Even better, this architecture makes using a
sophisticated API, like the ContentServices SDK, quite simple at the presentation layer. In
the JSP files, most of the work with ContentServices is done with simple JSP or JSTL tags.

The components in the sample application are JSP pages, servlets, and beans. Beans are
either value beans that hold data and are written according to the JavaBeans design patterns,
or utility beans that retrieve data or take some other action. Used this way, the beans can be
converted to Enterprise JavaBeans in a full J2EE application.

You should become familiar with the application components and what they do. Once you
learn the components, you will easily be able to add your own servlets and beans to build
your own application.

If you are working with the ContentCenter Standard or ContentCenter Professional


customizable interfaces, you may be curious about using JSP files, servlets, or beans from
the sample application in one of those interfaces. After all, they are both web applications
running on the Tomcat servlet container.

In a phrase—don’t do it. Moving components from one application to another is very


likely to cause problems, because the applications are built with different frameworks and
designs. Moving components from one to the other is not supported in this release.

59
Extending the Sample Application

Figure 2: Architecture of the J2EE Sample Application

View author_editor_console.jsp
emptyform.jsp
error.jsp
index.jsp
login.jsp
logout.jsp
master_console.jsp
modified_files_view.jsp
noelements.jsp
submit_approved.jsp
submit_denied.jsp
submit_direct.jsp
task_view.jsp

Controller AuthenticationFilter.java

Controller.java
DispatchSubmitDirect.java
ErrorDispatcherServlet.jav
a
FileDownloadServlet.java
GetModifiedFilesServlet.ja

Model - Value Beans FileDataBean.java


SubmitResultBean.java

DoSubmitDirectBean.java
Model - Utility Beans
GetWorkareaBean.java

Legend

JSP Filter Servlet Value Bean Utility Bean

60 ContentServices for TeamSite Cookbook


Accepting Login Values from the User

Accepting Login Values from the User

Task
You want to display a login form that requires users to enter a username, password, and role
to send to the controller servlet. The controller will use these values to authenticate users
on the TeamSite server. A user can enter just about any string for a username or password,
but must choose from a list of defined roles. (In the next section, we’ll explain how to write
an authentication filter to avoid sending null, empty, or unusable login values to the
controller servlet.)

Solution
The solution requires an HTML login form and a filter that checks the user’s login
parameters before passing them to a servlet that performs the authentication. These pieces
are tied together by entries in web.xml.

In this example, the login form is a JSP file that accepts a user name, password, and role.
Each value is required.

The filter implements javax.servlet.Filter from the Java Servlet API. A filter works on
the request before it is sent to a servlet, or the response before it is sent to a browser. In this
case, the request parameters are username, password, and role, and the filter checks for null
values, empty strings, and invalid entries. If the request parameters pass this check, the filter
routes them to the controller servlet for authentication. If not, the filter forwards the
request to a specialized JSP page that displays an explanatory message.

Files
login.jsp
emptyform.jsp
noelements.jsp
AuthenticationFilter.java
web.xml

Discussion
The first step is to build the HTML form. This example shows a skeletal login form
with a text box, password box, select widget, and submit button, all created with
standard HTML tags. The form names the input values username, password, and role.

61
Extending the Sample Application

Example 2: Displaying the Login Form (login.jsp)

<form action="<c:url value="/controller" />" method="get">

<table width="45%" border="0" cellspacing="5" cellpadding="5">


<tr>
<td align=center>
All fields are required.
</td>

<tr colspan=2>
<td align="center">
<input name="username" type="text" class="formElements" size="20">
<br>
<b>username</b><p></td>
</tr>

<tr colspan=2>
<td align="center">
<input name="password" type="password" class="formElements"
size="20">
<br>
<b>password</b><p></td>
</tr>

<tr colspan=2>
<td align="center">
<p>
<select name="role" size="3">
<option value="author">Author
<option value="editor">Editor
<option value="master">Master
</select>
<br>
<b>role</b><p></td>
</td>
</tr>

<tr colspan=2>
<td align="center"><p>
<input name="submit" type="submit" value="Login">
</p>
</td>
</tr>
</table>
</form>

The <form> tag routes the form input to the URL /controller using the <c:url> tag:

<!-- place this line at top of file -->


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
.
.
<form action="<c:url value="/controller" />" method="get">

62 ContentServices for TeamSite Cookbook


Filtering Login Values for the Controller

This mapping sends the form input to the controller servlet. The <c:url> tag is a JSTL core
library action that applies conversion and encoding rules to a URL used in a JSP page.
Because <c:url> comes from the JSTL core library, you must declare it with a JSP
<%@ taglib> directive.

In this case, <c:url> converts the context-relative path /controller to a server-relative


path so that the web server can locate the servlet class. The controller servlet is mapped to
the URL /controller in web.xml.

Example 3: Mapping the Controller Servlet (web.xml)

<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>com.interwoven.cssdk.examples.servlets.Controller
</servlet-class>
<init-param>
<param-name>authorPage</param-name>
<param-value>/author_editor_console.jsp</param-value>
</init-param>
<param-name>masterPage</param-name>
<param-value>/master_console.jsp</param-value>
</init-param>
<init-param>
<param-name>errorPage</param-name>
</init-param>
</servlet>
.
.
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>/controller</url-pattern>
</servlet-mapping>

See Also
„ The “Overview” chapter to see how a user login is translated to a SOAP request and
response

Filtering Login Values for the Controller

Task
You want to filter the login values the user enters so that the controller servlet receives only
valid values to use when authenticating users on the TeamSite server. If the controller
servlet receives a null or empty value, it would throw an exception and the sample
application would be temporarily unusable for that user’s session.

63
Extending the Sample Application

Solution
You can write a filter, a Java class that implements javax.servlet.Filter (from the Java
Servlet 2.3 API). A filter processes an HTTP request from the client before it reaches a
servlet, and then processes the response from the servlet before it reaches the client.

The filter should detect null or empty values and route the user to a JSP page that displays an
explanatory message. If the login values are valid, the filter should send them on to the
controller.

Files
AuthenticationFilter.java
noelements.jsp
invalidelements.jsp
web.xml

Discussion
Because the filter implements javax.servlet.Filter, it needs to define init, destroy,
and doFilter methods. init and destroy are standard servlet methods. The web server
creates just one instance of the filter for the web application.

The servlet container calls init after it creates the filter instance and before the filter
handles any requests. The server calls destroy after the filter has been taken out of service
and all pending requests have completed.

The doFilter method is where the filter’s work is done. You can parse request parameters,
log statistics to a file, or do whatever else is needed, before sending the request and
response on to the next item in the chain. The next item is either another filter or a servlet,
as defined in the web.xml file.

64 ContentServices for TeamSite Cookbook


Filtering Login Values for the Controller

The sample authentication filter has initialization parameters defined in web.xml. This way,
the filter has access to the request parameter names, which are defined in login.jsp. It can
use those names to get the request parameter values.
Example 4: Defining Init Parameters for AuthenticationFilter (web.xml)

<!-- Define the filters within the web application -->


<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>
com.interwoven.cssdk.examples.servlets.AuthenticationFilter
</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>initial</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>initial</param-value>
</init-param>
<init-param>
<param-name>role</param-name>
<param-value>initial</param-value>
</init-param>
<init-param>
<param-name>submit</param-name>
<param-value>initial</param-value>
</init-param>
</filter>

The filter is shown in Example 5 on page 66. Remember that it does most of its work in the
doFilter method. Specifically, it gets the names of each initialization parameter, gets the

65
Extending the Sample Application

corresponding request parameter value, checks the parameters for null values and empty
strings, and routes the request to the right place.

Example 5: Filtering the Login Values (AuthenticationFilter.java)

package com.interwoven.cssdk.examples.servlets;

import javax.servlet.*;
import java.util.Enumeration;
import java.io.IOException;

public class AuthenticationFilter implements Filter {

private FilterConfig filterConfig;

public void init(FilterConfig filterConfig)


throws ServletException {
System.out.println( "Within authentication filter .." );
this.filterConfig = filterConfig;
}

public void doFilter( ServletRequest request,


ServletResponse response,
FilterChain chain )
throws IOException, ServletException {

System.out.println( "Within doFilter .." );


RequestDispatcher rd = null;
boolean emptyform = false;

try {

Enumeration initParams = filterConfig.getInitParameterNames();

// if no init params invoke next element in chain


if (initParams == null) {
System.out.println( "No elements to verify" );
chain.doFilter( request, response);
}

// or, grab init param names and get the matching form elements
else {
while ( initParams.hasMoreElements() ) {
// get the name of the init param
String name = (String) initParams.nextElement();

// get the value of the request param with that name


String formElement = request.getParameter(name);

// check to see if any form element is null


// if so, forward to a jsp
if (formElement == null) {
System.out.println( "The form element is null" );
rd = request.getRequestDispatcher("/noelements.jsp");
rd.forward( request, response );

66 ContentServices for TeamSite Cookbook


Filtering Login Values for the Controller

return;
}

// check to see if any form element is empty


// if so, forward to a jsp
else if (formElement.equals("")) {
System.out.println( "The form element is empty" );
emptyform = true;
rd = request.getRequestDispatcher("/emptyform.jsp");
rd.forward( request,response );
return;
}
}

// otherwise, form was filled out properly


// send all form elements to Controller servlet
System.out.println( "form ok .. sending to ControllerServlet" );
chain.doFilter( request, response );
System.out.println( "Filtering the response .." );
}
}

catch (IOException io) {


throw io;
}
catch (ServletException se) {
throw se;
}
}

public void destroy() {


filterConfig = null;
System.out.println( "Authentication filter going away .." );
}

The HTML form in login.jsp sends values to the controller servlet. To apply the
authentication filter to the controller, so that the filter handles login values before they
reach the controller, you must register the filter and map it in web.xml. Note that the
<init-param> elements define the filter’s initialization parameters.

Example 6: Mapping the Authentication Filter to the Controller

<!-- map the filter to a servlet or URL -->


<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/controller</url-pattern>
</filter-mapping>

See Also
„ “Accepting Login Values from the User” on page 61 to see how to map the <form> tag
to a servlet

67
Extending the Sample Application

Creating a Factory Object

Task
You want to have your sample application communicate with the TeamSite server using
ContentServices SOAP.

Solution
The first step is to create a factory object. The sample application communicates with the
TeamSite server using ContentServices SOAP, so this example shows how to create a SOAP
factory.

The first step is to install the ContentServices SOAP server in your TeamSite directory and
the ContentServices SOAP client software in tomcat\webapps\csdemo\WEB-INF\lib.
Once those are installed, this code in the init method of Controller.java reads the
factory type from the file sampleapp.properties.

Example 7: Creating a ContentServices SOAP Factory

// read a factory setting from a properties file


try {
Properties props=new Properties();
InputStream in=(InputStream)getClass().getResourceAsStream(
"/sampleapp.properties");
props.load(in);
System.out.println("Using factory properties");
props.list(System.out);
in.close();
factory=CSFactory.getFactory(props);
} catch ( FileNotFoundException fnf ) {
throw new CSWebAppException( fnf );
} catch ( IOException io ) {
throw new CSWebAppException( io );
} catch ( CSFactoryInitializationException csfie ) {
throw new CSWebAppException( csfie );
}
System.out.println( "Factory object created from properties file" );
}

Files
Controller.java
web.xml

Discussion
Creating the factory object is the first step you need to take in any ContentServices
application. It defines a factory that creates CSClient objects that communicate with the
TeamSite server using the transport of your choice.

68 ContentServices for TeamSite Cookbook


Authenticating Users

When you create a SOAP factory, you make your application a client of the ContentServices
web service. The CSClient object that you create next will retrieve objects from the
TeamSite server using the SOAP transport.

See Also
„ “Authenticating Users” on page 69 to see how to create a client object
„ “Creating a Factory Object” on page 25 to see how to create a ContentServices JNI or
generic factory object

Authenticating Users

Task
You want to authenticate users on the server and make sure the username, password, and
role entered define a valid user. If the user is valid, you want to route to an appropriate JSP
page.

Solution
Before you can authenticate users, you need to define valid users (with passwords) on the
TeamSite host and assign those users TeamSite roles. Then, you need to get a factory object,
as described in “Creating a Factory Object” on page 68.

You use the factory object to authenticate the user. If all goes well, and the user is
authenticated, you are returned a CSClient object that allows you to retrieve files,
workareas, branches, editions, and so on for that user from the TeamSite filesystem, using
the transport type assigned to the factory object.

Files
Controller.java
author_editor_console.jsp
master_console.jsp

Discussion
Because the user has entered a username, password, and role in login.jsp, you can
retrieve them from the HTTP request. Each parameter has a name and a value. The names
are username, password, and role (as you saw in Example 2 on page 62). The values are
what the user enters.

You use the login values from the request, and the factory object, to get a client object (an
instance of CSClient) with getClient. A valid client object tells you that the user is

69
Extending the Sample Application

successfully authenticated. The client object also contains a CSContext object, which holds
information about the current user’s locale, application context, and server.

Example 8: Authenticating the User (Controller.java)

// get login values from the request


String username = request.getParameter( "username" );
String password = request.getParameter( "password" );
String role = request.getParameter( "role" );

System.out.println( "Variables set from request params" );

//
// This method returns a CSClient object if
// authentication is successful; otherwise, it throws
// an exception. The CSClient object is the authentication
// token for the ContentServices server and is added to
// the session as part of the CSUser object.
//

try {
client = factory.getClient(username, role,
password, Locale.getDefault(),
"mydemo", null);
} catch (CSException e) {
throw new CSWebAppException( e );
}
System.out.println( "User authenticated and client object obtained" );

// put the client object in the session so other


// components can grab it
HttpSession currentSession = request.getSession();
try {
currentSession.setAttribute( "client", client );
} catch ( IllegalStateException ise ) {
throw ise;
}
System.out.println( "Client object added to session" );

Notice that after we get the client object, we store it in the HTTP session. It’s such a useful
object that all components in the web application need to be able to use it.

See Also
„ “Displaying a List of Modified Files” on page 87 to see how another component retrieves
the client object from the session
„ “Allowing Users to Log Out” on page 71 to see how to invalidate the client object and
remove it from the HTTP session when a user logs out

70 ContentServices for TeamSite Cookbook


Allowing Users to Log Out

Allowing Users to Log Out

Task
You want to allow users to log out of your application. The application needs to handle the
objects that relate to the user’s session, both the TeamSite session and the HTTP session.

Solution
When a user logs out, you need to invalidate the CSClient object that represents the user
on the TeamSite server and remove it from the HTTP session.

You probably want to offer your user a button or link to click for logout. One way to handle
logout is to map the button or link to a servlet.

Example 9: Defining a Logout Button (author_editor_console.jsp)

<tr>
<form action="<c:url value="/logout" />" method="GET">
<td align="left">
<input name="submit" type="submit" class="formElements"
value="Logout"> </td>
</form>
</tr>

71
Extending the Sample Application

The GET request generated when the user clicks the button is sent to the URL /logout,
which is mapped to LogoutServlet in web.xml. The servlet handles the logout in its doGet
method.

Example 10: Handling the Logout Request (LogoutServlet.java)

public void doGet(HttpServletRequest req, HttpServletResponse res)


throws ServletException, IOException {

CSClient client;
RequestDispatcher rd;
HttpSession session = req.getSession();

// get the client object from the HTTP session


// it represents the user to TeamSite
client = (CSClient) session.getAttribute( "client" );

// set content type


res.setContentType( "text/html" );

// end the user's teamsite session


// and invalidate the client object
System.out.println( "TeamSite session ending for " +
client.getCurrentUser() );
client.endSession();

// invalidate the http session


// and unbind any objects added to it
session.invalidate();
System.out.println("The user's HTTP session has been invalidated");

// set content type


res.setContentType( "text/html" );

// forward to the logout jsp


rd = req.getRequestDispatcher( logoutPage );
rd.forward( req, res );
}

Remember that you end the user’s session on two levels. First, use client.endSession()
(from the ContentServices SDK) to invalidate the CSClient object that the TeamSite server
returned when it authenticated the user.

Then, end the HTTP session your web application uses and take whatever steps are
appropriate. Example 10 on page 72 calls session.invalidate() (from the Java Servlet
API) to end the user’s HTTP session and release any objects the application may have stored
in the session (such as the client object; see Example 8 on page 70).

72 ContentServices for TeamSite Cookbook


Handling Exceptions

Files
author_editor_console.jsp
master_console.jsp
modified_files_view.jsp
task_view.jsp
logout.jsp
LogoutServlet.jsp

Discussion
Allowing a user to log out is relatively simple. First, understand that the TeamSite server
does not maintain a real user session. The server returns a session string in the CSContext
object that is embedded in the CSClient object, and all calls made from the same CSClient
object represent the same user, but still it is up to the application to maintain the session.

A web application running on a servlet container typically uses one of two techniques for
tracking sessions. The server can return all information related to the current user with each
response and let the browser send it back as part of the next request. Another way is for the
server to save the client’s state somewhere and send back only an identifier with the
response that the client sends back with the next request.

Either way, the application can use cookies, hidden form fields, or URL rewriting to
identify the user’s session. The session string that is stored in the CSContext object (and
available with CSContext.getSessionString) is useful with any of these techniques for
identifying the user.

See Also
„ “Creating a Factory Object” on page 68 to learn how to authenticate a user and get a
CSClient object

Handling Exceptions

Task
You want to detect any runtime exception from any component in the web application and
display an error page with information about the exception.

Your application can use different ways of handling exceptions. During development, you
want to see the name of the component that threw the exception, the exception message,
and a stack trace. To prepare your application for end users, you want to catch the
exception and route to a JSP page that offers an informative message.

73
Extending the Sample Application

Solution
The ContentServices SDK sample application handles exceptions for developers. That is,
the application components catch and rethrow exceptions, and the
ErrorDispatcherServlet routes the exception information to a common error page.

This development-time solution to handling exceptions has several parts:

„ The web application needs a common error page, and the error page needs to be
declared in web.xml.
„ All JSP pages need to identify themselves to the error page if an exception occurs.
„ The web application needs an ErrorDispatcherServlet that ensures the exception is
dispatched to the error page.
„ Servlets and filters need to catch and rethrow exceptions so that the
ErrorDispatcherServlet can route them to the error page.
„ You need to define a new runtime exception class as a subclass of CSRuntimeException
that the web application will throw.

Once you take these steps, and the error page is working, you can start to examine the
ContentServices SDK exceptions that are thrown.

Files
ErrorDispatcherServlet.java
error.jsp
author_editor_console.jsp (as an example)

Discussion

First, define the error page (error.jsp) as a JSP page with the errorPage attribute set to
true:

<%@ page isErrorPage="true" %>

The error page also uses JSTL expressions to display the source page and exception message
and Java code to display the exception’s stack trace.

Second, each JSP page except the error page needs a line that identifies it as the page having
an exception, should an exception occur. This line uses the JSTL <c:set> tag:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>


<c:set var="sourcePage" scope="request"
value="${pageContext.request.requestURI}" />

Third, the application needs an ErrorDispatcherServlet to dispatch the exception to the


error page. This is due to the difference between the request-attribute name in the JSP and
servlet specifications. Briefly, the servlet specification defines the name
javax.servlet.error.exception for the request attribute that contains the Throwable

74 ContentServices for TeamSite Cookbook


Handling Exceptions

exception. The JSP specification uses javax.servlet.jsp.jspException. For now, you


can work around this by using a servlet to set the request attribute the JSP page requires.
The sample application uses a servlet named ErrorDispatcherServlet to do this.

You also need to register ErrorDispatcherServlet in web.xml and define which


exceptions should be mapped to the servlet.

Example 11: Defining the Error Page (web.xml)

<servlet>
<servlet-name>errorDispatcher</servlet-name>
<servlet-class>
com.interwoven.cssdk.examples.servlets.ErrorDispatcherServlet
</servlet-class>
<init-param>
<param-name>errorPage</param-name>
<param-value>/error.jsp</param-value>
</init-param>
</servlet>
.
.
<servlet-mapping>
<servlet-name>errorDispatcher</servlet-name>
<url-pattern>/errorDispatcher</url-pattern>
</servlet-mapping>
.
.
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/errorDispatcher</location>
</error-page>

The error.jsp page can now display the referring page, exception message, and stack
trace, as in Example 12 on page 75.

Example 12: Displaying Exception Information (error.jsp)

<td><b>The error occurred in <c:out value="${sourcePage}" /></b></td>


..
<td><b>The exception message is
<c:out value="${pageContext.exception.message}" /></b></td>
..
<td><b>The stack trace follows: </b>
<p>
<code>
<font size="+1">
<%
ByteArrayOutputStream baos = new ByteArrayOutputStream();
exception.printStackTrace(new PrintStream(baos));
%>
<%= baos.toString() %>
</font>
</code>

75
Extending the Sample Application

You can view the error page by creating an exception. For example, log in with the
username and password of an author, but enter the role master. The exception that occurs
is a CSWebAppException, which is a runtime exception that extends CSRuntimeException
and wraps the root cause exception, CSAuthenticationException. A
CSWebAppException is used so that a servlet can throw it in a doGet or doPost method.

The error page looks like Example 13 on page 76 (although the stack trace is truncated
here).

Example 13: What the Error Page Shows (error.jsp)

Page or Servlet
The error occurred in /csdemo/controller

Message
The exception message is Role is not authorized for this user

Stack Trace
The stack trace follows:

com.interwoven.cssdk.examples.exceptions.CSWebAppException:
(Role is not authorized for this user) at
com.interwoven.cssdk.examples.servlets.Controller.doPost(Controller.java:
158) at ...
Root cause: com.interwoven.cssdk.access.CSAuthenticationException:
master(Role is not authorized for this user) ...

The stack trace you saw in Example 13 on page 76 comes from code in Controller.java.

Example 14: Throwing a CSWebAppException (Controller.java)

try {
client = factory.getClient(username, role,
password, Locale.getDefault(),
"mydemo", null);
} catch (CSException e) {
throw new CSWebAppException( e );
}

In the ContentServices SDK, all exceptions are subclasses of CSException. In your


application, you can usually catch and handle the superclass CSException. If you want to
display your own exception message, catch and handle subclass exceptions individually.

The ContentServices SDK has some common exceptions, used in many methods, that you
should know.

ContentServices Exception Meaning


CSException The superclass of all exceptions. Handles an exception
that doesn’t fit into another category.

76 ContentServices for TeamSite Cookbook


Handling Exceptions

ContentServices Exception Meaning


CSAuthorizationException Thrown if the user is not authorized to perform the
requested task.
CSObjectNotFoundException Thrown if the server cannot find the object the user
wants to work with.
CSRemoteException Thrown if the ContentServices SOAP or JNI server has
an error and cannot return the data the user requested.
CSExpiredSessionException Thrown if the user’s TeamSite session has expired.

See Also
„ “Authenticating Users” on page 69 to see how to authenticate users and create a client
object

77
Extending the Sample Application

78 ContentServices for TeamSite Cookbook


Chapter 7

More on the Sample Application

Retrieving a User’s Workarea

Task
Once a user is authenticated, you want to retrieve the user’s workarea and display it in a JSP
page.

Solution
The solution has several parts:
„ Authenticate the user (as in “Authenticating Users” on page 69)
„ Retrieve the workarea, using a bean to define how information about each file and
directory is stored
„ Display information about each file using JSTL
„ Use a widget that allows a user to browse the workarea

Files
GetWorkareaBean.java
FileDataBean.java
Controller.java
author_editor_console.jsp
master_console.jsp

Discussion
The main work of retrieving the workarea is done by GetWorkareaBean. GetWorkareaBean
retrieves attributes for each file in the root of the workarea. It does not retrieve the files
themselves; that will happen later with FileDownloadServlet.

FileDataBean defines the attributes retrieved for each file, including name, size, last
modifier, last modification date, vpath, and kind (meaning, file or directory). Because
FileDataBean follows the JavaBeans design pattern, it is easy to use its values with JSTL in
a JSP file.

79
More on the Sample Application

In the sample application, the users you define share a workarea at the vpath /default/
main/WORKAREA/demo, so this vpath is hard-coded in GetWorkareaBean as the workarea
vpath:

// Path to the workarea containing the files we're interested in.


public static CSVPath waPath = new CSVPath(
"/default/main/web/WORKAREA/demo");

To retrieve the workarea, GetWorkareaBean uses the CSClient.getWorkarea method to


return an array of FileDataBean objects.
Example 15: Retrieving a User’s Workarea (GetWorkareaBean.java)

// get the workarea from the cs server


public FileDataBean[] getWorkarea() throws CSException {
CSWorkarea wa = client.getWorkarea(waPath, false);

CSSortKey[] sortArray = new CSSortKey[1];


sortArray[0] = new CSSortKey(CSSortKey.NAME, true);

Iterator i = wa.getFiles( CSFileKindMask.ALLNONHOLES,


sortArray,
CSFileKindMask.ALLNONHOLES,
null,
0,
-1);

// get all the files in the root of the workarea


ArrayList fileDataList = new ArrayList();
while (i.hasNext()) {
CSFile file = (CSFile) i.next();
long fsize = 0;
if (file.getKind() == CSSimpleFile.KIND) {
// Only simple files have a size...
fsize = ((CSSimpleFile) file).getSize();
}

// First, get the vpath of the file without the "//server" prefix
CSVPath pathNoServer = file.getVPath().getPathNoServer();

// Then, make the vpath a string starting with /default


String vpath = pathNoServer.toString();

fileDataList.add(new FileDataBean(file.getName(),
fsize,
file.getLastModifier().getName(),
file.getContentModificationDate(),
vpath,
file.getKind()));
}

FileDataBean[] fdata = new FileDataBean[fileDataList.size()];


fdata = (FileDataBean[]) fileDataList.toArray(fdata);
return fdata;
}

80 ContentServices for TeamSite Cookbook


Retrieving a User’s Workarea

Remember that the first method call, to getWorkarea, retrieves information about the
files. The first argument to getWorkarea is the hard-coded vpath to the group workarea.
The second argument is false, which tells the ContentServices SDK that if the workarea
does not exist, it should return a shallow workarea object and validate it if it is called by any
other methods.

The second method call is to getFiles. This call retrieves the actual files in the root of the
workarea, but only to check the file sizes. At this point, getFiles does not return any file
content.

The line that includes getVPath().getPathNoServer() is also interesting. It returns the


file’s vpath without the //servername at the beginning. In the sample application, a vpath
without a server name looks like /default/main/WORKAREA/demo/filename.

Once the user is authenticated, Controller.java calls GetWorkareaBean, retrieves the


user’s workarea, and stores it in the request scope in an attribute named files.

Example 16: Calling GetWorkareaBean (Controller.java)

GetWorkareaBean wab = new GetWorkareaBean( client );


FileDataBean[] files = null;
try {
files = wab.getWorkarea();
} catch (CSException e) {
throw new CSWebAppException(e);
}
System.out.println( "GetWorkareaBean created and workarea retrieved" );

// put the workarea files in the request scope


// and return them in the response
request.setAttribute( "files", files );

81
More on the Sample Application

The JSP file then uses JSTL tags to retrieve the workarea information from the request
scope and display it. The array of files that Controller.java puts in the request scope is
named files, and the current file in the array is named current.

Example 17: Displaying the Files in the JSP Page (author_editor_console.jsp)

<c:forEach items="${requestScope.files}" var="current">


<tr>
<td width=20> <img src="images/fiicon.gif" </td>
<td> <a href="<c:url value="/download" >
<c:param name="path" value="${current.vpath}" />
<c:param name="fname" value="${current.fileName}" />
</c:url> ">
<c:out value="${current.fileName}" /> </a> </td>
<td width=90> <c:out value="${current.size}" /> </td>
<td> <c:out value="${current.lastModDate}" /> </td>
<td> <c:out value="${current.lastModifier}" /> </td>
</tr>
</c:forEach>

Remember that fileName, size, lastModDate, and lastModifier are properties of files
defined in FileDataBean.

At this point, the workarea data is displayed exactly as it comes from the TeamSite server,
for example:
Research-Chemicals-Canada.doc 122880 Sun Mar 16 19:49:34 PST 2003
INTERWOVEN\jsmith

If you want to convert the file size to kilobytes, use a different date format, or display the
user name without a domain, you need to manipulate the returned data, perhaps in
FileDataBean.

See Also
„ “Creating a Factory Object” on page 68 to learn how to authenticate users
„ “Downloading a File” on page 82 to see how FileDownloadServlet (called by the
/download URL) works

Downloading a File

Task
You want to allow users to click a file name in a JSP page and download a file using a Save As
dialog box from the TeamSite filesystem to a local directory or hard disk.

82 ContentServices for TeamSite Cookbook


Downloading a File

Solution
Downloading a file with a Save As dialog box is a good job for a servlet. The key is in how
the servlet sets response headers. The servlet also needs a method that retrieves the file’s
content from the TeamSite server.

Files
FileDownloadServlet.java
author_editor_console.jsp
master_console.jsp

Discussion
Downloading a file to a local area is a simple way to allow users to edit files before
submitting the edited version. FileDownloadServlet retrieves the file content from the
TeamSite filesystem, using an unusual response header. The browser typically won’t
recognize the response header, so it throws a Save As dialog box appropriate to the
windowing system used by the client (user’s) computer.

Figure 3: Downloading a File from the TeamSite Server

Figure 4: Saving the File to a Local Directory on Windows

83
More on the Sample Application

In author_editor_console.jsp, we pass two values to FileDownloadServlet for each


filename the user clicks. Once again, JSTL does the magic.

Example 18: The Request Parameters Passed (author_editor_console.jsp)

<c:forEach items="${sessionScope.files}" var="current">


<tr>
<td width=20> <img src="images/fiicon.gif" </td>
<td> <a href="<c:url value="/download" >
<c:param name="path" value="${current.vpath}" />
<c:param name="fname" value="${current.fileName}" />
</c:url> ">
<c:out value="${current.fileName}" /> </a> </td>

The <c:url> tag links the file name to FileDownloadServlet. The <c:param> tags send
the servlet request parameters named path, containing the file’s vpath, and fName,
containing the file name. The filename is linked with an <a href> tag. The value of <a
href> is the JSTL tag <c:url>, which calls a servlet mapped in web.xml to /download. The
servlet allows a user to click a link and download a file from TeamSite 6 to a local directory
or hard disk. The example shows two values being passed to the servlet in the <c:param>
tags, the file’s vpath and name.

Using URLs and URIs in JSP files can be tricky. To link to a file stored in the TeamSite
filesystem safely:

„ Always use <c:url> to refer to a URL or URI in a JSP file.


„ Always link to a vpath, not to the file’s path on the mount point. Allow the TeamSite
server to locate the file from the vpath.

Remember that in a JSP file, a URI that starts with a / is always interpreted by the servlet
container as relative to the context root, the directory in tomcat/webapps where your web
application resides. This can be confusing when you want to refer to a vpath in the TeamSite
file system, such as /default/main.

84 ContentServices for TeamSite Cookbook


Downloading a File

Once the servlet gets the client object from the session, it can easily retrieve the values of
path and fName from the request. This is why we use a servlet for this job, because it works
so naturally.

Example 19: Reading the Request Parameters (FileDownloadServlet.java)

public void doGet(HttpServletRequest req, HttpServletResponse res)


throws ServletException, IOException {

String pathNoServer, newMountPath, fname;


CSClient client;
CSVPath vpath;

HttpSession session = req.getSession();

// get the client object from the session


// it represents the user's session
client = (CSClient) session.getAttribute( "client" );

// this is the vpath that starts with /default


// at this point it's a string
pathNoServer = req.getParameter( "path" );
System.out.println( "The value of path is " + pathNoServer );

// this is the filename to use in the Save As dialog


fname = req.getParameter( "fname" );
System.out.println( "The value of fname is " + fname );

// create a cs vpath object from the string vpath


vpath = new CSVPath( pathNoServer );

// set the response headers to display a Save As dialog


res.setContentType( "application/x-download" );
res.setHeader( "Content-Disposition",
"attachment; filename=" + fname);

// get an output stream


OutputStream out = res.getOutputStream();

// send the file; shown in the next example


returnFile( vpath, client, out);
}

We will give the first parameter, path, to the TeamSite server to locate the file. When you
retrieve it from the request, it’s a String, but you can easily convert it to a CSVPath object
with the CSVPath constructor.

The second parameter, fname, appears in the Save As dialog box to show the user which file
she is downloading. The setContentType and setHeader methods use a content type and
response header that are defined in the HTTP specification but unusual to browsers.

85
More on the Sample Application

Now for the returnFile method, which does the work of getting the file from the
TeamSite server so that the servlet can return it to the browser in the response.

Example 20: Returning a File from the Server (FileDownloadServlet.java)

// uses cs to locate the file from the vpath

public static void returnFile( CSVPath vpath, CSClient client,


OutputStream out )
throws FileNotFoundException, IOException {

InputStream in = null;

try {
// use the csvpath to get the corresponding file
CSSimpleFile f = (CSSimpleFile) client.getFile( vpath );

// a true argument to getInputStream makes it thread safe


in = f.getInputStream(true);

// do the buffering
byte[] buf = new byte[4 * 1024]; // 4K buffer
int bytesRead;
while ((bytesRead = in.read(buf)) != -1) {
out.write(buf, 0, bytesRead);
}
// catch any exceptions
} catch (CSException e) {
throw new CSWebAppException(e);
} // and clean up
finally {
if (in != null) in.close();
}
}

Once you have the CSVPath object (as you saw in Example 19 on page 85), you can retrieve
the file content with getFile. Use the returned file to get an input stream, specifying a
return value of true to make it thread safe (remember—servlets are multithreaded, so you
must always write them to be thread safe).

From that point, buffer the file content, write it to an output stream, handle exceptions—
and you’re done. The file is sent to the browser, and the browser returns it in the Save As
dialog box so the user can download it.

See Also
„ “Handling Exceptions” on page 73 to understand how to handle exceptions thrown by
the ContentServices SDK

86 ContentServices for TeamSite Cookbook


Displaying a List of Modified Files

Displaying a List of Modified Files

Task
After a user downloads files, modifies them, and copies the modified versions to the
workarea, you want to display a list of modified files. The user will select from the modified
files list to build a submit files list.

Solution
In the Author/Editor console, the user clicks the Modified Files link to move to the
Modified Files page. Because clicking a link sends an HTTP request, it is easy to use a servlet
to handle the request and return the list of modified files in the response. The
CSWorkarea.getModifiedFiles method returns the modified files, with several options.

Files
author_editor_console.jsp
modified_files_view.jsp
GetModifiedFilesServlet.java

Discussion
Once a user copies a modified file to the workarea, the ContentServices SDK detects it as
modified but not yet submitted. GetModifiedFilesServlet is similar to
FileDownloadServlet, in that it has a doGet method that handles the request and returns a
response, and another method that retrieves the modified files.

The modified file data returned is file attributes, just like the workarea data. Because the
sample application is designed with reusable components, GetModifiedFilesServlet
retrieves the modified file data and returns it as an array of FileDataBean objects. Then, it
is easy to display them in the JSP page, because you learned how to display FileDataBean
properties when you displayed the user’s workarea.

The first step is to add the servlet to the Modified Files link in
author_editor_console.jsp:

<a href="<c:url value="/modified" />" class="titlebarLinks">


Modified Files</a>

Again, we use the <c:url> tag so that the URL defined in web.xml is converted from a
context-relative path to a server-relative path.

87
More on the Sample Application

When the user clicks the link, GetModifiedFilesServlet receives the GET request and
displays modified_files_view.jsp.

Example 21: Defining the Modified Files Page (GetModifiedFilesServlet.java)

public void init() throws ServletException {


System.out.println( "In ModifiedFilesServlet" );

ServletConfig config = getServletConfig();


modifiedFilesPage = config.getInitParameter( "modifiedFilesPage" );
if ( modifiedFilesPage == null ) {
throw new UnavailableException( "Modified files page not defined
in web.xml" );
}
getServletContext().log( "modifiedFilesPage is " + modifiedFilesPage );
}

Then, the servlet’s doGet method handles the request. As usual, the first thing the servlet
does is get the client object that refers to the current user from the HTTP session.

Example 22: Handling the Request (GetModifiedFilesServlet.java)

public void doGet(HttpServletRequest req, HttpServletResponse res)


throws ServletException, IOException {

RequestDispatcher rd = null;
HttpSession session = req.getSession();

// get the client object from the session


// it represents the user's session
client = (CSClient) session.getAttribute( "client" );

// call getModifiedFiles
// pass it the client object
try {
modifiedFiles = getModifiedFiles( client );
} catch (CSException e ) {
System.out.println( "A CSException occurred" );
}

// set content type


res.setContentType( "text/html" );

// put modifiedFiles in the response


// jsp can retrieve them with "${requestScope.x.y}"
req.setAttribute( "modifiedFiles", modifiedFiles );

// dispatch to the modifiedFilesPage


rd = req.getRequestDispatcher( modifiedFilesPage );
rd.forward( req, res );
System.out.println( "Request forwarded to modified files page" );
}

88 ContentServices for TeamSite Cookbook


Displaying a List of Modified Files

The servlet passes the client object to the getModifiedFiles method, then stores the
modified files in a request attribute to be returned with the response. Now for the
getModifiedFiles method, where we can see the real ContentServices SDK work.

Example 23: Getting the Modified Files (GetModifiedFilesServlet.java)

public FileDataBean[] getModifiedFiles(CSClient client)


throws CSException {

this.client = client;

// using a validate flag of false means


// a shallow object is returned if no workarea exists
CSWorkarea wa = client.getWorkarea(waPath, false);

// Get all the modified files in the root of the workarea (no
// recursion, marked by the CS_EXPAND_NONE arg) no matter who
// is the modifier of the files (as indicated by the 'false' arg).
// For now, we will take just the files in the root of the workarea
// because we don't yet have a widget to display browsable folders
// in the JSP page.

CSFile[] modFiles = wa.getModifiedFiles(false, CSArea.CS_EXPAND_NONE);

FileDataBean[] fileData = new FileDataBean[ modFiles.length ];

for (int i=0; i<modFiles.length; i++) {


long fsize = 0;
if (modFiles[i].getKind() == CSSimpleFile.KIND) {
fsize = ((CSSimpleFile) modFiles[i]).getSize();
}
fileData[i] = new FileDataBean(modFiles[i].getName(),
fsize,
modFiles[i].getLastModifier().getName(),
modFiles[i].getContentModificationDate(),
modFiles[i].getVPath().getPathNoServer().toString(),
modFiles[i].getKind());
}
return fileData;
}

Here again, you can see the power and simplicity of the ContentServices SDK. One call to
getWorkarea gets files attributes for the root directory of the user’s workarea (in this case,
the group workarea named demo). Then, one call to getModifiedFiles returns the
modified files.

You can use several variations of getModifiedFiles. This example returns only the
modified files in the root of the workarea (again, because the sample application doesn’t
have a browseable directory widget yet). If you want to return more files, just specify
CSArea.CS_EXPAND_DEFAULT or CSArea.CS_EXPAND_NONE.

89
More on the Sample Application

The last part of this task is for the JSP page to display the modified files, retrieving them
from the request. In this page, all you need to display is the file name.

Example 24: Displaying Modified Files (modified_files_view.jsp)

<c:forEach items="${requestScope.modifiedFiles}" var="current">


<tr>
<td> <input type="checkbox" name="submitFiles"
value="<c:out value="${current.vpath}" />" >

<!-- the c:out tag adds the vpath as a string to the request -->
<!-- we are building an array of vpaths named submitFiles -->
<!-- each vpath starts with /default -->

</td>
<td> <img src="images/fiicon.gif"> </td>
<td> <c:out value="${current.fileName}" /> </td>
<td> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</tr>
</c:forEach>

Once again, the <c:forEach> tag is very useful. The array of modified files is named
modifiedFiles (remember Example 22 on page 88) in the request scope, so the JSTL
expression that retrieves it is ${requestScope.modifiedFiles}. To display the file name,
use <c:out>. The <c:url> tag used as a parameter to the <input> tag sends the file’s vpath
to the next servlet when the user checks that file’s box and clicks Submit.

See Also
„ “Retrieving a User’s Workarea” on page 79 to see how to display the files in the root of
the workarea, especially how to use JSTL tags to work with properties of the files
array

Allowing Direct Submits

Task
You want to allow master users to submit modified files directly to staging, without
workflow approval. Authors and editors are not allowed to submit direct, however. If you
log in as an author or editor in the sample application and try to do this, you will see an
exception.

Solution
This solution involves two JSP pages, a servlet, a value bean, and a utility bean. In
modified_files_view.jsp, a user can select any number of modified files to submit to
staging. The selected list is sent to DispatchSubmitDirectServlet, which calls

90 ContentServices for TeamSite Cookbook


Allowing Direct Submits

DoSubmitDirectBean to do the work of submitting the files to staging. The submit results
are stored as SubmitResultBean objects, which submit_direct.jsp can easily access with
JSTL tags.

Files
modified_files_view.jsp
DispatchSubmitDirectServlet.java
DoSubmitDirectBean.java
SubmitResultBean.java
submit_direct.jsp

Discussion
Most of the work of the direct submit is done on DoSubmitDirectBean. Submitting files
directly to staging from a workarea is relatively easy. However, it requires an array of
CSPathCommentPair objects, each with an area relative path and a comment. Remember
that the area relative path is the part of the vpath after the WORKAREA, STAGING, or
EDITION placeholder:
vpath /default/main/WORKAREA/demo/Report-Cosmetics-Canada.doc
area relative path demo/Report-Cosmetics-Canada.doc

The files the user selects in modified_files_view.jsp are sent as a String array to
DispatchSubmitDirectServlet, which sends them on to DoSubmitDirectBean.
DoSubmitDirectBean performs a series of conversions, converting the String array to a
CSVPath array, then to a CSAreaRelativePath array, then a CSPathCommentPair array.

Example 25: Converting Arrays (DoSubmitDirectBean.java)

// convert the strings to vpath objects


CSVPath[] vpaths = new CSVPath[ values.length ];
for ( int i=0; i<values.length; i++ ) {
vpaths[i] = new CSVPath( values[i] );
}
System.out.println( "strings converted to vpaths" );

// convert the vpath objects to area-relative paths


CSAreaRelativePath[] areaPaths = new CSAreaRelativePath[ vpaths.length ];
areaPaths = CSVPath.extractAreaRelativePaths( vpaths );
System.out.println( "vpaths converted to area relative paths" );

// build a path-comment array


// individual file comments are null
CSPathCommentPair[] pathComments = new
CSPathCommentPair[ areaPaths.length ];
for ( int i=0; i < areaPaths.length; i++ ) {
pathComments[i] = new CSPathCommentPair( areaPaths[i], null );
}
System.out.println("area relative paths converted to path-comment pairs");

91
More on the Sample Application

Once you have the CSPathCommentPair array, you can do the direct submit. With a direct
submit, the method defines whether to overwrite files in staging with versions in the
workarea. All files included in the direct submit are handled the same way.

Example 26: Submitting Directly, Overwriting All Files in Staging

// from the workarea, submit the files


// use OVERWRITE_ALL option
try {
result = wa.submitDirect( comment, null, pathComments,
CSWorkarea.OVERWRITE_ALL );
} catch ( CSException e ) {
throw new CSWebAppException( e );
}
System.out.println( "files submitted directly" );

The result of a direct submit is a CSSubmitResult, from which you can get a CSPathStatus
array or a CSSubmitRecord. Each data type has different information.

CSSubmitResult

CSPathStatus CSSubmitRecord

CSAreaRelativePath comment
primaryStatusCode infoComment
secondaryStatusCode CSEdition
statusMessage
Figure 5: Content of a CSSubmitResul

For the sample application, we are interested in the area relative path and the status
message. These are contained in the CSPathStatus array. We will store them in a
SubmitResultBean, along with the primary and secondary status codes. (Because a

92 ContentServices for TeamSite Cookbook


Allowing Direct Submits

SubmitResultBean is written according to the JavaBeans design patterns, its values can be
easily used in a JSP page with JSTL tags).

Example 27: Storing the Submit Results (SubmitResultBean.java)

.
.
// get the submit status for each path
// each status[i] has a vpath, primary code, secondary code, and message
CSPathStatus[] status = result.getResultOfSubmit();

// create an array of SubmitResultBeans


// it is very easy for the jsp to read from the beans
SubmitResultBean[] submitData = new SubmitResultBean[ status.length ];

// populate the array


for (int i=0; i<status.length; i++) {
submitData[i] = new SubmitResultBean(
status[i].getAreaRelativePath().toString(),
status[i].getPrimaryStatusCode(),
status[i].getSecondaryStatusCode(),
status[i].getStatusMessage() );
}

return submitData;
}

Once the files are submitted, DispatchSubmitDirect stores the submit data in the
response and forwards it to submit_direct.jsp. You can then retrieve the submit data and
display it with JSTL tags.

Example 28: Displaying the Submit Results (submit_direct.jsp)

<!-- display submit results here -->


<c:forEach items="${requestScope.submits}" var="current" varStatus="i">
<tr>
<td class="newsText"> <c:out value="${current.areaRelPath}" /> </td>
<td class="newsText"> <c:out value="${current.message}" /> </td>
<td> &nbsp; </td>
</tr>
</c:forEach>

93
More on the Sample Application

94 ContentServices for TeamSite Cookbook


Appendix A

Working with WSDL Files

Introduction
A WSDL file describes how to access and use a web service, creating an interface between a
web service and its client. WSDL files are written in XML according to the WSDL
specification, with six primary XML elements:

<definitions> The root element

<types> Describes the data types the web service uses

<message> Describes the messages sent to a web


service; similar to method parameters

<portType> Describes the web service and what it does;


similar to methods in a class

<binding> Describes the message format and protocol


details used to transmit messages

<service> Gives the location of the web service

Figure 6: The Structure of a WSDL File

In the ContentServices SDK, WSDL files perform several important functions:

„ They define how method calls made in Java or any other language are translated before
they are packaged into the SOAP envelopes sent to and from the ContentServices web
service.
„ They are used in development tools to generate web service client stubs in various
languages such as C#, VB.Net, or Perl. Any client can instantiate the stub to call the
web service.
„ They are used in WSDL invocation tools to automatically invoke a web service using a
command or short script.

95
Working with WSDL Files

WSDL

Generator Tool Web Service

Client
Stub

Client Application

Figure 7: Using a Web Service Client Stub

The ContentServices SDK has six WSDL files, structured according to the packages in the
Java client interface. Each WSDL has a URL specified in its <service> element. The URL
locates the WSDL in order to generate the client stub or invoke the web service.

Note: If you changed the HTTP port from 80 to another port number when you installed
the TeamSite server, use your HTTP port number in the URL.
Table 1: The ContentServices SDK WSDL Files

Name Location
AccessService.wsdl http://tsServer:80/iw/services/cm/2.0/
accessservice
contentservices.wsdl http://tsServer:80/iw/services/cm/2.0/
contentservices/ContentServices.wsdl
FileSys.wsdl http://tsServer:80/iw/services/cm/2.0/fileservice
Types.wsdl no URL
Util.wsdl http://tsServer:80/iw/services/cm/2.0/utilservice
Workflow.wsdl http://tsServer:80/iw/services/cm/2.0/
workflowservice

The file contentservices.wsdl is the base WSDL file that describes the entire
functionality of the ContentServices SDK. You can point tools to its URL to create stubs
(see “Generating and Using a C# Client Stub” on page 98 for details). The other WSDL files
describe services that are part of the ContentServices SDK.

In a WSDL file, the <wsdl:portType> element describes the web service as a whole and is
similar to a class. The <wsdl:message> element specifies the requests the web service
receives and the responses it sends back.

96 ContentServices for TeamSite Cookbook


Introduction

Suppose your application accepts login information to authenticate a user on the TeamSite
server. Your application would call the getClient method in CSFactory or one of its
subclasses.

Example 29: Declaring getClient in the Java Interface

public CSClient getClient( String name,


String role,
String password,
Locale locale,
String appContext,
String server)
throws
CSAuthenticationException,
CSRemoteException,

CSInvalidRoleException,

The corresponding WSDL file, AccessService.wsdl, has a <portType> and nested


<operation> elements that define how a call to getClient is sent to the web service.

Example 30: Defining beginSessionUsingPassword

<wsdl:portType name="AccessService">
...
<wsdl:operation name="beginSessionUsingPassword"
parameterOrder="userName roleName password locale appContext
serverName">

<wsdl:documentation>
Begin a CSSDK session using the specified credentials.
</wsdl:documentation>

<wsdl:input message="impl:beginSessionUsingPasswordRequest"/>
<wsdl:output message="impl:beginSessionUsingPasswordResponse"/>
<wsdl:fault message="impl:CSException" name="CSException"/>

</wsdl:operation>
...
</wsdl:portType>

The <operation> element defines an input message, an output message, and what happens
if an exception is thrown. Note that the parameter order is the same as in the method
declaration for getClient.

97
Working with WSDL Files

The <wsdl:message> element, earlier in the WSDL file, describes each parameter sent to
beginSessionUsingPassword (remember—it’s the WSDL equivalent of getClient).

Example 31: Defining beginSessionUsingPasswordRequest

<wsdl:message name="beginSessionUsingPasswordRequest">
<wsdl:documentation>
Begin a CSSDK session using the specified credentials.
</wsdl:documentation>

<wsdl:part name="userName" type="xsd:string">


<wsdl:documentation>
User id recognized by the Teamsite server.
</wsdl:documentation>
</wsdl:part>

<wsdl:part name="roleName" type="xsd:string">


<wsdl:documentation>
Role of the user.
</wsdl:documentation>
</wsdl:part>

<wsdl:part name="password" type="xsd:string"/>


<wsdl:part name="locale" type="xsd:string"/>

<wsdl:part name="appContext" type="xsd:string">


<wsdl:documentation>
A string unique to the application requesting authentication.
</wsdl:documentation>
</wsdl:part>

<wsdl:part name="serverName" type="xsd:string">


<wsdl:documentation>
Hostname of the Teamsite server.
</wsdl:documentation>
</wsdl:part>
</wsdl:message>

Generating and Using a C# Client Stub

Task
You want to write a C# program to do something with the ContentServices SDK, say,
retrieve the branches in a store.

Solution
You first need to generate a C# client stub from the ContentServices SDK and then write a
short C# program to run against it. The examples used in this section are in
samples\dotnet.

98 ContentServices for TeamSite Cookbook


Generating and Using a C# Client Stub

Discussion
This requires installing the Microsoft .NET framework SDK and a C# compiler. The C#
compiler is named csc.exe and is bundled with the .NET SDK. However, on Windows,
csc.exe might be stored in a location outside the main .NET SDK.

Before you generate the client stub, install TeamSite 6 and the ContentServices SDK
according to the instructions in quick_install_dotnet.html in the samples zip file.

Now you are ready to generate a C# client stub for the ContentServices SDK. Use the wsdl
command that is included with the .NET framework on ContentServices.wsdl, the main
WSDL file that imports the other WSDL files. For convenience, this command is part of a
makefile in the samples, make.cmd.

The wsdl command that generates the C# stub is:

wsdl /n:com.interwoven.cssdk /o:cssdk.cs


http://localhost/iw/services/cm/2.0/contentservices/ContentServices.
wsdl

You may need to edit the port number in make.cmd so that the command can locate the
WSDL file, for example:

... http://localhost:80/iw ...

Running this command generates cssdk.cs, the C# client stub. The next step is to compile
GetBranches.cs, the sample C# source file. The command to do this, also in make.cmd,
is:

csc /target:exe cssdk.cs GetBranches.cs

This command compiles GetBranches.cs to GetBranches.exe, using the stub cssdk.cs.


Once you have GetBranches.exe, you can run it, giving it a username, password, role, and
server name, to retrieve branches. To run the executable (and summarize the last few
paragraphs), do this:
1. Install TeamSite 6 and the ContentServices SDK according to
quick_install_dotnet.html.

2. Create a directory on your computer for running the .NET samples.


3. Copy the files in samples\dotnet to that directory.
4. If needed, edit the wsdl command in make.cmd. You may need to update the HTTP
port number, if you changed it from 80 to another port during installation.
5. Open a command window.
6. Enter make to generate cssdk.cs and compile GetBranches.exe. (Do it anyway, even
if cssdk.cs and GetBranches.exe already exist in that directory).

99
Working with WSDL Files

7. Run the GetBranches C# executable:


GetBranches username password role serverName http://serverName
GetBranches returns a list of branches it retrieves, something like this:
/default/main/branch1
/default/main/branch2
/default/main/branch1/subbranch1
/default/main/branch1/subbranch2

You can find GetBranches.cs in the samples zip file.

100 ContentServices for TeamSite Cookbook


Appendix B

Status Codes

This appendix contains status codes returned by the ContentServices SDK and TeamSite
Content Server. These are the codes returned by CSException.getErrorCode.

In general, an error code of 0 means Success, and all other codes indicate some type of
exception.

101
Status Codes

TeamSite Server Error Codes

0 = Success
1 = Generic failure
2 = No such file or directory
3 = No such process
4 = Interrupted system call
5 = I/O error
6 = No such device or address
7 = Arg list too long
8 = Exec format error
9 = Bad file number
10 = No children
11 = Resource temporarily unavailable
12 = Not enough core memory
13 = Permission denied
17 = Workarea, edition or branch already exists
20 = Directory expected, but wasn't one
21 = Directory not expected, but is a directory
22 = Invalid argument
28 = Insufficient space to complete operation
30 = Read-only file system
41 = Link number out of range
42 = Protocol driver not attached
43 = No CSI structure available
44 = Level 2 halted
45 = Resource deadlock condition
46 = No record locks available.
47 = Operation canceled
48 = Operation not supported
71 = Protocol error
132 = No buffers available
151 = Stale file handle
301 = Not super-user
480 = Authentication error
691 = Version number mismatch
905 = Function not yet implemented
910 = Buffer is too small for output
911 = String argument is too long
920 = Object being looked up was not found
921 = Task not done
925 = No such user
930 = RPC connection failure
980 = No authentication was done
981 = No authorization was done
999 = "No" is the response
2000 = Iteration ended
2001 = No iteration entry
2003 = No base edition for workarea create
2004 = No server found
2005 = No archive found
2006 = No branch found
2007 = No workarea found
2008 = No edition found
2009 = No fse found
2010 = No previous fse found
2011 = Workarea directory not found

102 ContentServices for TeamSite Cookbook


2012 =
Edition directory not found
2013 =
No staging area found
2014 =
No operation found
2015 =
No tag found
2016 =
Conflicts prevent publishing of edition
2017 =
Checked out files prevent publishing
2018 =
Workarea does not match branch
2019 =
Cannot destroy last remaining ed on br
2100 =
Illegal name given
2150 =
Illegal operaton on private fse
2200 =
No such role
2300 =
Illegal operator
2301 =
No such attribute
2302 =
Bad attribute key specified
2303 =
Attribute key exceeds size limit
2304 =
Attribute value exceeds size limit
2400 =
Object is being reserved by someone else
2401 =
Fse is the same as other fse
2402 =
Fse is newer than other fse
2403 =
No update performed
2404 =
No submit performed
2405 =
Cmprs'n WA/STGN, or latest ED not allowed
2406 =
Already compressed
2407 =
Already uncompressed
2408 =
More than one branch found
2409 =
More than one workarea found
2410 =
No such group
2411 =
File had been deleted
2412 =
Assigned files prevent submitting
2413 =
Must be author.
2414 =
Fse is older than other fse
2415 =
Not owner or member of workarea
2416 =
Operation aborted
2417 =
Fse is a deletion of the other fse
2418 =
Role is not authorized for this user
2419 =
Wrong username/password
2420 =
Domain does not exist
2421 =
Staging area directory not found
2422 =
No such teamsite user
2423 =
Different areas
2424 =
No changes since last publish
2425 =
Bad workflow query string.
2426 =
Operation needs an active object.
2427 =
Operation needs an inactive object.
2428 =
Object is read only.
2429 =
Task is not a start task.
2430 =
Object is inconsistent.
2431 =
Already being compressed
2432 =
Already being uncompressed
2433 =
Account restricted (NT only)
2434 =
Cannot logon at this time (NT only)
2435 =
Password has expired (NT only)
2436 =
This account is disabled (NT only)
2437 =
Password must be changed before logging in the first time
(NT only)
2438 = The account was locked out (NT only)
2439 = Operation not permitted.
2440 = Operation already in progress

103
Status Codes

2441 = Invalid license


2442 = Limit exceeded
2443 = TeamXML file prevents operation

ContentServices SDK Error Codes


5001 = Unknown error in JNI translation (not used)
5002 = Error in message catalog
5003 = Error thrown in the Java layer (not used)
5004 = Invalid session string
5005 = Templating configuration error
5006 = Invalid input
5007 = DCR ID error
5008 = Null pointer error
5009 = Configuration property not set
5010 = Factory initialization error (not used)
5011 = Could not create session string
5012 = Invalid VPath
5013 = Revision string could not be created
5014 = Invalid revision string
5015 = Session string has expired
5016 = Error looking up entity in EDB
5017 = Overwrite failed
5018 = Unsupported JNI class (not used)
5019 = Out of memory
5020 = Empty String found, but not expected
5021 = Negative integer passed but not expected
5022 = Invalid offset
5023 = Operation not permitted on task
5024 = Source and destination for compare are the same
5025 = Source and destination are the same
5026 = Source is a parent of the destination
5027 = Destination should be in same area but was not
5028 = Operation could not be performed in local mode
5029 = Unsupported operation
5030 = Compare to invalid VPath
5031 = File is already locked
5032 = Failed to get files for a task
5033 = Could not open property file
5034 = Could not read property file
5035 = Bad value in property file
5036 = Incorrect VPath type
5037 = Action failed because store is frozen
5038 = Only a simple file is allowed for this operation
5039 = Only a directory is allowed for this operation
5040 = Only a simple file or a directory is allowed for this operation
5041 = Only area-relative paths are allowed for this operation
5042 = Field not in query (not used)
5043 = File not attached to task
5044 = Invalid job specification
5045 = Invalid SOAP license key
5046 = Object Not writeable
5047 = Null or empty VPATH encountered but not permitted
5048 = Couldn't contact the CS server.

104 ContentServices for TeamSite Cookbook


105
Status Codes

106 ContentServices for TeamSite Cookbook


Appendix C

Mapping ContentServices 1.1 to 2.5

You can use this document as a starting point to map ContentServices SDK 1.1 methods to
ContentServices SDK 2.5.

Because the new ContentServices SDK has been rearchitected from the ground up, some of
the old methods might not have direct equivalents. Instead, you might need to use a
combination of several methods in the new SDK.

There are six packages in the new Java client interface: access, common, factory,
filesys, util, and workflow. Please see the Javadoc for complete method signatures.

IWPortalClient Method ContentServices 2.0 SDK Method

addTaskComment workflow.CSTask.addComment

addTaskFileComment workflow.CSTask.addFileComment

addTaskFiles workflow.CSTask.attachFiles

createWorkflow workflow.CSWorkflowEngine.createWorkflow

deleteFiles filesys.CSWorkarea.deleteFiles

editFile util.CSUrlsHelper.getFileUrls

endSession common.CSClient.endSession

finishTask workflow.CSTransitionableTask.chooseTransition

getCredentials common.CSClient.getContext

107
Mapping ContentServices 1.1 to 2.5

IWPortalClient Method ContentServices 2.0 SDK Method


getDirectoryContents filesys.CSDir.getFiles,
filesys.CSArea.getFiles(
CSAreaRelativePath[] filePaths)

getExtendedAttributes For small EAs:


filesys.CSSimpleFile.getExtendedAttributes

For searching:
filesys.CSSimpleFile.getExtendedAttributeNames

For large EAs:


filesys.CSSimpleFile.
getExtendedAttributeInputStream

getFile common.CSClient.getFile

getFiles filesys.CSArea.getFiles(
CSAreaRelativePath[] filePaths)

getModifiedFiles filesys.CSWorkarea.getModifiedFiles
filesys.CSDir.getModifiedFiles

getTaskById workflow.CSWorkflowEngine.getTask
common.CSClient.getTask

getTasksById workflow.CSWorkflowEngine.getTasks

getTasks workflow.CSWorkflowEngine.getTasksByQuery

getTemplateCategories util.CSTemplating.getTemplateCategories

getWebDeskNewDcrHelper util.CSTemplating.getWebDeskNewDcrHelper

importFiles util.CSUrlsHelper.getImportFilesUrl

isLoggedIn common.CSClient.isValid

108 ContentServices for TeamSite Cookbook


IWPortalClient Method ContentServices 2.0 SDK Method
lockFiles filesys.CSFile.lock,
filesys.CSWorkarea.lockFiles

ping factory.CSFactory.getServerVersion
Not an exact comparison, but serves the same purpose.
getServerVersion does not require any authorization or
authentication.

readFile filesys.CSSimpleFile.read
filesys.CSSimpleFile.getInputStream

removeTaskFiles workflow.CSTask.detachFiles

setExtendedAttributes For small EAs:


filesys.CSSimpleFile.setExtendedAttributes

For large EAs:


filesys.CSSimpleFile.
getExtendedAttributeOutputStream

submit util.CSUrlsHelper.getSubmitFilesUrl

submitDirect filesys.CSWorkarea.submitDirect

undoChanges filesys.CSWorkarea.update

unlockFiles filesys.CSWorkarea.unlockFiles

update filesys.CSWorkarea.update

uploadFiles util.CSUrlsHelper.getUploadFilesUrl

writeFile filesys.CSSimpleFile.write,
filesys.CSSimpleFile.getOutputStream

109
Mapping ContentServices 1.1 to 2.5

110 ContentServices for TeamSite Cookbook

Você também pode gostar