高度なカスタマイズ > Info*Engine ユーザーガイド > カスタムタグライブラリ
  
カスタムタグライブラリ
以下のトピックでは、Info*Engine のカスタムタグライブラリの実装および使用と、カスタムタグ内での定義式言語の使用について説明します。
カスタムタグライブラリについて
Info*Engine タスクコンパイラでは、カスタムタグライブラリの概念がサポートされています。Info*Engine タスクのカスタムタグライブラリは、JSP でサポートされているものと似ています。さまざまな組み合わせの Info*Engine タスクを使用するときに、カスタムタグライブラリを実装します。これを構成する方法には、共通のサブディレクトリ内で構成する方法と、タイプ識別子に関連付けられているフェデレーションタスク委任として構成する方法があります。これにより、Java コードを記述またはコンパイルすることなく、再利用可能なタグ機能を簡単に作成できます。より高度な機能が必要な場合は、カスタムタグライブラリを一連の Java クラスとして実装できます。これらの Java クラスは、タグライブラリ記述子 (TLD) と呼ばれる XML ドキュメントによって記述されます。これは、クラスを Info*Engine タスクで使用できるように適切なタグに関連付けます。
タスクと Java タグライブラリの両方を実装することにより、特定の属性が必要であるかどうか、および特定の属性で定義式を使用できるかどうかを指定できます。タグライブラリを作成するとき、公開される属性ごとにどのような設定が適切であるかを慎重に検討する必要があります。属性が required としてマークされている場合、タグの実装はその存在を確認する必要がありません。Info*Engine では、必要な属性値を提供しないタグを使用するタスクはコンパイルされません。
属性で定義式が使用できる場合でも、null 以外の値を指定できます。ただし、それよりも、属性で埋め込み定義式を使用できるかどうかのほうが重要です。定義式の評価は過度に高コストではないものの、論理的には、ハードコード化されている属性は、定義式を使用できない属性としてマークする必要があります。属性が定義式を使用できる属性としてマークされている場合でも、Info*Engine タスクコンパイラは、不要な間接費の発生を回避するため、その属性の値を検証して、実行時に定義式を評価する必要があるかどうかを決定します。詳細については、定義式言語のサポートを参照してください。
タスクベースのタグライブラリの実装
タグライブラリは、Info*Engine タスクを作成するときに使用するものと同様の規則と手順を使用して作成できます。それぞれのタスク (フェデレーションタイプ識別子を使用する場合はコマンド委任) は、単一のタグとして公開できます。タスクのタスクドキュメンテーションのコメントを使用してドキュメント化されているパラメータは、タグの属性として公開されます。各パラメータのメタデータを使用して、特定の属性が必要であるかどうか、および特定の属性で定義式を使用できるかどうかを制御できます。デフォルトでは、どの属性も必須ではなく、どの属性でも定義式を使用できます。デフォルトをオーバーライドするパラメータは以下のとおりです。
<!--com.infoengine.soap.rpc.def
This is the tag description.
@param boolean hardCoded No Expressions {rtexp:false}
@param string required Is required {required:true}
@return INFOENGINE_GROUP ${output}
-->
この例では、タスクのコメントのメタデータは波括弧 ({ }) で囲まれており、その名前はコロン (:) で値から区切られています。@return コメントは、タグ内で明示的に使用されることはありませんが、完全性を確保するため、およびタスクの実用性を高めるためにタグに含めるようにしてください。
INFOENGINE_GROUP タイプのパラメータを指定すると、親タスクの VDB からタグの VDB に 1 つのグループが提供されます。このような場合、タグは呼び出しタスクの VDB のコンテンツにアクセスできますが、明示的に必要とされている部分に限られます。配列入力は、複数の値をとるパラメータとして、タグの @FORM 入力に追加されます。入力時に、タグは呼び出しタスクの @SERVER および @AUTH-MAP のすべてのコンテキスト情報を継承しますが、@FORM のコンテキスト情報は継承しません。タグを呼び出したら、タグの VDB が呼び出しタスクの VDB にマージされます。
呼び出しタスクの入力および出力ストリームも、そのタスクが呼び出すタグに関連付けられるため、タスクベースのタグが入力を消費し、出力を生成することが可能です。
呼び出しタスクとそれが呼び出すタグは、タスクレットコンテキストを通じてほかの情報を共有できます。タスクレットコンテキストとは、データを含んでいる 1 対のマップのことです。それぞれのタスクには、変数データを保存するための独自のローカルマップが割り当てられます。このマップは、包括的なリクエストの IeContext オブジェクトによって支えられています。Info*Engine ベースのリクエストには、それぞれ独自の IeContext (com.infoengine.util.IeContext) のインスタンスがあり、これには特定のリクエストに固有のコンテキスト情報を保存できます。ただし、コンテキスト内のローカル範囲の変数は、それらが定義されているタスクでのみ認識されます。同じ範囲内のタスク間 (または場合によってはタグ間) で情報を共有するには、リクエスト範囲の変数が必要です。タスクレットコンテキストの詳細については、定義式言語のサポートを参照してください。
以下に例を示します。
<c:set var=“shared” value=“${value}” requestScope=“true” />
Info*Engine タスクを基盤とするタグは、同じプリフィックスを持ち、param という名前で、name および data 属性を持つ子タグを暗黙的にサポートします。このタグは、ドキュメント化されていないパラメータをタグに提供するために使用できます (たとえば、補助アダプタのパラメータを既存のアダプタベースの SOAP タスクに提供するなど)。この規則の例外として、タスクベースのタグライブラリに param というタグがすでに含まれている場合があります。この状況では、param タスクが優先され、ネストされている param タグをそのタグライブラリ内で使用することはできません。
タスクのルートにおけるタグライブラリの構成
タスクベースのタグライブラリを構成する主な方法には 2 つあります。1 つは、単にタスクのルート内にタグを格納するためのサブディレクトリを作成し、タグライブラリを使用するときに、そのディレクトリのパス (タスクのルートを基準とする相対パス) を URI 形式で指定する方法です。以下に例を示します。
<%@taglib uri="/ext/myorg/tags" prefix="my"%>
...
<my:myTag hardCoded="true" required="${expression}" />
...
サブディレクトリ内の各タグは独自のタグとして使用でき、そのパラメータはそれぞれその属性として公開されます。
フェデレーションタイプ識別子を使用したタグライブラリの構成
もう 1 つは、フェデレーションタイプ識別子を使用して Info*Engine タスクのタグライブラリを構成する方法です。この場合、タグが関連付けられているタイプ識別子を URI 属性の値として指定します。この構成方法には、タグでフェデレーションと階層クライミングを使用できるという利点があります。階層クライミングを使用する場合は、タスク委任で提供される入力に応じて、タグライブラリ内の特定のタグを複数のタスクにマッピングできます。このメカニズムを使用する場合は、すべてのタグで、暗黙的に、タスク委任を実行するために使用される入力グループを呼び出し元が指定できるようにする input 属性を使用できます (input 属性をすでに明示的に定義しているタグは例外)。入力グループの Unique Federation Identifier (UFID) とフェデレーションタイプ識別子の両方が明示的に指定されていなければ暗黙的に修飾されます。
必要に応じて、タスクのコンテキスト内でタイプ階層クライマの実装をオーバーライドできます。タスク委任の前に、フェデレーションタイプ識別子の ._ に置き換え、_climber (たとえば wt_fc_Persistable_climber) を追加し、クライマのクラス名をタスクレットコンテキストに配置することで、キーを作成できます。その結果、クライマの実装の新しい値がタスクレットコンテキストで検出され、タスク委任中に使用されます。デフォルトでは、Windchill のタイプ階層クライマが使用されます。これは、大半の使用状況に適しています。これの例については、Dispatch-Tasksを参照してください。
1 つの例として、wt.part.WTPart に関連付けられている create メソッドを作成したとすると、これは以下のように呼び出されます。
<%@taglib uri="wt.part.WTPart" uri="prt" %>
...
<prt:create name="myPart" />
...
ただし、前述のように、このメカニズムは、タイプ階層とともに使用されたほうが効果的であり、これによりタスクに適切な委任が動的に検出されるだけではなく、適切なシステムへのルーティングも行われます。以下に例を示します。
<%@page language="java"%>
<%@taglib uri="http://www.ptc.com/infoengine/taglib/core" prefix="ie"%>
<%@taglib uri="/org/myorg/util/" prefix="util"%>
<%@taglib uri="http://www.ptc.com/infoengine/taglib/log" prefix="log"%>
<%@taglib uri="/com/infoengine/tlds/iejstl.tld" prefix="c"%>
<%@taglib uri="WCTYPE|wt.fc.Persistable" prefix="obj"%>
...
<!-- create a document in two systems (assumed tag implementations) -->
<util:query type="wt.org.WTPrincipal"
where="uid='${@SERVER[0]auth-user[0]}'"
attribute="name,cabinetRef" groupOut="me" />
<!-- create the task delegate input -->
<ie:webject name="Create-Group" type="GRP">
<ie:param name="ELEMENT"
data="CLASS=wt.doc.WTDocument~name=${@FORM[]docName[]}~folderingInfo.cabinet=${me[0]cabinetRef[0]}"/>
<ie:param name="DELIMITER" data="~" />
<ie:param name="GROUP_OUT" data="doc"/>
</ie:webject>
<!-- create the document in this system -->
<log:debug message=”creating document ${doc[0]name[0]} locally” />
<obj:Create input=”${doc}” />
<!-- create the document in another system -->
<log:debug message=”creating document ${doc[0]name[0]} remotely” />
<c:set var=”${doc[0]obid}” value=”@otherdomain.myorg.org” />
<obj:Create input=”${doc}” />
...
* 
上述のタグのいくつかは、実際には存在せず、ここでは説明に使用することのみを目的としています。
Java ベースのタグライブラリの実装
Java ベースのタグライブラリを作成したほうが適切な場合があります。たとえば、現在 Info*Engine で利用できないほかの Java ベースの API と統合する必要があるため、スクリプトレットのコードをタスク内 (またはタスクベースのタグ内) に埋め込む必要がある場合などがあります。Java ベースのタグライブラリの実装を作成するとき、一連のインタフェースと補助ベースクラスを実装でき、これらは Info*Engine タスク内でタグとして再利用できます。クラスとインタフェースの詳細については、インストールに付属の Java ドキュメンテーション (/codebase/infoengine/docs/apidocs) 内の com.infoengine.task.tagext パッケージを参照してください。
この場合、タグは単純なイベント駆動型の Java クラスであり、これらのタグはタグライブラリ別にグループ化して分類できます。これを行うには、タグライブラリ記述子 (TLD) と呼ばれる簡単な XML ドキュメントを使用します。これは、ライブラリ、ライブラリで使用できるタグ、各タグで使用できる属性、およびタグとその属性に関する情報を定義します。TLD は、ルート taglib ノード、オプションの description ノード、および任意の数の子 tag ノードで構成されます。tag ノードは、それぞれタグライブラリ内のタグを定義し、そのタグをその実装クラスに関連付けます。tag ノードには、name 子ノード (タグ名を指定) と tagclass 子ノード (タグ実装クラスを指定) が含まれている必要があり、オプションで 1 つの description ノードといくつかの attribute ノードを含めることができます。
attribute ノードはどれも、追加されると、タグで使用できる属性を指定します。その属性が必要であるかどうか、およびその値として定義式を指定できるかどうかは問われません。このため、attribute ノードには、この情報を提供するために namerequired、および rtexprvalue 子ノードが必要です。TLD ファイルの一部分の例を以下に示します。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<description>My taglibrary.</description>
<tag>
<name>myTag</name>
<description>what this taglibrary does</description>
<tagclass>org.myorg.tags.MyTag</tagclass>
<attribute>
<name>myAttribute<name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
...
</taglib>
この場合、タグライブラリには myTag というタグが含まれており、これは org.myorg.tags.MyTag クラスによって実装されます。このタグには myAttribute という単一の属性が必要であり、これには定義式を指定できます。タグを Info*Engine タスク内に含めるには、タスク内のタグに使用するプリフィックスを定義する @taglib ディレクティブをタスク内で指定し、また、TLD ファイルのロケーション (Info*Engine タスクのルート内にある) も指定する必要があります。たとえば、このタグは、以下のように Info*Engine タスク内で使用できます。
<%@taglib uri=”/org/myorg/myTags.tld” uri=”pfx”%>
...
<pfx:myTag myAttribute=”${@FORM[]myAttributeValue[]}” />
タグの属性は、標準の Java Beans のような set アクセッサメソッドを使用して、タグに提供されます。タグライブラリを読み込むとき、Info*Engine はこれらの実装の詳細をすべて確認します。サポートされている属性に set メソッドがないなど、実装の詳細が原因でタグを適切に読み込むことができない場合には、エラーが発生します。上記の例では、以下のようにタグに set メソッドを使用することもできます。
public void setMyAttribute ( String value )
{
// perhaps set an instance variable or other work
// related to the attribute value specified in the value
// parameter.
}
タグの属性には任意のデータタイプを使用でき、実行時に必要に応じて値が確認されるか強制的に設定されます。サポートされているパラメータ値のデータタイプは以下のとおりです。
String
int
boolean
float
com.infoengine.object.factory.Group
Object
強制設定は、Stringintboolean、および float というプリミティブなタイプに対してのみサポートされています。Object が含まれているため、使用可能なあらゆるタイプの属性を使用できますが、この場合、必要とされるすべてのタイプについて、set メソッドで属性値を検証するか強制的に設定する必要があります。
タグ (com.infoengine.task.tagext.Tag の実装) には、単純なものもあれば、子要素を含むもの (com.infoengine.task.tagext.BodyTag の実装) もあります。BodyTag のインスタンスでは、作業版数もサポートされています。Tag または BodyTag では、例外を処理する方法として TryCatchFinally を実装することもできます。
一般的に、タグが TagSupport または BodyTagSupport ベースクラスを拡張し、必要な do*Tag メソッドで属性の set メソッドと機能を追加して実装を完了します。
さらに、タグは、スクリプトレットコードから、または定義式言語から再利用するために、タスク内で変数を暗黙的に設定するように設計できます。タグでは、com.infoengine.task.tagext.Tag で定義されている以下のメソッドを実装することで、これをサポートできます。
Tag.VariableInfo[] getVariableInfo ( Map<String,String>atts );
このメソッドは、タスクのコンパイル時にのみ呼び出され、暗黙の変数がコンパイルされたタスクのソースで定義される必要があるかどうかを決定します。getVariableInfo メソッドの詳細とこの機能の使用方法については、Java ドキュメンテーションを参照してください。
実行時、タグは大量の短命オブジェクトの作成に関連するパフォーマンス上の問題を回避するためにプーリングされます。これにより、過度のガーベジコレクションが必要とされることあります。したがって、タグがオプションの属性を使用し、属性値をインスタンス変数に保存する点に注意する必要があります。その場合は、finally ブロック内で doEndTag メソッドを実装し、インスタンス変数を再初期化します。これを行わず、タグが前に使用したときのインスタンス変数の値を保持していれば、タグが後で使用するときに予測どおりに機能しない可能性があります。