第3章

ドキュメントの管理

この章では、CM (コンテンツ管理) APIを使用してドキュメントを管理する方法について説明します。この章は、次の節から構成されています。

注記:   この章で説明するドキュメント管理タスクのほとんどは、CMS管理コンソールを使用して実現することもできます。

For more information    詳細については、およびを参照してください。

 
Top of page

ドキュメントについて

CMサブシステムの「ドキュメント」は、イメージなどの単純で限定された数のコンテンツである場合、または他のドキュメントを構成する複雑なエンティティである場合があります。ドキュメントは、exteNd Directorアプリケーションで直接または間接的に使用する任意のデータです。

CMサブシステムでは、メタデータフィールドを使用してドキュメントを説明します。各ドキュメントには、名前、タイトル、作成者、要約などの標準のフィールドがあります。コンテンツ関連のフィールドは、ドキュメントタイプに関連付けることもできます。この「拡張メタデータ」では、そのドキュメントタイプに固有の検索可能な追加情報を保持できます。

ドキュメントオブジェクトは、テキストまたはバイナリデータを保持するEbiDocContentオブジェクトに関連付けることができますが、ドキュメントにはコンテンツオブジェクトは必要ありません。ドキュメントのメタデータには、必要な情報をすべて保存できます。短いテキストドキュメントの場合、テキスト全体を要約フィールドに保存できます。ドキュメントにコンテンツがない場合は、MIMEタイプおよびコンテンツにnullを指定します。

提供されたコンテンツは(存在する場合)、ドキュメントの最初のバージョンになります。コンテンツを発行する場合は、publishDocumentContentVersion()を呼び出したり、コンテンツを発行するようにスケジュール設定されているタスクを使用したりします。コンテンツがないドキュメントにはバージョン(発行されたバージョンを含む)を割り当てることはできませんが、ステータスなどの別のフィールドを使用して、ドキュメントにパブリックで使用可能というラベルを付けることができます。

 
Top of section

CM APIへのアクセス

EbiContentMgmtDelegateインタフェースでは、CMサブシステムでドキュメントに関連するほとんどのメソッドへのアクセスが提供されます。

For more information    詳細については、CM APIについてを参照してください。

 
Top of page

ドキュメントの追加

ドキュメントを追加するには、EbiAddDocumentParamsオブジェクトを作成して、さまざまなパラメータを設定します。次の表では、必要パラメータのデフォルト値について説明します。名前、ドキュメントタイプ、フォルダ、拡張メタデータなど。また、デフォルト値に特定の意味がある他のパラメータについても説明します。明示的に設定されていない他のすべてのメタデータフィールドはnullです。

パラメータ

説明およびデフォルト値

名前

フォルダ構造のドキュメントのパスを指定する場合に使用する、ドキュメントの名前。デフォルトの名前はUUIDで、ドキュメントが追加される際に割り当てられます。

ドキュメントタイプID

このドキュメントのドキュメントタイプのID。デフォルトは、システムの「デフォルト」のドキュメントタイプです。

フォルダID

このドキュメントが含まれているフォルダ。デフォルトは、システムのルートフォルダです。

拡張メタデータ

少なくとも1つの拡張メタデータフィールドが関連付けられているドキュメントタイプにドキュメントが属する場合は、setExtensionMetaData()メソッドを呼び出して、フィールドに値を入力する必要があります。

For more information    詳細については、ドキュメントのフィールド値の指定を参照してください。

発行日

ドキュメントの現在のバージョンをいつ発行する必要があるかを指定するタイムスタンプ。デフォルト値のnullは、すぐに発行することを意味します。

有効期限

発行された領域からドキュメントをいつ削除する必要があるかを指定するタイムスタンプ。デフォルト値のnullは、無期限であることを意味します。

アクセス制御リスト

ドキュメントへのアクセス権を指定するACL。

ACLは、デフォルトでnullです。この場合、ドキュメントでは、フォルダのACLを継承します。フォルダにACLがない場合、ドキュメントに対する制限はありません。

 
Top of section

ドキュメントの追加

次のコードの例では、Movie Reviewタイプのドキュメントを追加する方法を説明するaddDocument()というメソッドを示します。このメソッドによって、ドキュメントタイプ、名前、タイトル、作成者、ペアレントフォルダなどの必要なドキュメントパラメータすべてと、一部のオプションパラメータが設定されます。

新しいドキュメントには拡張メタデータフィールドは含まれず、ペアレントドキュメントもありません。addDocument()メソッドによって、新しい映画レビュードキュメントのコンテンツが明示的に設定され、バイトアレイ「content」に保存されます。

