Content Management Guide
CHAPTER 2
This chapter describes how to set up and manage the infrastructure for the Content Management (CM) subsystem using the CM API. It has these sections:
NOTE: This chapter describes an exteNd Director API that allows you to build your own CM application. exteNd Director also provides the CMS Administration Console, which you can use to create, maintain, administer, and secure all content for your exteNd Director application.
For more information, see Setting Up the Required Infrastructure and Setting Up the Optional Infrastructure.
You can use the CM API to build a system tailored to your business process. By writing portlets, you can build a complete interface that includes such functionality as:
The CM API provides complete programmatic access to the document repository.
Methods of the EbiContentMgmtDelegate interface provide access to the most of the objects in the CM subsystem.
For all the examples in this chapter, you must use this code somewhere in your portlet to get a reference to the content manager delegate:
EbiContentMgmtDelegate defaultCmgr = com.sssw.cm.client.EboFactory.getDefaultContentMgmtDelegate(); if (cmgr != null) ... // do content-related processing else System.out.println("Failed to get Content Manager");
Using delegates Delegates are objects that provide a layer of abstraction for main exteNd Director manager objects (such as the Content Manager object). Using delegates removes the need for coding things like local and remote access to exteNd Director services.
From a best-practices standpoint, you should always use delegates rather than accessing exteNd Director manager objects directly.
In the simplest case, the basic procedure for working with objects in the repository is:
Use a get method of EbiContentMgmtDelegate to get an object from the repository.
Use an update method of EbiContentMgmtDelegate to put the changed object back in the repository, or use the update method on the object itself if it is available.
Some objects are more complex. The rest of this chapter describes how to work with many of these objects, with code examples.
Before creating documents in the CM subsystem, you must set up the content infrastructure, which includes the criteria by which you organize the documents. The infrastructure includes fields, document types, layout styles, folders, and categories:
All documents have a basic set of metadata, such as title, author, abstract, published version, and so on. You can also define custom metadata fields to store application-specific data for each document type. Fields are appropriate for any piece of data for which all the documents have a value. For example, movie reviews have a director, cast, release date, and rating. Books have an author, publisher, publish date, and number of pages. Reviews of travel destinations have country, cost category, and quality rating.
Fields are also useful for finding documents. For each document type, a set of fields identify the pertinent, searchable information for the subject matter of that document type. Fields can be searched quickly via a database lookup, in contrast to searching the document content text.
For example, for a document type of MovieReview, you might create several fields as shown below:
NOTE: In this example, Genre and Runtime could have multiple values.
Data types EbiDocField defines several data types to be used for fields. This table categorizes the available types:
Metadata for fields You already know that fields store metadata about a document. You can also store data about the field itself. You can use this extension metadata to store a list of appropriate values, a prompt to use in forms, an image for the field, or other information appropriate to your application. The data is a byte array.
Fields and document types When you create a document type, you specify the set of fields it uses. You can use a field with more than one document type.
Fields and values For each document of a particular document type, all the associated fields must have at least one value, specified via an EbiDocExtnMetaInfo object. The value can be null. You assign the field values to the document as a set via an EbiDocExtnMeta object. EbiDocExtnMeta holds an EbiDocExtnMetaInfo object for each field associated with the document type. You call getFieldValues() to get an array of values for a field. The values can be returned as Strings, or they can have the field's data type.
These methods in EbiContentMgmtDelegate let you add and modify fields:
For information about using fields with document types, see Managing document types.
This example provides a method called addField() that adds an extension metadata field:
public void addField(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { String fieldName = "Rating"; String valueType = EbiDocField.FT_STRING; String extnMeta = "This is a Rating field..."; cmgr.addDocumentField( context, // Context fieldName, // Field name valueType, // Value data type extnMeta.getBytes(), // Extension metadata null); // ACL }
This example shows how to add a field to a portlet's processAction(0 method. It gets the name and data type the user entered in an HTML form and adds a field. A message about success or failure is stored in the context object to be displayed when the portlet content is generated.
public void processAction (ActionRequest request, ActionResponse response){ String name = request.getParameter(FORM_NAME); String datatype = request.getParameter(FORM_DATATYPE); String valuelist = request.getParameter(FORM_LIST); EbiContentMgmtDelegate cmgr = ...; // get content manager try { cmgr.addDocumentField(context,name,datatype,valuelist,null); context.setValue( this.getPortletName() + KEY_STATUS, "Field " + name + " successfully added."); } catch (Exception e) { context.setValue( this.getPortletName() + KEY_STATUS, "Field " + name + " not added."); } }
This example provides a method called listFields() that gets existing document fields by filtering the results in different ways.
The listFields() method needs to have access to a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments. The context object provides information about the user's security privileges. The listFields() method passes the context object to the getFilteredDocumentFields() method to return only those fields for which the user has READ access:
public void listFields(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { // Get all the existing fields (note: no security checking is done here) Collection allFields = cmgr.getDocumentFields(context); Iterator iterAllFields = allFields.iterator(); while (iterAllFields.hasNext()) { EbiDocField field = (EbiDocField)iterAllFields.next(); System.out.println(field + "\n\n"); } // Get all the fields that belong to doctype 'MovieReview' EbiDocType docType = cmgr.getDocumentTypeByName(context,"MovieReview"); Collection docTypeFields = cmgr.getDocumentFields(context,docType.getDocTypeID()); // Get all the fields to which the user has Read access Collection filteredFields = cmgr.getFilteredDocumentFields(context); // Get all the Read-accessible fields that belong to doctype 'MovieReview' Collection filteredDtFields = cmgr.getFilteredDocumentFields(context, docType.getDocTypeID()); }
A document type identifies a particular type of content. Typically, you create document types for groups of documents that have similar content. The documents share the same set of fields that describe that content and, for XML content, the same layout styles to display the content.
After you have created a document type, you can modify its name and description. To do so, get an EbiDocType object, call setDocTypeName() or setDescription(), then call updateDocumentType() to put the changed type back into the content repository.
TIP: You can also associate layout styles with the document type. For information, see Managing layout styles.
These methods in EbiContentMgmtDelegate let you add and modify document types:
These methods of EbiContentMgmtDelegate manage the association between document types and fields:
This example provides a method called addDocType() that adds a document type called Movie Review and associates it with several existing fields. The addDocType() method needs to have access to a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments.
public void addDocType(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { // Get several fields by name EbiDocField fldDir = cmgr.getDocumentFieldByName(context, "Director"); EbiDocField fldGenre = cmgr.getDocumentFieldByName(context, "Genre"); EbiDocField fldYear = cmgr.getDocumentFieldByName(context, "Year"); EbiDocField fldCast = cmgr.getDocumentFieldByName(context, "Cast"); // Get the field IDs String[] fieldIDs = { fldDir.getFieldID(), fldGenre.getFieldID(), fldYear.getFieldID(), fldCast.getFieldID() }; // Add the doctype EbiDocType dt = cmgr.addDocumentType( context, // Context "Movie Review", // Doctype name "Movie Review document type", // Description fieldIDs, // Associated fields null); // ACL for the doctype System.out.println("The new doctype: " + dt); }
Layouts are XSL specifications for rendering a document. The document might be XML or some other format that can be processed by XSL. The actual layout specification is stored as the content of a document in the repository. The CM subsystem has a document type called Document Layout already installed for layout documents. You can use it or add your own document types for layouts.
What you can do After you have added a layout document, you can check it out, modify it, and check it in. That means a particular layout document can have multiple versions. You can publish one of those versions.
You can group several layouts together under the umbrella of a layout style. The various layouts in the layout style can handle the rendering of the document for different clients (also called user agents), such as browsers, PDAs, and other display devices. The association of a layout document with a user agent is handled by a layout document descriptor.
Layout styles and document types A layout style is associated with a document type. When you display a document of that type, the system searches the layout document descriptors in the style to find the one for the user agent, as specified in the portlet's context object.
A layout style with multiple layout document descriptors can process content for various clients. When you want to display a document of the particular document type, you call getDocumentLayout(); the system gets the current user agent from the context object to select the appropriate layout.
Here is the group of objects that provide XSL processing for a content document:
NOTE: In addition to layout styles for document types, you can define a layout set for a specific document. A layout set is a custom combination of layout documents for a single content document. This specialized functionality is appropriate for special types of documents. When you are producing many documents of the same type, you will typically stick with layout styles for the document type. For more information, see Specifying layout sets for documents.
To set up layout styles for a document type:
Add one or more layout styles for the content document type.
Specify one of the styles as the default for that document type.
Add one or more layout documents whose XSL is designed for the expected content. The versions can arrange the content differently or tailor the content for different clients.
Add layout document descriptors that tie the layout documents to a client and a layout style.
These methods in EbiContentMgmtDelegate let you add and modify layout styles and their associated objects:
A user agent identifies itself in the HTTP header it sends to the server. exteNd Director stores the identifying string in the context object. The string used by a browser varies according to the browser version. Here are some examples:
User Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) User Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT) User Agent: Mozilla/4.5 (Macintosh; U; PPC) User Agent: Mozilla/4.7 [en] (WinNT; I) User Agent: Mozilla/3.0 (compatible; Opera/3.0; Windows 95/NT) 3.1
You will need to use these strings in EbiLayoutDocumentDescriptor objects.
For more information on user agents, see the HTTP 1.1 specification.
This example provides a method called addLayoutStyle() that adds a layout style for a document type called Movie Review. The addLayoutStyle() method needs to have access to a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments:
public void addLayoutStyle(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { // Get the doctype for which the style is to be added EbiDocType dtMovieReviews = cmgr.getDocumentTypeByName(context, "Movie Review"); // Add the new style EbiDocLayoutStyle style = cmgr.addDocumentLayoutStyle( context, // Context dtMovieReviews.getDocTypeID(), // Doctype ID "MovieReviewStyle-PicOnLeft", // Style name "Layout style for movie reviews, with pic on left", // Style descr true, // Is default style null); // ACL for style System.out.println("The new style: " + style); }
This example provides a method called addLayoutDocAndDescriptor() that adds a layout document and a layout descriptor. The layout descriptor associates the layout document with the layout style from the previous example. The addLayoutDocAndDescriptor() method needs to have access to a content manager (EbiContentMgmtDelegate), context object (EbiContext), layout file name, and layout style, which are passed in as arguments:
public void addLayoutDocAndDescriptor( EbiContentMgmtDelegate cmgr, EbiContext context, String layoutFileName, String layoutStyleID) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException, FileNotFoundException, IOException { // Read in the XSL for the layout FileInputStream fis = new FileInputStream(layoutFileName); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] value = new byte[4096]; while (true) { int bytes = fis.read(value); if (bytes < 1) break; baos.write(value, 0, bytes); } byte[] content = baos.toByteArray(); baos.close(); // Get the document layout doctype EbiDocType dtLayout = cmgr.getDocumentTypeByName(context, "Document Layout"); // Get the Layouts folder EbiDocFolder layoutFolder = (EbiDocFolder)cmgr.lookupDirectoryEntry( context, "MyApp/Layouts", EbiDocFolder.EL_DOC_FOLDER); // Add the layout document EbiAddDocumentParams params = cmgr.createAddDocumentParams(); params.setName("ReviewLayout-POL"); params.setDocTypeID(dtLayout.getDocTypeID()); params.setFolderID(layoutFolder.getID()); params.setAuthor("JSmith"); params.setTitle("ReviewLayout-POL"); params.setSubtitle("This is the layout with picture on left"); params.setMimeType("text/xsl"); params.setContent(content); params.setComment("Initial revision."); // params.setAcl(...); specify an ACL, otherwise inherit ACL of parent folder EbiDocument layoutDoc = cmgr.addDocument(context, params); System.out.println("New layout doc: " + layoutDoc); // Publish the new layout document cmgr.publishDocumentContentVersion(context, layoutDoc.getID(), 1, true, true); // Figure out what user agent this layout is intended for String userAgent = "User Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)"; // Associate the new layout document with the specified layout style EbiLayoutDocDescriptor ldd = cmgr.addLayoutDocumentDescriptor( context, // Context layoutStyleID, // Layout style ID layoutDoc.getID(), // Layout document ID userAgent); // User agent }
This example presents a method called changeLayoutStyle() that gets the default style for a document type and changes it so that it is not the default. The changeLayoutStyle() method needs to have access to a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments:
public void changeLayoutStyle(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { EbiDocType dtMovieReview = cmgr.getDocumentTypeByName(context, "MovieReview"); EbiDocLayoutStyle style = cmgr.getDefaultDocumentLayoutStyle(context, dtMovieReview.getDocTypeID()); style.setDefault(false); cmgr.updateDocumentLayoutStyle(context, style); }
Folders and categories are ways of organizing documents. A document belongs to one folder and can belong to many categories. Typically, you would use folders to group documents for administrative purposes, such as all documents for a project or documents that have access restrictions. You can use categories to organize documents as an end user might view them, typically by subject matter.
The system has a root folder and root category already createdcalled Root Folder and Root Category. The content manager provides the getRootFolder() and getRootCategory() methods to get EbiDocFolder and EbiDocCategory objects for them.
The default directory type for folders and categories is EbiDirectory.DIR_TYPE_DEFAULT. The root and system types apply to the root folder and root category. You can also define your own folder types. For information, see EbiDirectory in the API Reference.
These methods of EbiContentMgmtDelegate let you manage folders and categories:
This example presents a method called addCategory() that gets the information required for creating a new category, then adds the new category as a subcategory of the specified parent. The addCategory() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments:
public void addCategory(EbiContentMgmtDelegate cmgr, EbiContext context) throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException { // Locate the parent category EbiDocCategory categParent = (EbiDocCategory)cmgr.lookupDirectoryEntry( context, "MyApp/Shopping", EbiDocCategory.EL_DOC_CATEGORY); EbiDocCategory categChild = cmgr.addCategory( context, // Context categParent, // Parent category "Clothing", // Tew category name EbiDirectory.DIR_TYPE_DEFAULT, // type of the new category "This is the clothing-related category", // Description null); // ACL for the new category System.out.println("New category added: " + categChild);
Once your directory hierarchy is established, you can get a listing of the contents of a directory and examine the properties of individual entries.
This section describes some ways to use the methods and classes that navigate the directory hierarchy. Both categories and folders implement the functionality for directory manipulation found in their superinterface EbiDirectory. Folders, categories, and documents also implement EbiDirectoryEntry and share methods for getting information about the contents of a directory.
Methods These methods are useful in navigating categories and folders:
getRootCategory() and getRootFolder() of EbiContentMgmtDelegate get the top of a directory hierarchy.
getDirectoryList() and getFilteredDirectoryList() of EbiContentMgmtDelegate return a collection of EbiDirectoryEntry objects. You can specify whether the list includes subdirectories, documents, or both.
isDirectory() of EbiDirectoryEntry reports whether an entry is a directory or a document.
lookupDirectoryEntry() of EbiContentMgmtDelegate gets an EbiDirectoryEntry object for a category, folder, or document based on a path built from the names of the parent objects in the hierarchy.
getEntry() of EbiContentMgmtDelegate gets an entry by name in the specified directory.
Example This example builds an XML DOM tree of nested categories, starting with the root category. The root category is a category element within Categories; subcategories of the root and further nested levels are category elements also. The name and ID for each category are attributes.
The code creates the Categories container element and gets the root category of the tree you want to build. It then calls addNode() to find and add its subcategories. The variable dom is the DOM object and root is the root element of the DOM.
Element categories = dom.createElement("Categories"); root.appendChild(categories); EbiDocCategory category = cmgr.getRootCategory(context); if (category == null) System.out.println("root category is null"); else { Element rootCategory = dom.createElement("category"); categories.appendChild(rootCategory); rootCategory.setAttribute("id", category.getID()); rootCategory.setAttribute("name", category.getName()); addNode(rootCategory, category, dom, context, cmgr, "category"); }
The addNode() method gets the subcategories of a particular category and adds them as child elements. It is called recursively to add additional levels of nested subcategories if they exist:
public void addNode(org.w3c.dom.Element element, EbiDirectoryEntry directoryEntry, org.w3c.dom.Document document, EbiContext context, EbiContentMgmtDelegate cmgr, String elementName) { try { Collection collection = cmgr.getFilteredDirectoryList( context, (EbiDirectory) directoryEntry, true, false); Enumeration list = Collections.enumeration(collection); if (list != null) { Element child; while (list.hasMoreElements()) { EbiDirectoryEntry subdirEntry = (EbiDirectoryEntry) list.nextElement(); child = document.createElement(elementName); child.setAttribute("id", subdirEntry.getID()); child.setAttribute("name", subdirEntry.getName()); element.appendChild(child); addNode(child, subdirEntry, document, context, cmgr, elementName); } } } catch (Exception e) { e.printStackTrace(); } }
Copyright © 2004 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved. more ...