第5章
この章では、Content Management (CM)サブシステムでのタスクの機能、およびインストールされたタスクの再設定とカスタムタスクを作成、実装する方法について説明します。この章の節は次のとおりです。
CMS管理コンソールを使用してタスクを管理することもできます。詳細については、を参照してください。
exteNd Director「タスク」は、指定の時間に実行するために設定が可能なバックグラウンドジョブまたはバックグラウンドプロセスを指します。通常、タスクは、ドキュメントの発行といった特定のCM操作を実行します。
タスクの使用 展開したexteNd Directorアプリケーションでタスクを使用するには、タスクが「有効」になっている必要があります。有効なタスクのリストは、CMS管理コンソールのTaskセクションに表示されます。アプリケーションの実行中に、このリストに表示されたタスクを開始および停止できます。
タスクのタイプ exteNd Directorタスクには、次の2つのタイプがあります。「周期 」および「スケジュール設定」定期タスクは、ミリ秒単位で指定された一定の間隔で実行するよう設定されます。スケジュール設定されたタスクは、特定の日時に実行するよう設定されます。タスクは、スケジュール設定されているか、周期的であるか、あるいはその両方の場合があります。
CMサブシステムでインストールされるタスクは、次のとおりです。
設定可能性 これらのインストールされたタスクは、詳細な設定(3つのXMLファイルのセットでの)が可能であるため、ご使用のアプリケーションの特定のニーズを満たすよう調整できます。たとえば、操作の範囲を定義するクエリを使用して、パブリッシャまたはジャニタといったタスクを指定するとします。このようなクエリでは、タスクを実行するドキュメントのセットが指定されます。
インストールされたタスクを再設定する際に編集しなければならないファイルの詳細については、タスクの登録および設定方法についてを参照してください。例については、インストールされたタスクのカスタマイズを参照してください。
インストールされたタスクを再設定するだけでは、一部のアプリケーションのニーズを満たすことができない場合があります。そのような場合、アプリケーション固有の新しいタスクを作成することもできます。
タスクを作成する場合は、次のようにします。
新しいタスクを登録して設定する際、および作成したJavaクラスを登録する際に編集しなければならないファイルの詳細については、タスクの登録および設定方法についてを参照してください。
タスク、およびタスクに関連付けられたJavaクラスは、プロジェクトのlibrary/ContentMgmtService/ContentMgmtService.spf/ContentMgmtService-confディレクトリで、次の3つのXMLファイルで登録、設定されます。
|
XMLファイル |
機能 |
|---|---|
|
タスクの名前および説明を確立し、定期タスクまたはスケジュール設定されたタスクのどちらであるかを特定します。 |
|
|
タスクを設定します。 |
|
|
タスク(および他のexteNd Director機能)をそれぞれのJavaクラスと関連付けます。 |
tasktypes.xmlのエントリでは、各タスクの名前および説明が確立され、各タスクが周期タスクまたはスケジュール設定されたタスクのいずれか、(または両方)であるかが特定されます。このファイルの構造は、プロジェクトのlibrary/FrameworkService/FrameworkService.spf/DTDディレクトリにあるframework-task-type_3_0.dtdに従っている必要があります。
ファイルを構造化する方法、およびインストールされているdefaultタスク、synchタスク、publishタスクが最初に定義された方法を示したtasktypes.xmlの抜粋は、次のとおりです。
<framework-task-types>
<!-- PERIODIC TASK TYPES -->
<periodic>
<task-type>
<type-name>default</type-name>
<type-descr>The Default Periodic Task</type-descr>
</task-type>
<task-type>
<type-name>synch</type-name>
<type-descr>Periodic CM/Search Engine Synchronization Task</type-descr>
</task-type>
<task-type>
<type-name>publish</type-name>
<type-descr>Periodic Document Publish Task</type-descr>
</task-type>
...
</periodic>
<!-- SCHEDULED TASK TYPES -->
<scheduled>
...
</scheduled>
</framework-task-types>
Default_tasklist.xmlのエントリでは、プロジェクトのlibrary/ContentMgmtService/ContentMgmtService.spf/DTDディレクトリにあるcontentmgmt-task-list_3_0.dtdに従って、各タスクが設定されます。
ファイルを構造化する方法、およびperiodic-publishタスクを設定する方法を示したDefault_tasklist.xmlの抜粋は、次のとおりです。
<contentmgmt-task-list>
...
<periodic-publish>
<task-name>Default Repository Document Publish</task-name>
<description>The Default Repository Document Publish Task</description>
<since-last>false</since-last>
<enabled>true</enabled>
<interval>
<millis>86400000</millis>
<exact>false</exact>
</interval>
<do-all-not-yet-published>false</do-all-not-yet-published>
<do-all-unpublished>false</do-all-unpublished>
<do-all-ready>false</do-all-ready>
<force-publish>false</force-publish>
</periodic-publish>
...
</contentmgmt-task-list>
命名規則 periodic-publishタスクの「タグ名」は、tasktypes.xmlで定義されたとおり、タスクのタイプ(periodic)と名前(publish)がハイフンで結ばれて作成されていることに注意してください。Default_tasklist.xmlファイルに対して、このような命名規則が必要です。
タスクの有効化または無効化
タスクを有効にするには、<enabled>タグのコンテンツをtrueに設定します。タスクを無効にするには、この値をfalseに設定します。
services.xmlファイルには、タスク(および他のexteNd Director機能)をそれぞれのJavaクラスに関連付けるエントリが含まれます。このファイルの構造は、プロジェクトのlibrary/FrameworkService/FrameworkService.spf/DTDディレクトリにあるframework-services_3_0.dtdに従っている必要があります。
periodic-publishタスクの処理方法を示したservices.xmlの抜粋は、次のとおりです。
<\x83 T\x81 [\x83 r\x83 X> <interface>com.sssw.cm.periodic-publish</interface> <impl-class>com.sssw.cm.task.impl.EboDocPeriodicPublishTask</impl-class> <description>Periodic CM Document Publish Task</description> <max-instances>0</max-instances> <startup>M</startup> <namespaced>false</namespaced> </service>
グラフィカルビュー exteNd Directorでは、このファイルのグラフィカルビューも提供されており、このビューでは新しいエントリを追加できます。
新しいタスクのみ 新しいタスクを作成する場合に限り、services.xmlに新しいエントリを追加する必要があります。
Default_tasklist.xmlファイルで設定を編集することによって、インストールされたタスクをカスタマイズします。
次の例では、periodic-publishタスクの定義にドキュメントクエリが追加されています。クエリは、<content-search>要素で指定されます。
追加されたコード(太字で表示)により、periodic-publishタスクが設定され、STATUSがReviewedに設定されたすべてのドキュメントが発行されます。
<periodic-publish>
<task-name>Default Repository Document Publish</task-name>
<description>The Default Repository Document Publish Task</description>
<since-last>false</since-last>
<enabled>true</enabled>
<interval>
<millis>86400000</millis>
<exact>false</exact>
</interval>
<do-all-not-yet-published>false</do-all-not-yet-published>
<do-all-unpublished>false</do-all-unpublished>
<do-all-ready>false</do-all-ready>
<force-publish>false</force-publish>
<content-search>
<where-clause>
<eq>
<var>STATUS</var>
<val>Reviewed</val>
</eq>
</where-clause>
</content-search>
</periodic-publish>
タスク定義内でドキュメントクエリを作成する際に使用可能な要素および値の詳細については、contentmgmt-task-list_4_0.dtdで<content-search>要素の定義を参照してください。
再展開の必要性 タスク設定への変更を有効にするには、アプリケーションEARを再展開する必要があります。
次の手順は、新しいドキュメントをチェックし、新しいドキュメントについて受信者リストに電子メールで通知するnew-doc-notifierという新しいタスクを作成する場合の例に基づいています。
これを行うには、tasktypes.xmlファイルを変更します。タスクは、スケジュール設定されたタスク、定期タスク、またはスケジュール設定されたタスクと定期タスクの両方として、登録できます。次の例では、新しいタスクは、定期タスクです。
<periodic>
.............
<task-type>
<type-name>new-doc-notifier</type-name>
<type-descr>Periodic CM task for notifying of any new documents.</type-descr>
</task-type>
これを行うには、Default_tasklist.xmlファイルに新しい要素を追加します。
<periodic-new-doc-notifier>
<task-name>New Document Notifier</task-name>
<description> Periodic CM task for notifying of any new documents.</description>
<since-last>false</since-last>
<enabled>true</enabled>
<interval>
<millis>86400000</millis>
<exact>false</exact>
</interval>
<!-- any other XML that is specific to the custom task goes here... -->
<!-- for instance, there may be a node here defining the list of email recipients. -->
<recipients>
<recipient>user@myco.com</recipient>
<recipient>user2@myco.com</recipient>
<recipient>user3@myco.com</recipient>
</recipients>
<mail-smtp-host>smtp_host@myco.com</mail-smtp-host>
<subject>New documents have been added</subject>
<text>The following new documents have been added:</text>
</periodic-new-doc-notifier>
「命名規則」 タスク定義(<periodic-new-doc-notifier>)を囲むXMLタグの名前は、タスクのタイプ(periodicまたはscheduled)とDefault_tasklist.xmlにおけるタスクの名前から作成する必要があることに注意してください。このような命名規則が必要とされます。
一般exteNd Directorタスク管理APIは、com.sssw.fw.task.apiパッケージで提供されています。このパッケージには、タスク、タスクタイプ、およびタスク管理に対して、次のような一般的なインタフェースが含まれます。
CMサブシステムでは、独自のタスク管理パッケージ(com.sssw.cm.task.api)でこれらのインタフェースをサブクラスに分類します。EbiTaskMgmtDelegateに加えて、独自のEbiTaskおよびEbiTaskManagerが提供され、タスクを管理するためには、これら3つをすべて使用する必要があります。また、このパッケージには、ドキュメントの発行、期限切れ、削除、およびCMサブシステムとSearchサブシステムエンジン間での同期化などを行うための一般的なインタフェースも含まれます。
独自のカスタムタスクを作成する場合は、次のいずれかのインタフェースを実装する必要があります。
new-doc-notifier のコードでは、NewDocumentNotifier クラスにより、com.sssw.cm.task.impl.EboTaskが拡張され、タスクの義務やタスクの実行方法についての詳細がカプセル化されます。PeriodicNewDocumentNotifierクラスは、NewDocumentNotifierクラスのperiodicサブクラスです。
new-doc-notifierの例に対するJavaコードの完全なリストについては、カスタムタスクのサンプルコードを参照してください。
これを行うには、エントリを<!-- Task management related objects -->のservices.xmlファイルに追加します。
<!-- Periodic tasks -->
........................
<service>
<interface>com.myco.cmtask.api.periodic-new-doc-notifier</interface>
<impl-class>com.myco.cmtask.impl.PeriodicNewDocumentNotifier</impl-class>
<description>The periodic new document notifier class.</description>
<max-instances>0</max-instances>
<startup>M</startup>
</service>
「命名規則」 オブジェクトを正常にファクトリ化およびインスタンス化するためには、インタフェースの命名がタスクの種類およびタイプに対応する必要があることに注意してください。たとえば、periodicおよびnew-doc-notifierは、<interface>ノード値でperiodic-new-doc-notifierにマップします。
ヒント: タスクを停止するには、[中止]ボタンをクリックします。
この節では、Step 3で説明したNewDocumentNotifierクラスに対するJavaコードをリストで示します。
この節にはまた、NewDocumentNotifierクラスのperiodicサブクラスである、PeriodicNewDocumentNotifierクラスに対するコードも含まれています。
package com.myco.cmtask.impl;
//Java imports
import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
// FW imports
import com.sssw.fw.api.*;
import com.sssw.fw.exception.*;
import com.sssw.fw.log.*;
import com.sssw.fw.task.exception.*;
import com.sssw.fw.util.*;
// CM imports
import com.sssw.cm.api.*;
import com.sssw.cm.factory.*;
import com.sssw.cm.task.api.*;
import com.sssw.cm.task.impl.EboTask;
// Other imports
import org.w3c.dom.*;
abstract public class NewDocumentNotifier extends EboTask
{
//
// Constants
//
protected static final String RECIPIENTS = "recipients";
protected static final String RECIPIENT = "recipient";
protected static final String SMTP_HOST = "mail-smtp-host";
protected static final String SUBJECT = "subject";
protected static final String TEXT = "text";
protected static final String SENDER = "sender";
protected static final String NEWLINE = "\n";
protected static final String MAIL_SMTP_HOST = "mail.smtp.host";
protected static final String LINE_SEPARATOR = "line.separator";
// These actually belong in a resource bundle...
protected static final String ERROR = "An error occurred while executing the New Document Notifier task.";
protected static final String DEFAULT_SUBJECT = "New documents have been added";
protected static final String DEFAULT_TEXT = "The following documents have been added:";
protected static final String DEFAULT_SENDER = "notifier@myco.com";
protected static final String LOCATION = "Location: ";
protected static final String TITLE = "Title: ";
protected static final String AUTHOR = "Author: ";
//
// Member variables
//
protected EbiLog m_log; // Our log
protected ArrayList m_recipients; // Notification recipients
protected String m_smtpHost; // SMTP host
protected String m_subject; // Message subject
protected String m_text; // Message text
protected String m_sender; // Sender
protected String m_lineSep; // Line separator
// Constructor
public NewDocumentNotifier()
{
// Use the CM log
m_log = EboLogFactory.getLog(EboLogFactory.CM);
m_recipients = new ArrayList();
m_subject = DEFAULT_SUBJECT;
m_text = DEFAULT_TEXT;
m_sender = DEFAULT_SENDER;
}
// Initialization from XML
public void fromXML(Node node)
{
// Rely on the superclass to get all the general task
// settings
super.fromXML(node);
try
{
NodeList nodes = node.getChildNodes();
if (nodes != null)
{
// Process the nodes
for (int i = 0; i < nodes.getLength(); i++)
{
Node child = nodes.item(i);
String nodeName = child.getNodeName();
if (child.getNodeType() == Node.ELEMENT_NODE)
{
// Recipient list
if (RECIPIENTS.equals(nodeName))
processRecipientList(child);
// SMTP host
else if (SMTP_HOST.equals(nodeName))
m_smtpHost = getElementValue(child);
// Message subject
else if (SUBJECT.equals(nodeName))
m_subject = getElementValue(child);
// Base message text
else if (TEXT.equals(nodeName))
m_text = getElementValue(child);
// Sender
else if (SENDER.equals(nodeName))
m_sender = getElementValue(child);
}
} // end for each node
}
}
catch (Exception ex)
{
EboExceptionHelper.handleException(
ex, // The exception
m_log, // Our log to write exception into
false, // Don\x92 t print stack trace to console
false); // Don\x92 t rethrow as a runtime exception
}
}
// Process the list of recipients provided in the XML task definition
protected void processRecipientList(Node node)
{
NodeList nodes = node.getChildNodes();
if (nodes != null)
{
// Process the nodes
for (int i = 0; i < nodes.getLength(); i++)
{
Node child = nodes.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE)
{
String nodeName = child.getNodeName();
if (RECIPIENT.equals(nodeName))
{
String recipient = getElementValue(child);
if (!EboStringMisc.isEmpty(recipient))
m_recipients.add(recipient);
}
}
}
}
}
// Extract a node value from a Node
public static String getElementValue(Node node)
{
// Entities are often considered separate text nodes;
// for example, Jim's wagon is represented by three
// text nodes "Jim", "'",and "s wagon".Thus all
// children need to be concatenated in order to retrieve
// the proper text node value.
String nodeValue;
if (node.hasChildNodes())
{
Node curNode = node.getFirstChild();
nodeValue = EboStringMisc.m_emptyStr;
while (curNode != null)
{
nodeValue = nodeValue + curNode.getNodeValue();
curNode = curNode.getNextSibling();
}
}
else
nodeValue = EboStringMisc.m_emptyStr;
return nodeValue;
}
// Carry out the task
public void doTask() throws EboTaskException
{
try
{
super.doTask();
EbiContentManager cmgr = EboFactory.getDefaultContentManager();
EbiDocQuery query = (EbiDocQuery)cmgr.createQuery(EbiDocQuery.DOC_QUERY);
// If we\qre to only get the data that\qs changed since
// The time that the task was last run
if (getSinceLast())
{
// Figure out the start of the interval
Timestamp fromTime = getFromTime();
// Figure out the end of the interval
Timestamp toTime = new Timestamp((new Date()).getTime());
EbiQueryExpression expr = null;
EbiQueryExpression expr2 = null;
// Augment the where clause with the time interval
if (fromTime != null)
expr = query.whereCreateDate(fromTime, EbiDocQuery.ROP_GREATER, false);
if (toTime != null)
expr2 = query.whereCreateDate(toTime, EbiDocQuery.ROP_LEQ, false);
// Set the augmented where clause into the query
if (expr != null && expr2 != null)
{
expr.andExpression(expr2);
query.setWhere(expr);
}
}
// Otherwise, we\qll process all the documents
// Get the list of documents
Collection documents = cmgr.findElementsFiltered(m_context, query);
// Send the e-mail notifications
sendNotifications(documents);
}
catch (Exception ex)
{
throw new com.sssw.fw.task.exception.EboTaskException(ex, ERROR);
}
}
// Send the e-mail notifications to our recipients
protected void sendNotifications(Collection documents)
throws EboUnrecoverableSystemException, EboSecurityException,
MessagingException
{
if (!documents.isEmpty())
{
String msgText = getEmailMessageBody(documents);
// For each recipient
for (int i = 0; i < m_recipients.size(); i++)
{
String recipient = (String)m_recipients.get(i);
send(
m_sender, // From
recipient, // To
m_smtpHost, // Host
m_subject, // Subject
msgText); // Yext
}
}
}
// Generate an e-mail
// "The following documents have been added:
//
// <doc 1>
// <doc 2>
// .......
// <doc N>"
protected String getEmailMessageBody(Collection documents)
throws EboUnrecoverableSystemException, EboSecurityException
{
String lineSeparator = getLineSeparator();
StringBuffer buf = new StringBuffer(m_text);
buf.append(lineSeparator);
buf.append(lineSeparator);
Iterator iter = documents.iterator();
while (iter.hasNext())
{
EbiDocument doc = (EbiDocument)iter.next();
buf.append(getDocumentDescriptor(doc));
buf.append(lineSeparator);
buf.append(lineSeparator);
}
return buf.toString();
}
// Send an e-mail
protected static void send(
String from,
String to,
String host,
String subject,
String msgText)
throws MessagingException
{
Properties props = System.getProperties();
props.put(MAIL_SMTP_HOST, host);
Session session = Session.getDefaultInstance(props, null);
// Create a message
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
InternetAddress[] address = { new InternetAddress(to) };
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setText(msgText);
Transport.send(msg);
}
// Generate a document descriptor
// Location: <...>
// Title: <...>
// Author: <...>
protected String getDocumentDescriptor(EbiDocument doc)
throws EboUnrecoverableSystemException, EboSecurityException
{
String lineSeparator = getLineSeparator();
StringBuffer buf = new StringBuffer(LOCATION);
buf.append(doc.getURL(false));
buf.append(lineSeparator);
buf.append(TITLE);
buf.append(doc.getTitle());
buf.append(lineSeparator);
buf.append(AUTHOR);
buf.append(doc.getAuthor());
return buf.toString();
}
// Figure out the line separator to use
protected String getLineSeparator()
{
if (m_lineSep == null)
m_lineSep = System.getProperty(LINE_SEPARATOR, NEWLINE);
return m_lineSep;
}
abstract protected Timestamp getFromTime();
}
package com.myco.cmtask.impl;
//Java imports
import java.sql.Timestamp;
//Framework imports
import com.sssw.fw.task.api.*;
import com.sssw.fw.task.impl.*;
// CM imports
import com.sssw.cm.api.*;
import com.sssw.cm.task.api.*;
// Other imports
import org.w3c.dom.*;
public class PeriodicNewDocumentNotifier
extends NewDocumentNotifier
implements EbiPeriodicTask
{
//
// Protected data
//
protected long m_interval; // Interval, if any
protected boolean m_exact; // Run asap or x millis after // current time
//
// Constructor
//
public PeriodicNewDocumentNotifier()
{
}
public boolean isExact()
{
return m_exact;
}
public long getInterval()
{
return m_interval;
}
public void setExact(boolean exact)
{
m_exact = exact;
}
public void setInterval(long millis)
{
m_interval = millis;
}
public void fromXML(Node node)
{
super.fromXML(node);
EboTaskHelper.getPeriodicDataFromXML(this, node);
}
public String toString()
{
return super.toString() +
", Interval (millis)=" + m_interval +
", Exact=" + m_exact;
}
protected Timestamp getFromTime()
{
// For an interval-based task, the \qfrom\q time is \qnone\q if
// the task has not run once yet; otherwise it\qs
// task_first_scheduled_time + interval*times_task_ran
return (m_timesRan < 1) ? null :
new Timestamp(
m_launchTime.getTime() + m_interval * (m_timesRan - 1));
}
}
タスクイベントは、exteNd Directorイベントモデルフレームワークの拡張子で、「状態変更イベント」、「イベント手順」、および「イベントリスナ」(拒否権付きリスナを含む)で構成されています。この節は、次のトピックで構成されています。
この節では、exteNd Directorイベントモデルおよびイベント処理に精通していることを想定しています。詳細については、『exteNd Directorアプリケーションの開発』のイベントの操作に関する節を参照してください。
APIでは、タスク管理操作に関連する状態変更イベントのセットを定義します。イベントIDは、個々のイベントクラスのほかにcom.sssw.fw.task.event.api.EbiConstantsインタフェースにも表示されます。
一般状態変更イベント また、com.sssw.fw.event.api.EboStateChangeEventで定義された変更のタイプを表す一般状態変更定数があります。
タスクマネージャオブジェクト(com.sssw.cm.task.api.EbiTaskMgmtDelegate)のaddStateChangeListener()メソッドまたはaddVetoableStateChangeListenerメソッドのいずれかを使用します。
addStateChangeListener()のバージョンを使用して指定されたタイプまたはイベントのタイプに登録できます。
public boolean addStateChangeListener(
BitSet events, EbiStateChangeListener listener)
ここで、eventsはイベントIDのビットセットです。
com.sssw.fw.event.api.EbiConstantsで指定したイベントIDを使用します。たとえば、次のコードはタスクの開始、停止、および完了した操作を登録します。
EbiTaskMgmtDelegate tmgr = new EbiTaskMgmtDelegate(); EbiStateChangeListener listener = new EbiStateChangeListener(); // Instantiate a Java BitSet and populate it BitSet events = new BitSet(); events.set(EbiConstants.EVENT_ID_TASK_STARTED); events.set(EbiConstants.EVENT_ID_TASK_STOPPED); events.set(EbiConstants.EVENT_ID_TASK_COMPLETED); // add listener tmgr.addStateChangeListener(events, listener);
exteNd DirectorプロジェクトでFrameworkサブシステムのconfig.xml を開きます。
com.sssw.fw.task.events.enable
Copyright © 2004 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved. more ...