addDocument()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)およびコンテキストオブジェクト(EbiContext)にアクセスする必要があり、これらは引数として渡されます。

addDocument()メソッドでは新しいドキュメントのACLは設定されないことに注意してください。つまり、ACLはnullで、ドキュメントではフォルダのACLを継承します。

  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);
      }

 
Top of section

複数のドキュメントの追加

次のコードの例では、ファイルのセットを「Movie Review」タイプの新しいドキュメントに変換してCMサブシステムに追加する「addMultipleDocuments()」というメソッドを示します。

このメソッドによって、ドキュメントタイプ、名前、タイトル、作成者、ペアレントフォルダなどの必要なドキュメントパラメータすべてと、一部のオプションパラメータが設定されます。

addMultipleDocuments()メソッドでは、効率的な処理のために、「for」ループ外で次の共有論理が実行されます。

新しいドキュメントには拡張メタデータフィールドは含まれず、ペアレントドキュメントもありません。addMultipleDocuments()メソッドによって、新しい各映画レビューのコンテンツが元のファイルから読み込まれ、データがバイトアレイのcontentに保存されます。

セキュリティのため、addMultipleDocuments()メソッドでは新しいドキュメントのACLは設定されません。つまり、ACLはnullで、ドキュメントではフォルダのACLを継承します。

addMultipleDocuments()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のファイルが保存されているディレクトリにアクセスする必要があります。これらのすべてのエンティティは、引数として渡されます。

  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 \q" + dirName 
  	 	 	 	 + "\q.");
  
          // 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);
  
          }
      }

 
Top of page

ドキュメントのフィールド値の指定

ドキュメントを追加する場合は、ドキュメントのタイプに対して定義されたフィールドに一致するフィールド値のセットを作成する必要があります。各フィールドには1つまたは複数の値を指定でき、null値も使用できます。(タイトル、作成者、要約、ステータスなどの) EbiDocumentオブジェクトに対して定義される標準のメタデータとは対照的に、これらのフィールドと値は「拡張メタデータ」と呼ばれます。

拡張メタデータは、次の2つのオブジェクトを使用して管理します。

オブジェクト

説明

EbiDocExtnMeta

全フィールドのすべての拡張メタデータのホルダ。

EbiDocExtnMetaInfo

フィールドを値のセットに関連付ける

特定のフィールドに対してEbiDocExtnMetaInfoオブジェクトを作成した後、フィールドに対する値は、値が1つしかない場合でも、アレイとして設定します。アレイのタイプは、フィールドのデータタイプに対応する必要があります。

各フィールドに対してEbiDocExtnMetaInfoオブジェクトを作成してEbiDocExtnMetaオブジェクトに追加した後、EbiAddDocumentParamsのsetExtensionMetaData()を呼び出して、追加するドキュメントに関連付けます。

 
Top of section

ドキュメントタイプのフィールドの取得

ドキュメントに対して指定するフィールドを確認するには、そのドキュメントタイプのEbiDocFieldオブジェクトのコレクションを取得します。次の例では、ユーザに読み込みアクセスがあるすべてのドキュメントタイプフィールドを取得するgetDocTypeFields()というメソッドを示します。

getDocTypeFields()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)およびコンテキストオブジェクト(EbiContext)にアクセスする必要があり、これらは引数として渡されます。

  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);
          }
      }

 
Top of section

名前によるフィールドオブジェクトの取得

個々のフィールドは、名前を使用して取得することもできます。次の例では、Directorというフィールドを取得するgetField()というメソッドを示します。

getField()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)およびコンテキストオブジェクト(EbiContext)にアクセスする必要があり、これらは引数として渡されます。

  public void getField(EbiContentMgmtDelegate cmgr, EbiContext context)
          throws EboUnrecoverableSystemException, EboSecurityException, EboItemExistenceException
      {
          EbiDocField fldDirector = cmgr.getDocumentFieldByName(context, "Director");
          System.out.println("Director field:" + fldDirector);
      }

 
Top of section

フィールド値の設定

この例では、次のタスクを実行するsetFieldValues()というメソッドを示します。

各フィールドの値は、Stringアレイとして渡されます。

setFieldValues()メソッドでは新しいドキュメントのACLは設定されないことに注意してください。つまり、ACLはnullで、ドキュメントではフォルダのACLを継承します。

setFieldValues()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)およびコンテキストオブジェクト(EbiContext)にアクセスする必要があり、これらは引数として渡されます。

  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 \qDirector\q
          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 \qGenre\q
          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);
      }

 
Top of section

すべてのフィールドの取得

