Advanced Customization > Info*Engine User’s Guide > Custom Tag Libraries > Task-Based Tag Library Implementation
  
Task-Based Tag Library Implementation
Tag libraries can be written using rules and procedures similar to those used when authoring Info*Engine tasks. Each task (or command delegate if using a federated type identifier) can be exposed as a single tag. The parameters documented using the taskdoc comments of a task are exposed as the attributes of the tag. Metadata on each parameter can be used to control whether a given attribute is required, and whether or not it supports expressions. By default, attributes support expressions and are not required. Parameters that override the defaults may appear as follows:
<!--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}
-->
In this example, metadata on task comments is supplied in curly braces ({ }), and the name is separated from the value by a colon (:). In tags, the @return comment is not used explicitly, but should be included for completeness and to enhance the usefulness of the task.
Specifying a parameter with a type of INFOENGINE_GROUP provides a group from the VDB of the parent task to the VDB of the tag. As such, a tag has access to the contents of the calling task’s VDB, but only to those portions of it that are explicitly required. Array input is added to the tag’s @FORM input as a multivalued parameter. Upon input, the tag inherits all of the calling task’s @SERVER and @AUTH-MAP context information, but not @FORM. Following tag invocation, the tag’s VDB is merged back into the calling task’s VDB.
The calling task’s input and output streams are also associated with whichever tags it calls, so it is possible for a task-based tag to consume input and produce output.
A calling task and the tags it calls can share other information through the “tasklet context.” The tasklet context refers to a pair of maps containing data. Each task gets its own local map to store variable data, and that map is backed by the IeContext object of the overarching request. Each Info*Engine-based request has its own instance of IeContext (com.infoengine.util.IeContext) that can hold contextual information specific to a given request. However, locally-scoped variables in the context are only visible to the task in which they are defined. Sharing information between tasks (and also possibly tags) within the same scope requires request-scoped variables. For more information on the tasklet context, see Expression Language Support.
For example:
<c:set var=“shared” value=“${value}” requestScope=“true” />
Each tag based on an Info*Engine task implicitly supports a child tag that has the same prefix, is named “param,” and has name and data attributes. This tag can be used to supply undocumented parameters to a tag (for example, supplying parameter for a supporting adapter to an existing adapter-based SOAP task). The exception to this rule would be a situation in which the task-based tag libraries already contain a tag named “param”. In this situation the param task takes precedence, and nested param tags are not allowed within that tag library.
Tag Library Organization in the Task Root
There are two primary ways to organize a task-based tag library. The first is to simply create a subdirectory within the task root to hold your tags, and then specify the path of that directory (relative to the task root) as the URI when using your tag library. For example:
<%@taglib uri="/ext/myorg/tags" prefix="my"%>

...
<my:myTag hardCoded="true" required="${expression}" />
...
Each tag within the subdirectory is available as its own tag, and each of its parameters are exposed as its attributes.
Tag Library Organization Using a Federated Type Identifier
The second method of organizing an Info*Engine task tag library is using a federated type identifier. In this situation, the value you specify on the URI attribute is the type identifier with which your tags are associated. This method of organization has the advantage of allowing tags to support federation and hierarchy climbing. If you choose to use hierarchy climbing, a given tag within a tag library can map to multiple tasks, depending on the input given at task delegation. When using this mechanism, every tag implicitly supports an input attribute that allows the caller to supply the input group used to drive task delegation (the exception being tags that already explicitly define an input attribute). Both the unique federation identifier (UFID) and federated type identifier on the input group are implicitly qualified if not explicitly supplied.
If necessary, you can override the type hierarchy climber implementation within your task’s context. Prior to task delegation, you can create a key by replacing “.” with “_” in the federated type identifier, appending _climber (for example, wt_fc_Persistable_climber), and by placing the climber class name in the tasklet context. As a result, the new value for the climber implementation is discovered in the tasklet context and then used during task delegation. The default is to use a Windchill type hierarchy climber, which should be suitable for the vast majority of usages. For an example, see Dispatch-Tasks.
As an example, if you wrote a create method associated with wt.part.WTPart, it could be called as follows:
<%@taglib uri="wt.part.WTPart" uri="prt" %>
...
<prt:create name="myPart" />
...
As previously mentioned, however, this mechanism can be more effective if used with type hierarchies, which would allow for not only dynamic discovery of the appropriate delegate for a task, but also routing to an appropriate system. For example:
<%@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}” />
...
* 
Some of the tags above do not actually exist, but are used here for illustration purposes only.