|
Content Management Guide |
This chapter describes the Director Content Management subsystem from a programmer's viewpoint. It covers:
TIP This chapter describes a Director API that allows you to build your own content management application. Director also provides the Portal Management Console (PMC), which you can use to create, maintain, administer, and secure all content for your Director application.
You can use the Content Management API to build a system tailored to your business process. By writing components, you can build a complete interface that includes such functionality as:
The Content Management API provides complete programmatic access to the document repository.
Several components that access the document repository come with Director. You can use the discussion board and document viewer in your Director application. Their source code can serve as a starting point for your own components.
Methods of the EbiContentMgmtDelegate interface provide access to the most of the objects in the Content Management subsystem.
For all the examples in this chapter, you must use this code somewhere in your component 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 Director manager objects (such as the Content Manager object). Using delegates removes the need for coding things like local and remote access to Director services.
From a best practices standpoint, you should always use delegates rather than accessing 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 Content Management 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:
|
Field name |
Data type |
Sample value |
|---|---|---|
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:
|
Type of data |
Available data types defined in EbiDocField |
|---|---|
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.
Adding a field 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
}
Adding a field in the processRequest() method This example shows how to add a field in the processRequest() method of a component. 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 getComponentData() generates content.
public void processRequest( EbiPortalContext context,
java.util.Map params )
{
String name = req.getParameter(FORM_NAME);
String datatype = req.getParameter(FORM_DATATYPE);
String valuelist = req.getParameter(FORM_LIST);
EbiContentMgmtDelegate cmgr = ...; // get content manager
try
{
cmgr.addDocumentField(context,name,datatype,valuelist,null);
context.setValue(
context.getComponentInfo().getComponentClassName(),
KEY_STATUS,
"Field " + name + " successfully added.");
}
catch (Exception e)
{
context.setValue(
context.getComponentInfo().getComponentClassName(),
KEY_STATUS,
"Field " + name + " not added. " + e.toString() );
}
}
Listing fields using different filters 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.
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:
Adding a document type with associated 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 Content Management 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.
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.
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 component's context object.
A layout style with multiple layout document descriptors can process content for various clients (also called user agents). When you want to display a document of the particular document type, you call getDocumentLayout() and the system will get 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. 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.
Adding a layout style 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);
}
Adding a layout document and layout document descriptor 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
}
Changing a layout style This 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 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", // new 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);
}
A document in the Content Management subsystem may represent a simple, finite piece of content such as an image, or it may be a complex entity that comprises other documents. A document can be any data that you want to use directly or indirectly in your Director application. For ideas on the different types of information that can be documents, see Content and documents.
The Content Management subsystem uses metadata fields to describe a document. There are standard fields for every document, such as name, title, author, and abstract. You can also associate content-related fields with a document type. This extension metadata can hold additional searchable information specific to that document type.
A document object can be associated with an EbiDocContent object that holds the text or binary data, but a document doesn't need to have a content object. The metadata for the document may store all the information you need. For a short text document, you could store the entire text in the abstract field. If the document doesn't have content, specify null for the MIME type and content.
The supplied content, if any, becomes the first version of the document. If you want to publish the content, you can call publishDocumentContentVersion() anytime or rely on your scheduled task to publish it. Documents without content cannot have versions (including a published version), but you could use another field, such as status, to label a document as publicly available.
To add a document, you create an EbiAddDocumentParams object and set various parameters. The next table explains the default values for the required parameters: name, document type, folder, and extension metadata, if anyas well as other parameters for which the default value has a particular meaning. Any other metadata fields that aren't explicitly set are null:
|
Parameter |
Description and default values |
|---|---|
A name for the document, used when specifying a path for the document in the folder structure. The default name is the UUID assigned to the document when it is added. | |
The ID of the document type for this document. The default is the system's Default document type. | |
The folder that contains this document. The default is the system's root folder. | |
If the document belongs to a document type that has at least one associated extension metadata field, you must call the setExtensionMetaData() method to provide values for the fields.
| |
A timestamp specifying when the document's current version should be published. The default value of null means publish as soon as possible. | |
A timestamp specifying when the document should be removed from the published area. The default value of null means never expire. | |
An ACL specifying access rights to the document. The ACL is null by default. In this case, the document inherits the ACL of its folder. If the folder doesn't have an ACL, there are no restrictions for the document. |
The following code examples show how to add single or multiple documents to the Content Management subsystem.
Adding a document This example presents a method called addDocument() that illustrates how to add a document of type Movie Review. This method sets all required document parametersdocument type, name, title, author, and parent folderas well as some optional parameters.
The new document does not contain extension metadata fields, nor does it have a parent document. The addDocument() method sets the content of the new movie review document explicitly and stores it in the byte array content.
The addDocument() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments.
Note that the addDocument() method does not set the ACL for the new document. This means that the ACL is null and the document inherits the ACL of its folder.
public void addDocument(EbiContentMgmtDelegate cmgr, EbiContext context)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
// Get the doctype
EbiDocType type = cmgr.getDocumentTypeByName(context, "Movie Review");
// Get the folder
EbiDocFolder folder = (EbiDocFolder)cmgr.lookupDirectoryEntry(
context, "MyApp/MovieReviews/Current", EbiDocFolder.EL_DOC_FOLDER);
// Get the content
String movieContent = "This movie has exceeded all expectations!....";
byte content[] = movieContent.getBytes();
EbiAddDocumentParams docParams = cmgr.createAddDocumentParams();
docParams.setName("Star Trek Movie Review");
docParams.setDocTypeID(type.getDocTypeID());
docParams.setFolderID(folder.getID());
docParams.setAuthor("Night Ghost");
docParams.setTitle("Star Trek Movie Review");
docParams.setSubtitle("Generations");
docParams.setAbstract("This reviewer loves the movie!........");
docParams.setMimeType("text/xml");
docParams.setContent(content);
docParams.setComment("Initial revision.");
// params.setAcl(...); specify an ACL, otherwise inherit ACL of parent folder
EbiDocument doc = cmgr.addDocument(context, docParams);
System.out.println("Added new movie review: " + doc);
// Publish the new document
cmgr.publishDocumentContentVersion(context, doc.getID(), 1, true, true);
}
Adding multiple documents This example presents a method called addMultipleDocuments() that converts a set of files into new documents of type Movie Review and adds them to the Content Management subsystem.
This method sets all required document parametersdocument type, name, title, author, and parent folderas well as some optional parameters.
Note that the addMultipleDocuments() method executes the following shared logic outside the for loop for efficient processing:
The new documents do not contain extension metadata fields, nor do they have parent documents. The addMultipleDocuments() method reads in the content of each new movie review from its file of origin and stores the data in the byte array content.
As for security, the addMultipleDocuments() method does not set the ACL for the new documents. This means that the ACL is null and the documents inherit the ACL of their folder.
The addMultipleDocuments() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and the directory where the files of interest are stored. All of these entities are passed in as arguments.
public void addMultipleDocuments(
EbiContentMgmtDelegate cmgr, EbiContext context, String dirName)
throws
EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException,
FileNotFoundException, IOException
{
// Get the doctype
EbiDocType type = cmgr.getDocumentTypeByName(context, "Movie Review");
// Get the folder
EbiDocFolder folder = (EbiDocFolder)cmgr.lookupDirectoryEntry(
context, "MyApp/MovieReviews/Current", EbiDocFolder.EL_DOC_FOLDER);
// Instantiate a document addition parameters object
EbiAddDocumentParams docParams = cmgr.createAddDocumentParams();
// Set all the String parameters to be reused
String author = "NightGhost";
String mimeType = "text/xml";
String comment = "Initial revision.";
File dir = new File(dirName);
File[] files = null;
if (dir.exists() && dir.isDirectory())
files = dir.listFiles();
else
throw new EboApplicationException(null, "Invalid directory name '" + dirName + "'.");
// Turn each file in the specified directory into a new movie review document
for (int i = 0; i < files.length; i++)
{
if (files[i].isDirectory())
continue;
FileInputStream fis = new FileInputStream(files[i]);
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();
String name = files[i].getName();
docParams.setName(name);
docParams.setDocTypeID(type.getDocTypeID());
docParams.setFolderID(folder.getID());
docParams.setAuthor(author);
docParams.setTitle(name);
docParams.setMimeType(mimeType);
docParams.setContent(content);
docParams.setComment(comment);
docParams.setPublishImmediately(true);
// params.setAcl(...); specify an ACL, otherwise inherit ACL of parent folder
EbiDocument doc = cmgr.addDocument(context, docParams);
}
}
When you add a document, you must create a set of field values that match the fields defined for the document's type. Each field can have one or more values, and null values are allowed. The fields and their values are called extension metadata, in contrast to the standard metadata defined for an EbiDocument object (such as title, author, abstract, and status).
You manage the extension metadata via two objects:
EbiDocExtnMeta, which is a holder for all the extension metadata for all the fields
EbiDocExtnMetaInfo, which associates a field with a set of values
After you create an EbiDocExtnMetaInfo object for a specific field, you set the values for the field as an array, even if there is only one value. The type of the array must correspond to the data type of the field.
After you've created an EbiDocExtnMetaInfo object for each field and added it to the EbiDocExtnMeta object, call setExtensionMetaData() for EbiAddDocumentParams to associate it with the document you are adding.
Getting fields for the document type To find out what fields to specify for a document, you can get a collection of EbiDocField objects for the document type. This example presents a method called getDocTypeFields() that gets all the document type fields to which the user has READ access.
The getDocTypeFields() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments.
public void getDocTypeFields(EbiContentMgmtDelegate cmgr, EbiContext context)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocType docType = cmgr.getDocumentTypeByName(context, "Movie Review");
if (docType != null)
{
Collection fields = cmgr.getFilteredDocumentFields(context, docType.getDocTypeID());
System.out.println("Fields: " + fields);
}
}
Getting a field object by name You can also get individual fields by name. This example presents a method called getField() that gets the field named Director.
The getField() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments.
public void getField(EbiContentMgmtDelegate cmgr, EbiContext context)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocField fldDirector = cmgr.getDocumentFieldByName(context, "Director");
System.out.println("Director field: " + fldDirector);
}
Setting a field value and associating the extension metadata with a new document This example presents a method called setFieldValues() that performs the following tasks:
Creates an EbiDocExtnMeta holder and EbiDocExtnMetaInfo objects for the Director and Genre fields
Associates the EbiDocExtnMeta object with an EbiAddDocumentParams object that it uses to add the new document to the content respository
The values for each field are passed as String arrays.
Note that the setFieldValues() method does not set the ACL for the new document. This means that the ACL is null and the document inherits the ACL of its folder.
The setFieldValues() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), which are passed in as arguments.
public void setFieldValues(EbiContentMgmtDelegate cmgr, EbiContext context)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
// Get the doctype
EbiDocType type = cmgr.getDocumentTypeByName(context, "Movie Review");
// Get the folder
EbiDocFolder folder = (EbiDocFolder)cmgr.lookupDirectoryEntry(
context, "MyApp/MovieReviews/Current", EbiDocFolder.EL_DOC_FOLDER);
// Instantiate a document addition parameters object
EbiAddDocumentParams docParams = cmgr.createAddDocumentParams();
// Create the extension metadata holder object
EbiDocExtnMeta meta = cmgr.createExtnMeta();
// Specify the extn metadata field values for 'Director'
EbiDocField fldDirector = cmgr.getDocumentFieldByName(context, "Director");
EbiDocExtnMetaInfo miDirector = cmgr.createExtnMetaInfo(fldDirector);
String[] directors = { "Andy Wachowski", "Larry Wachowski" };
miDirector.setFieldValues(directors);
meta.setExtnMetaInfo(miDirector);
// Specify the exnt metadata field values for 'Genre'
EbiDocField fldGenre = cmgr.getDocumentFieldByName(context, "Genre");
EbiDocExtnMetaInfo miGenre = cmgr.createExtnMetaInfo(fldGenre);
String[] genres = { "Action", "Thriller", "Sci-Fi" };
miGenre.setFieldValues(genres);
meta.setExtnMetaInfo(miGenre);
// Get the content
String movieContent = "This movie has exceeded all expectations!....";
byte content[] = movieContent.getBytes();
// Set the extension metadata into the doc params object
docParams.setExtensionMetaData(meta);
docParams.setName("The Matrix (1999)");
docParams.setDocTypeID(type.getDocTypeID());
docParams.setFolderID(folder.getID());
docParams.setAuthor("Night Ghost");
docParams.setTitle("The Matrix (1999)");
docParams.setMimeType("text/xml");
docParams.setContent(content);
docParams.setComment("Initial revision.");
// params.setAcl(...); specify an ACL, otherwise inherit ACL of parent folder
EbiDocument doc = cmgr.addDocument(context, docParams);
// Publish the new document
cmgr.publishDocumentContentVersion(context, doc.getID(), 1, true, true);
}
Getting all fields This example presents a method called getExtnMeta() that gets all the extension metadata fields for a specified document. The method uses the EbiDocExtnMeta object as a holder for the document's fields. This object provides methods for getting information about the fields, such as names and values.
The getExtnMeta() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and the document of interestall of which are passed in as arguments.
public void getExtnMeta(EbiContentMgmtDelegate cmgr, EbiContext context, String docID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
// Get the extension metadata holder for the document
EbiDocExtnMeta extnMetaData = cmgr.getDocumentExtnMeta(context, docID);
System.out.println("Extension metadata: " + extnMetaData);
// Enumerate the field names
Iterator fieldNames = extnMetaData.getFieldNames().iterator();
while (fieldNames.hasNext())
System.out.println("Field: " + (String)fieldNames.next());
// For each extension meta info
for (int i = 0; i < extnMetaData.size(); i++)
{
EbiDocExtnMetaInfo mi = extnMetaData.getExtnMetaInfoByIndex(i);
System.out.println("MetaInfo " + i + ": " + mi);
String fieldName = mi.getFieldName();
System.out.println("Field name: " + fieldName);
Collection fieldValues = mi.getFieldValues(false);
System.out.println("Values: " + fieldValues);
}
}
Getting field values for a single field This example presents a method called getExtnMeta() that gets an EbiDocExtnMetaInfo object for a single field.
The getExtnMeta() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and the document and field of interestall of which are passed in as arguments:
public void getExtnMeta(
EbiContentMgmtDelegate cmgr, EbiContext context,
String docID, String fieldID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocExtnMetaInfo info = cmgr.getDocumentExtnMetaInfo(
context, docID, fieldID);
System.out.println("Meta Info: " + info);
}
From the EbiDocExtnMetaInfo object you can get a Collection of the values for the field (the values of the array that set the field). A boolean argument lets you specify whether the data type of the returned values is String or the actual data type of the field.
This statement gets the values of the EbiDocExtnMetaInfo object as Strings:
Collection valueStrings = info.getFieldValues(true);
This table lists methods that let you manage documents, edit the metadata, and get documents:
Typically, the layout styles associated with the document type are adequate for displaying your document (as described in Managing layout styles). When you have hundreds of documents (news stories, press releases, editorials, reviews), you don't want to design custom XSL for each one. One design or a few alternative designs are enough; you can associate one or more layout styles with a document type.
When you want to lock in a particular layout for an individual document, you can specify a layout set for that document. A layout set uses a specific layout style, selected from the ones that are valid for the document's type. The layout set uses one or more of the layout document descriptors associated with that style. In the set you can use whatever version of the layout document is currently published or you can select a specific version. The set needs to includes layout document descriptors for whatever clients will view the content. The XSL in the layout documents associated with the descriptors render the document.
A layout set is meant for locking in a presentation so that the document always looks the same. As layout styles for a document type evolve with new versions, the presentation of an individual document will change. Use a layout set when it is important to preserve the original presentation.
The layout set is less appropriate for giving a document a unique look. It may be more appropriate to add a new document type. However, you can also add a custom style to the document type in order to make a special layout available for the document. If you don't want to be constrained to styles for the document type, you could design your application to locate style documents in another wayfor example, via a custom field. However, you would want to make sure your custom system has the flexibility for getting different XSL for different clients.
Methods These methods of EbiContentMgmtDelegate manage layout sets:
To associate a layout set with a new document, call the setLayoutSet() method of EbiAddDocumentParams.
To change the XSL documents in the layout set of an existing document, call getDocumentLayoutSet(), call methods of EbiDocLayoutSet to make changes, and then call updateDocumentLayoutSet().
Currently, you cannot add a layout set to a document if it didn't have one when it was added.
You can specify relationships between documents by specifying that one document is a child of another.
The content repository supports two types of document relationships:
Hierarchicalwhere each document in the hierarchy stores the ID of its parent document. A document has only one parent. The value ם identifies the top document in a chain of links. The chain can be an indefinite number of levels deep.
Hierarchical linking is designed for a threaded discussion and similar structures.
Compoundwhere a link object identifies the originator of the link (parent) and the target of the link (child). A parent can have many child documents, and a child can have many parents.
Compound linking is designed for building composite documents, where many pieces of content are brought together in a single presentation page. For example, child documents might include sections of a report, a list of cross-references that is appended to a document, or images to be displayed in a page.
You can use linked documents in many ways. A parent document might serve as a container of child documents, where each subsection of the document is produced by a different author. Documents could be linked in a chain to identify a message thread. Links could point to nontext documents that are stored separately, such as images or sound files.
CAUTION When specifying either hierarchical or compound links, you are not prevented from creating circular links, where a parent document is also a child of its child document. If you do this, proceed with caution: circularity may confuse both programmer and end user. It is up to you to understand the link structure of your repository when you process the content.
Hierarchical linking lets you create a threaded discussion. The following diagram shows two views of a threaded discussion. Each reply has one parent, and each message can be the parent of several replies. The top message in each chain has no parent.
When a user submits a reply, the component uses the ID of the original message as the parent of the new reply document:
These methods of EbiContentMgmtDelegate are useful in managing hierarchical links:
In addition, when you have an EbiDocument object, you can get and change the parent document ID, via getParentDocID() and setParentDocID(). After changing the ID, call updateDocument() to put the changes in the repository.
This example presents a method called addChildDocument() that creates a child document as a reply in a message thread. Inside a while loop, the method navigates the thread to the top message, then uses its title to construct the name and subtitle of the reply.
The addChildDocument() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), the parent document, message subject, and replyall of which are passed in as arguments.
public void addChildDocument(
EbiContentMgmtDelegate cmgr, EbiContext context, String folderID,
String parentID, String subject, String reply)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiAddDocumentParams params = cmgr.createAddDocumentParams();
params.setName("Reply to " + threadTitle);
EbiDocType doctype = cmgr.getDocumentTypeByName(context, "Discussion");
if (doctype != null)
params.setDocTypeID(doctype.getDocTypeID());
params.setFolderID(folderID);
params.setAuthor(context.getUserID());
params.setTitle(subject);
params.setSubtitle(threadTitle);
params.setMimeType("text/plain");
params.setContent(reply.getBytes());
params.setParentID(parentID);
cmgr.addDocument(context, params);
}
Compound linking lets you create a network of interrelated documents. You might use it to create a composite document out of many contributed pieces, such as sections (written by different authors), images, cross-references, and other information.
For more information, see
Composite documents.
The following diagram shows a network of documents that are used by two different parent documents. Some of the material is shared by both.
Access to documents you want to link To create a link, you must check out both the parent and child documents, add the link, and then check in both documents.
XML for composite documents It is easy to program the display of a composite document when the content type is XML. Your component inserts each child document as a node in the DOM with an appropriate element name. An XSL style sheet specifies how those elements are displayed. You don't have to insert the child documents into existing content in any particular order. The order is determined by the style sheet. By selecting different style sheets, you can change the way the different elements are displayed and whether they are included at all.
For information about style sheets for document types, see
Managing layout styles. To specify styles for individual documents, see
Specifying layout sets for documents.
For example, suppose you have a Movie Review document type and the paragraphs of the review are its content. Child documents for the review could include an image from the movie and biographies of the cast. In the displayed HTML, the biographies could be displayed on the same page or they could be links to another HTML page. You could have different style sheets that determine which way to display the biographies and whether the image is on the left or the right.
NOTE When adding, removing, and changing links, you must check out the parent and child documents.
These methods of EbiContentMgmtDelegate are useful in managing compound links:
Linking a child document This example presents a method called addDocLink() that adds a link between a parent document and a child document.
The addDocLink() method needs to access a content manager (EbiContentMgmtDelegate), a context object (EbiContext), the parent and child documents, and the child document versionall of which are passed in as arguments.
public void addDocLink(
EbiContentMgmtDelegate cmgr, EbiContext context,
String linkParentDocID, String linkChildDocID, int linkChildVersionID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocLink lnk = cmgr.addDocumentLink(
context, linkParentDocID, linkChildDocID, linkChildVersionID);
}
Updating a link with a new document version This example presents a method called updateDocumentContentAndLink() that creates and publishes a new version of a child document, then updates the link from the parent to point to the new version.
If a new version of the child document is published later, this link continues to point to the old version. A link between the parent and child must exist. If not, use addDocumentLink() instead of updateDocumentLink().
The updateDocumentContentAndLink() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), the parent and child documents, document content, and MIME typeall of which are passed in as arguments.
public void updateDocumentContentAndLink(
EbiContentMgmtDelegate cmgr, EbiContext context,
String linkParentDocID, String linkChildDocID,
byte[] linkChildDocContent, String linkChildDocMimeType)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
// Create a new version of the link child document
int newVersionID = cmgr.checkinDocument(
context, // context
linkChildDocID, // docid of link child
linkChildDocMimeType, // mime type
linkChildDocContent, // new content
"new version", // check-in comment
false); // whether to keep doc checked out
// Publish it
cmgr.publishDocumentContentVersion(
context, linkChildDocID, newVersionID, true, true);
// Now, update the link to point to the new version
cmgr.updateDocumentLink(
context, // context
linkParentDocID, // link parent docid
linkChildDocID, // link child docid
newVersionID); // new version id
}
Getting linked parent documents This example presents a method called getLinkParentDocuments() that gets the parent documents that are linked to a specified child.
By calling getFilteredLinkParentDocuments(), the code retrieves only documents to which the user has READ access.
The getLinkParentDocuments() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and the child document of interestall of which are passed in as arguments.
public void getLinkParentDocuments(
EbiContentMgmtDelegate cmgr, EbiContext context,
String linkChildDocID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
Collection linkParentDocs = cmgr.getFilteredLinkParentDocuments(context, linkChildDocID);
System.out.println("Parent docs: " + linkParentDocs);
}
Getting linked child documents This example presents a method called getLinkChildDocuments() that gets the child documents that are linked to a specified parent.
By calling getFilteredLinkChildDocuments(), the code retrieves only documents to which the user has READ access.
The getLinkChildDocuments() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and the parent document of interestall of which are passed in as arguments.
public void getLinkChildDocuments(
EbiContentMgmtDelegate cmgr, EbiContext context,
String linkParentDocID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
Collection linkChildDocs = cmgr.getFilteredLinkChildDocuments(context, linkParentDocID);
System.out.println("Child docs: " + linkChildDocs);
}
The Content Management subsystem includes functionality that supports checkout, checkin, versioning, and publishing.
Much of the information in the Content Management subsystem is data about documents. However, when you start using the checkout and checkin methods, you also get multiple versions of document content. Each time a document is checked in, a new version is created. When a document is published, there is also a released version of the content, which comes from the set of versions. You can continue creating new versions, while the publicly available version remains stable.
The diagram that follows shows the relationship between an EbiDocument object, which holds the document metadata, and its version objects. The content for each version is stored in an EbiDocVersion object. When you select a version for publishing, that version's content is copied to an EbiDocContent object.
NOTE It is important to remember that only the content has multiple versions. There is only one version of the document's metadata.
You might program components for source control and publishing to accomplish tasks like these:
Add a new document to the system. If the document is added with accompanying content, the system creates a first version.
Check out a document. When a user checks out the document, your component copies the content to an appropriate editing environment.
Check in a document. When the user checks in the document, the system creates a new version.
Publish documents. You might have a scheduled task that checks publish dates and calls publishDocumentContentVersion() when a document's publish date is passed.
Unpublish documents. You might have a scheduled task that removes a published version when the expiration date has passed. The task might move the document to an archive folder, purge it from the system, or set its publish date so another version can be published later.
To find out if a document is published, call the EbiDocument method getPublishStatus(). If it returns null, then the document has no published content.
A publish date does not automatically reflect the time the document was published. It just indicates when it should be published. For example, a publish date of null means publish immediately. However, your publishing component can set the publish date if you want to track the date a document became available.
The document's status field is available for your own document tracking. You can establish your own application-specific set of status values and update the document's status field to reflect its progress through your document processing procedures. For example, you could specify submitted, reviewed, approved, rejected, published, unpublished, archived, and purged as status values for your application.
Example of setting document status This example presents a method called setDocumentStatusToRejected() that sets a document's status to rejectedperhaps to indicate that the document has been rejected by a content administrator and requires further changes before it can be published. Note that after setting status, you must call the updateDocument() method for the change to take effect.
The setDocumentStatusToRejected() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and document of interestall of which are passed in as arguments.
public void setDocumentStatusToRejected(
EbiContentMgmtDelegate cmgr, EbiContext context, String docID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocument doc = cmgr.getDocument(context, docID);
doc.setStatus("rejected");
cmgr.updateDocument(context, doc);
}
These methods of EbiContentMgmtDelegate are available for source control and publishing:
The Director Content Management subsystem is integrated with the Director Search subsystem to provide capabilities for conceptual and keyword searching of document content and metadata. The underlying technology is built around Application Builder, a toolkit from Autonomy, Inc. consisting of application programming interfaces (APIs) that provide access to conceptual query and index functionality of Autonomy's Dynamic Reasoning Engine (DRE).
The Content Management subsystem also provides its own built-in capability for SQL-based searching over document metadata.
The Autonomy-based search technology gives you the ability to implement conceptual and keyword searching in your Director components. Traditional keyword searching returns all documents that contain occurrences of a search string. By contrast, conceptual searching matches concepts rather than simply finding literal text strings, thereby returning content that is related by meaning and ranked by relevance to the search criteria. As a result, conceptual search returns more relevant results and fewer false hits.
For more information about conceptual searching, see the chapter about the Search subsystem in the Search Guide.
eXtend Director comes with a data fetcher for the Director Content Management repository that propagates document content and metadata from the Content Management repository into the Director DRE where it is indexed. The related processes of propagating and indexing data is often called fetching. The Content Management subsystem communicates with the Director DRE through the Search API, as described in the chapter about the Search API in the Search Guide.
To implement Autonomy-based conceptual and keyword search in your Director applications, you use the Content Management API functionality that wrappers the relevant Search APIs:
This Content Management package:
com.sssw.cm.api.EbiContentMgmtDelegate.runQuery()
wrappers this Search package:
com.sssw.search.api.EbiQueryEngineDelegate.runQuery()
This Content Management package:
com.sssw.cm.api.EbiQueryResult
extends this Search package:
com.sssw.search.api.EbiQueryResult
The wrapper classes provide methods for constructing and running queries on content and metadata that reside in the Content Management repository and have been indexed by the Director DRE.
In addition, you can configure your environment to manage the processes of document fetching and querying, as described in the section on setting search options in the chapter on using the Search subsystem in the Search Guide.
CAUTION The Content Management data fetcher that comes with Director allows you to conduct Autonomy-based searches exclusively on content and metadata stored in theDirector Content Management repository. To use Autonomy technology with Director to search data sources other than the Content Management repository, you must purchase additional data fetchers from Autonomy, Inc. and use Search API classes to implement data fetching and querying.
Key classes and interfaces for implementing Autonomy-based searching of content and metadata in the Content Management repository include:
This section describes methods that you can use to perform basic functions.
The method for getting the content manager delegate is getDefaultContentMgmtDelegate(), called on com.sssw.cm.client.EboFactory. This method returns a content manager delegate associated with the Default Director Content Management repository.
You can run Autonomy-based queries on this object to search document content, standard metadata, and custom metadata stored in the Default Content Management repository.
For more information about why to use delegates, see
Programming practices.
The EbiQuery interface for constructing Autonomy-based queries resides in the Search subsystem API. You must use the Search API method getQuery() method to instantiate an object that implements this interface, then call Search API methods on this query object to construct Autonomy-based queries and fine-tune search results. The key methods for constructing and configuring Autonomy-based queries are the following:
|
Method |
Description |
|---|---|
Instantiates a blank EbiQuery object that can be used to construct Autonomy-based queries. | |
Specifies the type of query you want to run.
| |
For more information, see the chapter that describes the Search API in the Search Guide.
You run Autonomy-based queries by calling the runQuery() method on the content manager delegate associated with the Default Director Content Management repository. You can also run queries via the Search subsystem by calling EbiQueryEngineDelegate.runQuery(), as described in the chapter on the Search API in the Search Guide.
You can call methods on EbiQueryResult to process your Autonomy-based query results. EbiQueryResult inherits methods from com.sssw.search.api.EbiQueryResult to allow you to get and set properties on your query results. It also inherits methods from com.sssw.cm.api.EbiDocument and com.sssw.cm.api.EbiDocConetent to allow you to retrieve content and metadata from your search results.
This section describes the best practices for using the Content Management API (in conjunction with the Search API) to implement conceptual searching in components for your Director applications.
The Content Management subsystem lets you use delegates to access the content manager. A delegate is a wrapper that hides the location of a service. The delegate model follows the J2EE Business Delegate pattern.
When you use a delegate, you do not need to know whether the service is using a local manager object or an EJB. The delegate initially attempts to instantiate a local manager. If this fails, it attempts to use an EJB instead. This approach allows developers to use the same code on clients and servers to instantiate services.
For more information about delegates, see the chapter on coding Java for Director applications in the Core Development Guide.
Here is the recommended logic flow for developing a search component. Add this logic to the setComponentData() method of your component:
Configure your search environment, as described in the section on setting search options in the chapter on using the Search subsystem in the Search Guide.
NOTE The Content Management data fetcher supplied with Director automatically initiates the process of fetching data, based on how you set synchronization mode.
Set other parameters such as maximum number of results to return and relevance cut.
Get an object that implements the EbiContentMgmtDelegate interface for running the query.
For more information about writing Director components, see the chapter on developing components in the Portal Guide.
Here is an example of a getComponentData() method that illustrates the recommended logic flow for running a conceptual query:
...
public void getComponentData( EbiPortalContext context, java.util.Map params ) throws com.sssw.fw.exception.EboUnrecoverableSystemException
{
//Declare a string buffer
StringBuffer sb = new StringBuffer();
//Set the query string
String queryString = "The+effect+of+the+recession+on+consumer+spending";
try
{
//Create a blank query object
com.sssw.search.api.EbiQuery query = com.sssw.cm.factory.EboFactory.getQuery();
//Set query type to text
query.setQueryType(query.QUERY_TYPE_TEXT);
//Specify the query string. This is a conceptual query
query.setText(queryString);
//Ask for a maximum of 50 results
query.setMaxNumResults(50);
//Ask for results that are at least 80% relevant
query.setRelevanceCut(80);
//Ask to return all available document properties in the results
query.selectAll();
//Get the content manager delegate
EbiContentMgmtDelegate contentMgr = com.sssw.cm.client.EboFactory.getDefaultContentMgmtDelegate();
//Run the query
//The boolean argument in runQuery indicates whether results should be filtered
Iterator iterResults = contentMgr.runQuery(context, query, true).iterator();
//Process the results
while (iterResults.hasNext())
{
com.sssw.cm.api.EbiQueryResult res = (com.sssw.cm.api.EbiQueryResult)iterResults.next();
//Get document metadata
String docTitle = res.getTitle();
java.sql.Timestamp dateCreated = res.getDateCreated();
//Get document content
String docAbstract = res.getAbstract();
//Add query result to the string buffer returned by the component
sb.append("\n").append(docTitle).append(dateCreated).append(docAbstract).append("\n");
}
}
catch (Exception _E)
{
System.out.println ("Query failed");
_E.printStackTrace();
}
//Set content type
context.setContentType(com.sssw.portal.api.EbiComponentConstants.MIME_TYPE_HTML_UTF8);
//Place the content into the context
context.setComponentContent( sb.toString() );
}
...
Note that this component retrieves standard metadatathe document title and the date createdas well as content from the query results. To make sure this data is returned in the query results, you must configure the Director DRE to index standard metadata and content by setting the following search options in the Content Management subsystem configuration file:
com.sssw.cm.fetch.process.content.CM repository name
com.sssw.cm.fetch.process.metadata.CM repository name
The Content Management subsystem provides many other configurable options that you can set to customize your search environment. For more information, see the section on setting search options in the chapter on using the Search subsystem in the Search Guide.
You can query content and metadata using a single query.
When you use the Content Management data fetcher supplied with Director, you specify what types of data to searchcontent, standard metadata, and/or custom metadataas described in the section on setting search options in the chapter on using the Search subsystem in the Search Guide. Then you use the Content Management API to instantiate a query object and run the query using a method defined on an EbiContentMgmtDelegate object, as described in Programming practices.
Autonomy-based searching allows you to run the following types of queries in Director applications:
For more information about these Autonomy-based queries and how to implement them, see the section on query types in the chapter that describes the Search API in the Search Guide.
In the Content Management subsystem you can find documents whose metadata or content contain specific values. There are three ways you can search:
Search specific fields in the document's standard metadata and extension metadata for specific values or ranges of values
Search the standard metadata for words, phrases, or other patterns
Search the document content for words, phrases, or other patterns
To perform a query, you write code that calls:
The EbiContentMgmtDelegate method createQuery(), specifying the type of query you want to perform
Methods of the particular query object, specifying what data to return and what the WHERE clause and ORDER BY criteria are
The EbiContentMgmtDelegate method findElements(), which executes the query and returns a Collection of EbiDocument or EbiDocContent objects
The EbiDocument and EbiDocContent objects contain only the fields that you specify via the SELECT methods. They are not complete representations of the object in the content repository. If you call a get method for a field that was not part of the query, the method will return null.
For example, you might search the document content for a phrase, but return only the document ID and size. Using the ID, you can display a list of document names and sizes; and the user can click a link to see the document content, which you can display by calling getContent().
You can search the standard and extension metadata for documents by creating an EbiDocQuery object:
EbiDocQuery query = (EbiDocQuery) cmgr.createQuery(EbiDocQuery.DOC_QUERY);
The EbiDocQuery object has numerous methods for specifying the metadata fields you want to select and search.
To select the fields to be returned, call one of the inherited SELECT methods.
To specify the search criteria, call one of the WHERE methods of EbiDocQuery, which creates a EbiQueryExpression object. You can create several expression objects and call methods of EbiQueryExpression to concatenate them using AND or OR, as well as parentheses. (For more details, see Building the search criteria.)
To execute the search, you call findElements(), which returns a collection of EbiDocument objects. The EbiDocument objects contain the document ID plus the data for the fields you selected. Data for other fields is not available, and methods to get that data return null.
For each of the standard metadata fields, you can choose one of several WHERE methods to specify search criteria for that field. The methods can match a value against the data using a SQL, relational, or string operator. Each method includes a NOT parameter that can negate the clause. The full set of WHERE methods are listed in EbiDocQuery.
A summary of the operators defined in com.sssw.fw.api.EbiMetaDataQuery are:
Using Title for an example, you can call these three methods:
When you need WHERE expressions for several metadata fields, you connect them together using methods of EbiQueryExpression. Here are some patterns that assign the result to expression1:
This method joins two expressions using AND:
expression1.andExpression(expression2);
This method puts parentheses around the expression, done before joining it to another expression:
expression1.parenthesize();
This method joins the current value of expression1 to expression3 using OR:
expression1.orExpression(expression3);
To search an extension metadata field, you create one expression for the field IDs you want to search and another expression for the value to search for. For the field ID, you would usually use:
whereFieldID(int value, int op, boolean not)
For field values, you might use any of these:
whereFieldValue(java.lang.Object fieldValue, int op, boolean not) whereFieldValueBetween(java.lang.Object first, java.lang.Object last, boolean not) whereFieldValueIn(java.lang.Object[] values, boolean not)
After you create an expression for the field ID and another for the field value, you concatenate the two using the AND method and the parenthesize() method, which restricts the search to that field and values. You can search another field by setting up another pair of expressions in the same way and concatenating the result with the rest of the WHERE clause.
This example presents a method called executeDocMetaSearch() that finds documents of type Movie Review that meet these search criteria:
The EbiDocument objects in the returned collection contain all the properties that have been defined for the movie reviews in ascending order by creation date.
The executeDocMetaSearch() method needs to access a content manager (EbiContentMgmtDelegate) and context object (EbiContext), along with the document type and field of interestall of which are passed in as arguments.
public void executeDocMetaSearch(
EbiContentMgmtDelegate cmgr, EbiContext context,
String mrDocTypeID, String yorFieldID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
// The search condition: find all the Movie Review documents whose:
// (Author is 'JSmith' or whose Title starts with 'A')
// AND
// whose YearOfRelease was between the year 1990 and the year 2000.
EbiDocQuery docQuery = (EbiDocQuery)cmgr.createQuery(EbiDocQuery.DOC_QUERY);
docQuery.selectAll();
EbiQueryExpression expr = docQuery.whereDocTypeID(mrDocTypeID, EbiDocQuery.ROP_EQUAL, false);
EbiQueryExpression expr2 = docQuery.whereAuthor("JSmith", EbiDocQuery.ROP_EQUAL, false);
EbiQueryExpression expr3 = docQuery.whereTitle("A", EbiDocQuery.SOP_STARTS_WITH, false);
EbiQueryExpression expr4 = docQuery.whereFieldID(yorFieldID, EbiDocQuery.ROP_EQUAL, false);
EbiQueryExpression expr5 = docQuery.whereFieldValueBetween(
EboMisc.getInteger(1990), EboMisc.getInteger(2000), false);
// (Author is 'JSmith' or Title starts with 'A)
expr2.orExpression(expr3);
expr2.parenthesize();
// YearOfRelease was between the year 1990 and the year 2000
expr4.andExpression(expr5);
// (Author is 'JSmith' or whose Title starts with 'A')
// AND
// YearOfRelease was between the year 1990 and the year 2000
expr.andExpression(expr2);
expr.andExpression(expr4);
docQuery.setWhere(expr);
// Sort results by creation date/time, in ascending order
docQuery.orderByCreateDate(true);
// Execute the search
Collection results = cmgr.findElementsFiltered(context, docQuery);
}
Categories and folders form two separate hierarchies of nested directories, starting from a root category or folder. The main difference between the two is that a document belongs to one and only one folder, but may belong to zero or more categories. In this discussion, directory refers to both folders and categories.
In the Content Management subsystem, you can add directories to the root directory and to subdirectories to any level of nesting, described in Managing folders and categories. 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.
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.
For a working component that uses this technique, see component/documentmgmt/CategoryTreeBase.java.
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();
}
}
Components in your online application get a document's metadata and content, retrieve linked content, and use the associated layout styles to display the document to the user.
If the content type of a document is HTML and it has no linked documents, the component might simply get and set the content, as shown below:
EbiContentMgmtDelegate cm = null;
try {
cm = (EbiContentMgmtDelegate)
com.sssw.fw.factory.EboFactory.getManager(
EbiPortalConstants.PORTAL_CONTENT_MGR);
} catch (EboFactoryException ebfe) {
throw new EboUnrecoverableSystemException(ebfe,
"Unable to get ContentManager");
}
try {
EbiDocument doc = (EbiDocument)
cm.lookupDirectoryEntry(context, "MyFolder/TDBDoc1",
EbiDocument.EL_DOCUMENT);
EbiDocContent content = cm.getContent(context, doc.getID(), true);
if (content != null)
{
byte [] html = content.getData();
String shtml = new String(html);
context.setComponentContent(shtml);
context.setContentType(EbiComponentConstants.MIME_TYPE_HTML);
}
} catch (EboItemExistenceException eiee)
{
throw new EboUnrecoverableSystemException(eiee,
"Unable to get Content");
} catch (EboSecurityException ese)
{
throw new EboUnrecoverableSystemException(ese, "Security exception");
}
If the content of a document is an XML String and it has no linked documents, the component could get the content and the document layout (also as an XML String) and use the layout XSL to transform the XML.
This concept is illustrated in the displayContent() example method shown below. In this example, methods in com.sssw.fw.util.EboXmlHelper convert a String to a DOM and apply an XSL transformation to a DOM. The displayContent() method accesses a content manager (EbiContentMgmtDelegate), context object (EbiContext), and document of interestall of which are passed as arguments.
public void displayContent(
EbiContentMgmtDelegate cmgr, EbiPortalContext context, String docID)
throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
{
EbiDocument doc = (EbiDocument)cmgr.lookupDirectoryEntry(
context, "MyFolder/TDBDoc1", EbiDocument.EL_DOCUMENT);
EbiDocContent doccnt = cmgr.getContent(context, doc.getID(), true);
if (doccnt != null)
{
byte[] xml = doccnt.getData();
EbiDocVersionDescriptor layoutver = cmgr.getDocumentLayout(
context, docID, EbiContentMgmtDelegate.COMPARE_ALL, true);
EbiDocVersion layoutcnt = cmgr.getDocumentContentVersion(
context, layoutver.getDocumentID(), layoutver.getDocumentVersionID(), true);
byte[] xsl = layoutcnt.getData();
String sxml = new String(xml);
String sxsl = new String(xsl);
String content = EboXmlHelper.processXML(
EboXmlHelper.getDOM(sxml), EboXmlHelper.getDOM(sxsl));
context.setComponentContent(content);
// set type according to results of xsl transformation
context.setContentType(EbiComponentConstants.MIME_TYPE_HTML);
}
}
A composite document could be constructed in many different ways. It is up to your component to gather the pieces and put them together in an appropriate way. Typically, you would build an XML DOM for the composite document and add elements for each piece. For a simpler composite document where the pieces are HTML fragments, you might concatenate them into a larger HTML fragment.
To illustrate the process of building an XML DOM, suppose you are displaying a movie review, a document of type Movie Review. The content of the movie review document is the text paragraphs of the review. The document's metadata provides the title, author, and other information specific to the Movie Review type, such as genre, director, year of release, and cast. Child documents refer to an image of the movie and cast biographies. To display all the data, the component builds an XML DOM of the pieces and provides an XSL style sheet for display specifications.
You will want to plan an XML structure for defining the XSL and building the DOM in the component's code. You may want to formalize that structure in a DTD. The XML structure might look like this (without closing tags):
<REVIEW> <TITLE> <AUTHOR> <GENRE> <DIRECTOR> <CAST> <CASTMEMBER> <CASTPICTURE> <BIO> </CASTMEMBER> <CASTMEMBER> <CASTPICTURE> <BIO> </CASTMEMBER> </CAST> <CONTENT> </REVIEW>
Get the metadata you want displayed (such as title, author, director, and genre) and add elements for each one. Element names might be TITLE, AUTHOR, and so on. The data values could be attributes or text nodes of the elements.
Get the cast metadata and add a CAST element, with child CASTMEMBER elements for each one.
Get the content data. Add a CONTENT element for the review paragraphs (the document content) and add the content data as a text node of the element.
Call getLinkChildDocuments() to get the linked child documents.
For each linked document, get the MIME type and other information to determine the document's purpose:
For an image from the film, add a MOVIEPICTURE element whose attributes have information needed by the XSL to build an image link.
For a cast biography, find the corresponding CASTMEMBER element and add a child BIO element. Depending on the page design, you could insert information to build a link or include the paragraphs.
For a picture of a cast member, find the CASTMEMBER element and add a CASTPICTURE element with information to build an image link.
When the XML DOM is complete, call methods of the context object to set the MIME type and the content.
You can specify access restrictions based on user ID or group membership on most objects in the Content Management subsystem. You can use access restrictions to:
Prevent changes after your infrastructure of document types, folders, and categories has been set up
Protect documents or other objects from being seen by unauthorized users
For example, you can specify that a folder and its documents have read-only access or that a document type cannot be changed.
You specify access restrictions via an ACL. To provide support for ACLs, Director implements the java.security.acl.Acl interface.
For every content management action, Director checks whether the user specified in the EbiPortalContext object has permission to perform the specified action. If an object has an ACL, Director checks whether the user has been granted the specified permission. These situations can occur:
The Content Management subsystem determines whether the user has permission to access an element in three steps:
Is the user an administrator by having PROTECT access for EbiContentAdmin?
NOTE For information on administrators, see Roles for users of the Content Management subsystem.
Objects that can have access restrictions implement the EbiSecurableElement interface. Each of the objects has a set of supported access right types. The supported types are defined as String constants in each object's interface.
The access right types include:
The table that follows lists the securable objects (not including some securable superinterfaces) and the access right types they support.
|
Object |
Access right types |
|---|---|
A comprehensive security policy must set different permissions for different roles. Typical roles in the Content Management subsystem are:
|
Role |
Description |
|---|---|
Has read and write access for documents; has read, write, and list access for folders and categories | |
Has publish access for documents; has list access for folders and categories | |
Users are considered administrators when the ACL assigned to EbiContentAdmin gives them at least one of the permissions. If they have all permissions, you could think of them as super-administrator.
When setting up users and groups for Director, you will want to consider how your users fall into these roles and create appropriate groups. You can use those user IDs and groups to create ACLs that implement your security. You might create a master ACL that you can get and reuse throughout the Content Management subsystem.
ACLs for new objects For securable objects, you can specify an ACL when you create the object. It is an argument of the object's add method.
Inheriting ACLs For the following objects, if you don't specify an ACL when you create them, the settings of their container are copied to the new object:
|
New |
Copy the ACL of their |
|---|---|
After the object is created, there is no further connection to the container's ACL. Changes to a container's ACL have no effect on the contained objects.
For other object types, if you don't specify an ACL, they have an empty ACL.
ACLs for existing objects For securable objects, you can call the getAcl() and setAcl() methods to get and change the ACL associated with an object.
You can set permissions for an object's ACL by calling:
Security methods of EbiContentMgmtDelegate, as described in Methods for Content Management subsystem security
Security methods of EbiSecurityManager, including:
For information about using the security methods of EbiSecurityManager, see the chapter on authorization in the User Management Guide.
These methods of EbiContentMgmtDelegate let you set security for objects:
This section provides examples that demonstrate a number of techniques for setting ACLs on objects and handling security exceptions.
For information on adding users and groups to ACLs, see the section on setting up ACL-based security in the User Management Guide.
Setting ACLs on objects This example presents a method called demonstrateSecurity() that illustrates the following techniques:
Adding READ access to the content admin element associated with a principal (the identity assigned to a user as a result of authentication)
NOTE In this case, the folder inherits the ACL from its parent.
The demonstrateSecurity() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and principalall of which are passed in as arguments.
public void demonstrateSecurity(
EbiContentMgmtDelegate cmgr, EbiContext context,
Principal principal)
throws
EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException, EboFactoryException, NotOwnerException
{
EboPermission readPerm = EboPermission.getPermission(
context.getEbiSession(), EboPermission.READ);
EboPermission writePerm = EboPermission.getPermission(
context.getEbiSession(), EboPermission.WRITE);
// Add READ access to the Content Admin element to the passed in principal
EbiContentAdmin adminElement = cmgr.getAdminElement(context);
Acl admAcl = cmgr.getAcl(context, adminElement);
AclEntry aclEntry = com.sssw.fw.factory.EboFactory.getAclEntry();
aclEntry.setPrincipal(principal);
aclEntry.addPermission(readPerm);
admAcl.addEntry(principal, aclEntry);
cmgr.setAcl(context, adminElement, admAcl);
// Add a folder with an ACL
Acl acl = com.sssw.fw.factory.EboFactory.getAcl();
aclEntry = com.sssw.fw.factory.EboFactory.getAclEntry();
aclEntry.setPrincipal(principal);
aclEntry.addPermission(readPerm);
aclEntry.addPermission(writePerm);
cmgr.addFolder(
context,
cmgr.getRootFolder(context),
"Movie Reviews",
EbiDocFolder.DIR_TYPE_DEFAULT,
"Folder for movie reviews",
acl);
// Add a folder with no ACL -- it will inherit the ACL
// from its parent folder (if there is an ACL set on the parent)
EbiDocFolder frFolder = cmgr.addFolder(
context,
cmgr.getRootFolder(context),
"Financial Reports",
EbiDocFolder.DIR_TYPE_DEFAULT,
"Folder for financial reports",
null);
// This code adds an ACL to an existing folder.
cmgr.setAcl(context, frFolder, acl);
}
Handling security exceptions This example presents a method called demonstrateHandleExceptions() that illustrates how to handle a security exception (and other exceptions as well).
This code publishes version 2 of a document whose ID is assigned to the variable docid. The publishDocumentContentVersion() method will throw an EboSecurityException if the user is not allowed to publish the specified document. This example handles the exception by adding an error message to the context object. The component can then include the error message in its generated content so the user knows what went wrong.
The demonstrateHandleExceptions() method needs to access a content manager (EbiContentMgmtDelegate), context object (EbiContext), and document of interestall of which are passed in as arguments.
public void demonstrateHandleExceptions(
EbiContentMgmtDelegate cmgr, EbiContext context, String docID)
{
try
{
cmgr.publishDocumentContentVersion(context, docID, 2, true, true);
}
catch (EboSecurityException se)
{
se.printStackTrace();
String msg = "Security violation: " + se.toString();
context.setValue("error", "User does not have access. " + msg);
}
catch (EboUnrecoverableSystemException use)
{
use.printStackTrace();
String msg = "Unrecoverable exception: " + use.toString();
context.setValue("error", msg);
}
catch (EboItemExistenceException iee)
{
iee.printStackTrace();
String msg = "Item existence exception: " + iee.toString();
context.setValue("error", msg);
}
}
}
The Content Management API includes EbiImporter and EbiExporter, two powerful, flexible interfaces for importing and exporting data into and out of a Director Content Management system.
Potential uses of the functionality provided by EbiImporter and Ebi exporter include:
Importing pre-existing documents into a new Director Content Management system
Moving and copying data within a single Content Management system
Importing and exporting data in the PMC The Import and Export facilities of the PMC implement a subset of the functionality of EbiImporter and EbiExporter. Using these facilities, you can import and export Content Management data without writing any Java code.
For a description of the import and export facilities of the PMC, see
Importing and exporting content.
These methods of EbiExporter allow you to export Content Management data:
For code examples on exporting Content Management data, see the Javadoc topic on EbiExporter.
These methods of EbiImporter allow you to import data into a Content Management system:
For code examples on importing Content Management data, see the Javadoc topic on EbiImporter.
|
Content Management Guide |
Copyright © 2002, SilverStream Software, Inc. All rights reserved.