次の例では、指定したドキュメントの拡張メタデータフィールドをすべて取得するgetExtnMeta()というメソッドを示します。このメソッドでは、EbiDocExtnMetaオブジェクトをドキュメントのフィールドのホルダとして使用します。このオブジェクトによって、名前や値などのフィールドに関する情報を取得するためのメソッドが提供されます。

getExtnMeta()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のドキュメントにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
          }
      }

 
Top of section

単一のフィールドに対するフィールド値の取得

次の例では、単一のフィールドに対してEbiDocExtnMetaInfoオブジェクトを取得するgetExtnMeta()というメソッドを示します。

getExtnMeta()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のドキュメントとフィールドにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

EbiDocExtnMetaInfoオブジェクトからは、フィールドに対する値のコレクション(フィールドを設定するアレイの値)を取得できます。ブール引数を使用すると、返される値のデータタイプをStringまたはフィールドの実際のデータタイプにするかを指定できます。

次のステートメントでは、EbiDocExtnMetaInfoオブジェクトの値はStringとして取得されます。

  Collection valueStrings = info.getFieldValues(true);

ドキュメントを管理するためのメソッド

ドキュメントの管理、メタデータの編集、およびドキュメントの取得を実行できるようにするためのメソッドは、次の表のとおりです。

メソッド

返される値

説明

createAddDocumentParams()

EbiAdd-DocumentParams

メタデータ、拡張メタデータ、コンテンツ、およびACLを含む、ドキュメントを追加する場合に必要なデータを保持する空のオブジェクトを作成します。EbiAddDocumentParamsオブジェクトはaddDocument()メソッドで使用します。

addDocument()

EbiDocument

コンテンツリポジトリにドキュメントを追加します。ドキュメントのコンテンツはオプションです。

copyDocument()

EbiDocument

ドキュメントをフォルダまたはペアレントドキュメントにコピーします。

getDocument()

EbiDocument

指定したドキュメントIDのドキュメントオブジェクトを取得します。

moveDocument()

EbiDocument

ドキュメントをフォルダまたはペアレントドキュメントに移動します。

updateDocument()

void

EbiDocumentの変更内容を使用して、コンテンツリポジトリのドキュメントに関する情報を更新します。

removeDocument()

boolean

ドキュメントおよびそのすべてのバージョンをシステムから削除します。

addDocumentCategory-Reference()

void

ドキュメントがカテゴリに追加されます。ドキュメントは複数のカテゴリに属することができます。

removeDocumentCategory-Reference()

boolean

ドキュメントをカテゴリから削除します。

getDocumentExtnMeta()

EbiDocExtnMeta

ドキュメントの各フィールドに関連付けられている拡張メタデータオブジェクトのホルダを取得します。そのメソッドを使用すると各フィールドの値を取得できます。

getDocumentExtnMeta-Info()

EbiDocExtnMetaInfo

ドキュメントのフィールドの拡張メタデータオブジェクトを取得します。

getDocumentsByType() andgetFilteredDocuments-ByType()

EbiDocumentのコレクション

特定のドキュメントタイプのドキュメントのコレクションを取得します。フィルタされたバージョンでは、現在のユーザに読み込みアクセスがないドキュメントを除外します。フィルタされていないバージョンでは、アクセス権に関係なく、そのタイプのすべてのドキュメントを取得します。

getLatestDocumentContent-Version()

EbiDocVersion

ドキュメントの最新バージョンを取得します。

getDocumentContent-Version()

EbiDocVersion

ドキュメントの1つのバージョンを取得します。

getDocumentContent-Versions()

EbiDocContentのコレクション

ドキュメントのすべてのバージョンを取得します。

publishDocumentContent-Version()

void

ドキュメントの1つのバージョンを発行します。

getContent()

EbiDocContent

ドキュメントの発行されたコンテンツを取得します。ドキュメントが発行されていない場合は、nullを返します。

unpublishDocumentContent()

boolean

発行された領域からドキュメントのコンテンツを削除します。

すべてのドキュメントバージョンのコンテンツはそのまま維持されます。

 
Top of page

ドキュメントのレイアウトセットの指定

通常、ドキュメントタイプに関連付けられているレイアウトスタイルは、ドキュメントを表示するのに適しています(レイアウトスタイルの管理の説明を参照)。何百ものドキュメント(ニュース記事、プレスリリース、社説、レビューなど)がある場合、それぞれのドキュメントに対してカスタムXSLを設計することは避けたいものです。しかし、ドキュメントタイプには1つまたは複数のレイアウトスタイルを関連付けることができるため、1つまたはいくつかの代わりになるものを設計すれば十分です。

 
Top of section

レイアウトセットを使用する場合

個々のドキュメントに対して特定のレイアウトをロックするには、そのドキュメントに「レイアウトセット」を指定します。レイアウトセットでは、ドキュメントのタイプに対して有効なレイアウトスタイルの中から選択した特定のレイアウトスタイルが使用されます。また、レイアウトセットでは、そのスタイルに関連付けられている1つまたは複数のレイアウトドキュメント記述子が使用されます。セットでは、現在発行されているレイアウトドキュメントのバージョンを使用したり、特定のバージョンを選択したりすることができます。セットには、クライアントに表示されるコンテンツのレイアウトドキュメント記述子が含まれている必要があります。記述子に関連付けられているレイアウトドキュメントのXSLによって、ドキュメントは表示されます。

レイアウトセットに適したもの   レイアウトセットは表示をロックするために使用され、ドキュメントは常に同じように表示されるようになります。ドキュメントタイプのレイアウトスタイルが新しいバージョンとともに発展すると、個々のドキュメントの表示は変わります。元の表示を保持することが重要である場合はレイアウトセットを使用します。

レイアウトセットに適さないもの   レイアウトセットは、ドキュメントに固有の表示を持たせる場合にはあまり適しておらず、新しいドキュメントタイプを追加する場合の方が適している可能性があります。ただし、ドキュメントに使用できる特別なレイアウトを作成するために、ドキュメントタイプにカスタムスタイルを追加することもできます。ドキュメントタイプのスタイルに制限されないようにするためには、別の方法で(たとえば、カスタムフィールドを使用して)スタイルドキュメントが配置されるようにアプリケーションを設計できます。ただし、異なるクライアントの異なるXSLを取得する柔軟性がカスタムシステムにあることを確認する必要があります。

 
Top of section

レイアウトセットを管理するためのメソッド

次のEbiContentMgmtDelegateのメソッドは、レイアウトセットを管理します。

メソッド

返される値

説明

createDocLayoutSet()

EbiDocLayoutSet

空のレイアウトセットを作成します。これは、addDocument()を呼び出すとドキュメントに関連付けられます。

getDocumentLayoutSet()

EbiDocLayoutSet

ドキュメントのレイアウトセットを取得します。

removeDocumentLayoutSet()

boolean

レイアウトセットをドキュメントから削除します。

updateDocumentLayoutSet()

void

レイアウトセットを新しいレイアウトスタイルおよびレイアウトスタイル記述子情報で更新します。

レイアウトセットを新しいドキュメントに関連付けるには、EbiAddDocumentParamsのsetLayoutSet()メソッドを呼び出します。

既存のドキュメントのレイアウトセットでXSLドキュメントを変更するには、getDocumentLayoutSet()を呼び出し、EbiDocLayoutSetのメソッドを呼び出して変更してから、updateDocumentLayoutSet()を呼び出します。

注記:   ドキュメントが追加されたときにレイアウトセットがなかった場合、ドキュメントにレイアウトセットを追加することは現時点では不可能です。

 
Top of page

ドキュメント間のリンクの作成

1つのドキュメントが別のドキュメントのチャイルドであると指定することによって、ドキュメント間の関係を指定できます。

この節は、次のトピックで構成されています。

 
Top of section

2つのタイプのドキュメントの関係

コンテンツリポジトリは、「階層型」と「複合型」という2つの種類のドキュメント関係をサポートしています。

ドキュメント関係

説明

階層型

階層内の各ドキュメントに、そのペアレントドキュメントのIDが保存されます。1つのドキュメントにペアレントは1つしかありません。値-1は、リンクのチェーンのトップにあるドキュメントを示します。リンクのチェーンのレベル数は無限です。

階層型リンクは、スレッド化されたディスカッションおよび類似の構造に対して設計されています。

複合型

リンクオブジェクトによって、リンク元(ペアレント)およびリンク先(チャイルド)が識別されます。ペアレントは多数のチャイルドドキュメントを持つことができ、チャイルドは多数のペアレントを持つことができます。

複合型リンクは、多数のコンテンツが単一の表示ページにまとめられる合成ドキュメントを作成するために設計されています。たとえば、チャイルドドキュメントには、レポートのセクション、ドキュメントに追加される相互参照のリスト、またはページに表示されるイメージを含むことができます。

リンクされたドキュメントはさまざまな方法で使用できます。ペアレントドキュメントは、ドキュメントの各サブセクションが異なる作成者によって作成されたチャイルドドキュメントのコンテナとして使用できます。また、ドキュメントはチェーンでリンクして、メッセージスレッドを識別することもできます。リンクは、イメージやサウンドファイルなど、個別に保存されているテキスト以外のドキュメントを指すこともできます。

警告:    階層型リンクまたは複合型リンクを指定する場合、ペアレントドキュメントがチャイルドドキュメントのチャイルドでもあるというような循環型リンクを作成することもできます。循環型リンクを作成する場合は、注意が必要です。循環によってプログラマおよびエンドユーザの両方を混乱させる可能性があるからです。コンテンツを処理する際にリポジトリのリンク構造を理解しておくことは、ユーザの責任です。

 
Top of section

階層型リンク

階層型リンクを使用すると、スレッド化されたディスカッションを作成できます。スレッド化されたディスカッションの2つのビューは、次の図のようになります。各応答には1つのペアレントがあり、各メッセージは複数の応答のペアレントになることができます。各チェーンでトップにあるメッセージにはペアレントはありません。

ユーザが応答を送信すると、アプリケーションでは、元のメッセージのIDを新しい応答ドキュメントのペアレントとして使用します。

replyDoc

階層型リンク用のメソッド

次のEbiContentMgmtDelegateのメソッドは、階層型リンクの管理に役立ちます。

メソッド

返される値

説明

addDocument()

EbiDocument

ドキュメントを追加する場合、ペアレントIDを指定することによってそれをチャイルドドキュメントにすることができます。ペアレントIDが-1の場合、ドキュメントにペアレントはありません。

getChildDocuments() and getFilteredChild-Documents()

EbiDocumentのコレクション

指定したドキュメントのペアレントIDを持つチャイルドドキュメントを取得します。フィルタされたバージョンでは、現在のユーザに読み込みアクセスがないドキュメントを除外します。フィルタされていないバージョンでは、アクセス権に関係なく、すべてのチャイルドドキュメントを取得します。

また、EbiDocumentオブジェクトがある場合は、ペアレントドキュメントIDをgetParentDocID()を使用して取得したり、setParentDocID()を使用して変更したりすることができます。IDを変更した後は、updateDocument()を呼び出して変更内容をリポジトリに置きます。

 
Top of section

チャイルドドキュメントの追加

次の例では、メッセージスレッドで応答としてチャイルドドキュメントを作成するaddChildDocument()というメソッドを示します。whileループの中で、メソッドによってスレッドがトップのメッセージまで移動され、そのタイトルを使用して応答の名前およびサブタイトルが作成されます。

addChildDocument()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、ペアレントドキュメント、メッセージの件名、および応答にアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

 
Top of section

複合型リンク

複合型リンクを使用すると、相互に関係するドキュメントのネットワークを作成できます。複合型リンクは、(異なる作成者によって作成された)セクション、イメージ、相互参照、他の情報などの提供された多数のドキュメントから合成ドキュメントを作成する場合に使用できます。

For more information    詳細については、合成ドキュメントを参照してください。

次の図に、2つの異なるペアレントドキュメントによって使用されるドキュメントのネットワークを示します。オブジェクトの一部は、両方のペアレントドキュメントによって共有されています。

docNetwork

リンクするドキュメントへのアクセス   リンクを作成するには、ペアレントドキュメントおよびチャイルドドキュメントの両方をチェックアウトして、リンクを追加してから、両方をチェックインする必要があります。

合成ドキュメントのXML   コンテンツタイプがXMLである場合、合成ドキュメントの表示をプログラムするのは簡単です。ポートレットによって、各チャイルドドキュメントが、適切な要素名を持つノードとしてDOMに挿入されます。XSLスタイルシートでこれらの要素の表示方法が指定されます。チャイルドドキュメントは、特定の順序で既存のコンテンツに挿入する必要はありません。順序は、スタイルシートによって決定されます。異なるスタイルシートを選択することによって、異なる要素がどのように表示されるか、および異なる要素が含まれるかどうかを変更できます。

For more information    ドキュメントタイプのスタイルシートの詳細については、レイアウトスタイルの管理を参照してください。個別のドキュメントのスタイルを指定するには、ドキュメントのレイアウトセットの指定を参照してください。

たとえば、Movie Reviewドキュメントタイプがあり、レビューの記事がコンテンツだとします。レビューのチャイルドドキュメントには、映画のイメージおよび出演者の紹介文を含めることができます。表示されるHTMLでは、紹介文を同じページに表示したり、別のHTMLページへのリンクにすることができます。どちらの方法で紹介文を表示するか、またイメージを左または右のどちら側に置くかを決定する、異なるスタイルシートを使用することもできます。

複合型リンク用のメソッド

注記:   リンクを追加、削除、および変更する場合は、ペアレントドキュメントおよびチャイルドドキュメントをチェックアウトする必要があります。

次のEbiContentMgmtDelegateのメソッドは、複合型リンクの管理に役立ちます。

メソッド

返される値

説明

addDocumentLink()

EbiDocLink

2つのドキュメントの間にリンクを追加します。チャイルドのバージョンIDの引数には、特定のバージョンまたは-1を指定して、発行されたバージョンを使用できます。

getDocumentLink()

EbiDocLink

ペアレントIDおよびチャイルドIDがある場合はリンクオブジェクトを取得します。

removeDocumentLink()

boolean

リンクを削除します。

updateDocumentLink()

void

リンクに使用されるチャイルドドキュメントのバージョンを変更できます。

getLinkChildDocuments() andgetFilteredLinkChild-Documents()

EbiDocumentのコレクション

指定したペアレントドキュメントにリンクされたチャイルドドキュメントのリンクオブジェクトを取得します。フィルタされたバージョンでは、現在のユーザに読み込みアクセスがないドキュメントを除外します。フィルタされていないバージョンでは、アクセス権に関係なく、すべてのドキュメントを取得します。

getLinkParentDocuments() and getFilteredLinkParent-Documents()

EbiDocumentのコレクション

指定したチャイルドドキュメントがリンクされているペアレントドキュメントのドキュメントオブジェクトを取得します。フィルタされたバージョンでは、現在のユーザに読み込みアクセスがないドキュメントを除外します。フィルタされていないバージョンでは、アクセス権に関係なく、すべてのドキュメントを取得します。

 
Top of section

チャイルドドキュメントのリンク

次の例では、ペアレントドキュメントとチャイルドドキュメントの間にリンクを追加するaddDocLink()というメソッドを示します。

addDocLink()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、ペアレントドキュメントとチャイルドドキュメント、およびチャイルドドキュメントバージョンにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

 
Top of section

新しいドキュメントバージョンでのリンクの更新

次の例では、チャイルドドキュメントの新しいバージョンを作成および発行した後、新しいバージョンを指すようにペアレントのリンクを更新するupdateDocumentContentAndLink()というメソッドを示します。

チャイルドドキュメントの新しいバージョンが後に発行された場合、このリンクは古いバージョンを指し続けます。ペアレントとチャイルドの間には、リンクが存在する必要があります。存在しない場合は、updateDocumentLink()ではなくaddDocumentLink()を使用する必要があります。

updateDocumentContentAndLink()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、ペアレントドキュメントとチャイルドドキュメント、ドキュメントコンテンツ、およびMIMEタイプにアクセスする必要があり、これらはすべて引数として渡されます。

  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
      }
  

 
Top of section

リンクされているペアレントドキュメントの取得

次の例では、指定したチャイルドにリンクされているペアレントドキュメントを取得するgetLinkParentDocuments()というメソッドを示します。

getFilteredLinkParentDocuments()を呼び出すと、ユーザに読み込みアクセスがあるドキュメントのみが取得されます。

getLinkParentDocuments()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のチャイルドドキュメントにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

 
Top of section

リンクされているチャイルドドキュメントの取得

次の例では、指定したペアレントにリンクされているチャイルドドキュメントを取得するgetLinkChildDocuments()というメソッドを示します。

getFilteredLinkChildDocuments()を呼び出すと、ユーザに読み込みアクセスがあるドキュメントのみが取得されます。

getLinkChildDocuments()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のペアレントドキュメントにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

 
Top of page

ドキュメントの変更および発行

CMサブシステムには、チェックアウト、チェックイン、バージョニング、および発行をサポートする機能が含まれています。

CMサブシステムの情報の多くは、ドキュメントについてのデータです。ただし、チェックアウトメソッドおよびチェックインメソッドの使用を開始すると、ドキュメントコンテンツの複数のバージョンも取得されます。ドキュメントがチェックインされるたびに、新しいバージョンが作成されます。ドキュメントが発行された場合、バージョンのセットから提供される、コンテンツのリリースされたバージョンもあります。新しいバージョンを作成し続けることができる一方、パブリックで使用可能なバージョンはそのまま安定しています。

ドキュメントメタデータを保持するEbiDocumentとそのバージョンオブジェクトの間の関係は、次の図のとおりです。各バージョンのコンテンツは、EbiDocVersionオブジェクトに保存されています。発行するバージョンを選択すると、そのバージョンのコンテンツがEbiDocContentオブジェクトにコピーされます。

objRelationship

注記:   コンテンツにのみ複数のバージョンがあることに注意してください。ドキュメントのメタデータのバージョンは1つしかありません。

ソース制御および発行のためにポートレットをプログラムすると、次のようなタスクを実現できます。

タスク

情報

システムへの新しいドキュメントの「 追加」

ドキュメントが、付随するコンテンツとともに追加された場合は、システムによって最初のバージョンが作成されます。

ドキュメントの「チェックアウト」

ユーザがドキュメントをチェックアウトすると、ポートレットによって、適切な編集環境にコンテンツがコピーされます。

ドキュメントの「チェックイン」

ユーザがドキュメントをチェックインすると、システムによって新しいバージョンが作成されます。

ドキュメントの「発行」

発行日を確認し、ドキュメントの発行日を過ぎるとpublishDocumentContentVersion()を呼び出すタスクをスケジュール設定することができます。

ドキュメントの「発行の取り消し」

有効期限日を過ぎると発行されたバージョンを削除するタスクをスケジュール設定することができます。タスクによって、ドキュメントのアーカイブフォルダへの移動、システムからのパージ、または他のバージョンを後に発行するための発行日の設定を実行することができます。

ドキュメントのバージョンに対するチェックインコメントの「レビュー」。

 
Top of section

ドキュメントステータスの追跡

ドキュメントが発行されているかどうかを確認するには、EbiDocumentのメソッドgetPublishStatus()を呼び出します。nullが返された場合、ドキュメントには発行されたコンテンツはありません。

発行日では、ドキュメントが発行された時刻が自動的に反映されるわけではありません。発行日は、いつドキュメントを発行する必要があるかを単に示します。たとえば、発行日がnullの場合は、すぐに発行することを意味します。ただし、ドキュメントが使用可能になった日を追跡するには、発行ポートレットで発行日を設定できます。

ドキュメントのステータスフィールドは、ドキュメント追跡のために使用可能です。アプリケーション固有の独自のステータス値セットを確立し、ドキュメント処理手順を通じて、進行状況を反映するようにドキュメントのステータスフィールドを更新できます。たとえば、アプリケーションのステータス値として、submitted、reviewed、approved、rejected、published、unpublished、archived、およびpurgedを指定できます。

ドキュメントステータスの設定   次の例では、(たとえば、ドキュメントがコンテンツ管理者によって拒否されており、発行するためにはさらに変更が必要であることを示すために)ドキュメントのステータスをrejectedに設定するsetDocumentStatusToRejected()というメソッドを示します。ステータスを設定した後は、変更内容を有効にするためにupdateDocument()メソッドを呼び出す必要があります。

setDocumentStatusToRejected()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のドキュメントにアクセスする必要があり、これらはすべて引数として渡されます。

  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);
      }

 
Top of section

ソース制御および発行用のメソッド

次のEbiContentMgmtDelegateのメソッドは、ソース制御および発行に対して使用できます。

メソッド

返される値

説明

checkoutDocument()

boolean

(コンテキスト引数で指定された)現在のユーザにドキュメントをチェックアウトします。このメソッドではドキュメントがロックされます。 編集するためにコンテンツを取得するには、 getDocumentContentVersion()など他のメソッドを使用してください。

checkinDocument()

int

コンテンツのデータがあるドキュメントの新しいバージョンをチェックインします。ドキュメントをチュックアウトしたユーザのみが、そのドキュメントをチェックインできます。ユーザはコンテキスト引数に潜在的に含まれます。

uncheckoutDocument()

boolean

現在のユーザによって設定されたロックを解除します。

unlockDocument()

boolean

ユーザによって設定されたドキュメントロックを解除できるようにする管理メソッド。

rollbackDocument-Content()

void

ドキュメントコンテンツを最新のバージョンから指定バージョンにロールバックします。

publishDocument-ContentVersion()

void

指定したドキュメントの特定のバージョンを発行します。

getContent()

EbiDocContent

ドキュメントの発行されたコンテンツオブジェクトを取得します。実際のデータを含めるかどうかを選択できます。含める場合は、EbiDocContentのgetData()を呼び出して、データのバイトアレイを取得します。

getDocumentContent-Version()

EbiDocVersion

ドキュメントの1つのバージョンを取得します。実際のデータを含めるかどうかを選択できます。含める場合は、EbiDocVersionのgetData()を呼び出して、データのバイトアレイを取得します。

unpublishDocument-Content()

boolean

ドキュメントの発行されたコンテンツを削除します。

 
Top of page

ドキュメントの表示

オンラインアプリケーションのポートレットでは、ドキュメントのメタデータ、コンテンツ、およびリンクされているコンテンツを取得し、関連付けられているレイアウトスタイルを使用してドキュメントをユーザに表示します。

 
Top of section

HTMLコンテンツ

ドキュメントのコンテンツタイプがHTMLであり、リンクされているドキュメントがない場合は、ポートレットによってコンテンツが単に取得、設定されます(次を参照)。

  EbiContentMgmtDelegate cm = null;
  try {
    cm = 
     com.sssw.cm.client.EboFactory.getDefaultContentMgmtDelegate();
  } 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)
     {
       PrintWriter writer = response.getWriter();
       byte [] html = content.getData();
       String shtml = new String(html);
       writer.print(shtml);
     }
  
  } catch (EboItemExistenceException eiee)
  {
    throw new EboUnrecoverableSystemException(eiee, 
     "Unable to get Content");
  } catch (EboSecurityException ese)
  {
    throw new EboUnrecoverableSystemException(eiee, 
  }

 
Top of section

XML コンテンツ

ドキュメントのコンテンツがXML Stringであり、リンクされているドキュメントがない場合は、ポートレットによってコンテンツとドキュメントレイアウト(XML Stringとして)が取得され、レイアウトXMLを使用してXMLが変換されます。

この概念は、次の displayContent() メソッドの例に示します。この例では、com.sssw.fw.util.EboXmlHelperのメソッドによってStringがDOMに変換され、DOMにXSL変換が適用されます。displayContent()メソッドでは、コンテンツマネージャ(EbiContentMgmtDelegate)、コンテキストオブジェクト(EbiContext)、および目的のドキュメントにアクセスし、これらはすべて引数として渡されます。

  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));
              // Set type according to results of xsl transformation
              response.setContentType(EbiPortletConstants.MIME_TYPE_HTML);
              // Use a PrintWriter to render
              writer.print(content);
          }
      }

 
Top of section

合成ドキュメント

合成ドキュメントは、多数の異なる方法で作成できます。ポートレットによってコンテンツが収集され、適切な方法で合成されます。一般的には、合成ドキュメントのXML DOMを作成して、それぞれのコンテンツの要素を追加します。コンテンツがHTMLフラグメントである単純な合成ドキュメントに対しては、コンテンツを結合してより大きなHTMLフラグメントにすることができます。

XML DOM作成のプロセスを示すために、Movie Reviewタイプのドキュメントである映画レビューを表示するとします。映画レビュードキュメントのコンテンツは、レビューのテキスト記事です。ドキュメントのメタデータによって、タイトル、作成者、およびMovie Reviewタイプに固有な他の情報(ジャンル、監督、公開年、出演者など)が提供されます。チャイルドドキュメントでは、映画のイメージおよび出演者紹介文が参照されます。すべてのデータを表示するために、ポートレットではコンテンツのXML DOMを作成し、表示仕様のXSLスタイルシートを提供します。

コンポーネントのコードでXSLを定義したりDOMを作成したりするためのXML構造を計画するとします。このような状況では、その構造をDTDで形式化する必要があります。XML構造の例は次のようになります(終了タグなしで表示)。

  <REVIEW>
     <TITLE>
     <AUTHOR>
     <GENRE>
     <DIRECTOR>
     <CAST>
        <CASTMEMBER>
           <CASTPICTURE>
           <BIO>
        </CASTMEMBER>
        <CASTMEMBER>
           <CASTPICTURE>
           <BIO>
        </CASTMEMBER>
     </CAST>
     <CONTENT>
  </REVIEW>
  

コーディングの手順は次のとおりです。

  1. EbiDocumentオブジェクトを取得します。

  2. 表示するメタデータ(タイトル、作成者、監督、ジャンルなど)を取得し、それぞれに要素を追加します。要素名には、TITLEやAUTHORなどを使用できます。データ値には、引数または要素のテキストノードを使用できます。

  3. 出演者メタデータを取得し、それぞれの出演者に対するチャイルドのCASTMEMBER要素が含まれるCAST要素を追加します。

  4. コンテンツデータを取得します。レビュー記事(ドキュメントコンテント)のCONTENT要素を追加し、コンテンツデータを要素のテキストノードとして追加します。

  5. getLinkChildDocuments()を呼び出し、リンクされているチャイルドドキュメントを取得します。

  6. リンクされている各ドキュメントに対して、MIMEタイプおよび他の情報を取得して、次のようにドキュメントの目的を決定します。

  7. XML DOMが完成したら、コンテキストオブジェクトのメソッドを呼び出して、MIMEタイプおよびコンテンツを設定します。



Copyright © 2004 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.  more ...