The adoption of JSP frameworks such as Struts has allowed the use of tag libraries in place of JSP elements. In terms of the JEE Analyzer, this has caused some problems resulting in incomplete analysis results (loss of objects and/or links). To explain the situation, take the example of a JSP page that displays the value of a bean property. Using the classic JSP syntax, we would write:
<jsp:useBean id="user" scope="page" class="User" /> <jsp:getProperty name="user" property="firstName" />
After analysis with the JEE Analyzer, the following result would be obtained:
The Jakarta Taglibs project provides a library of tags dedicated to handling beans. The tag:
corresponds to the standard action:
and the code below is re-written:
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <jsp:useBean id="user" class="User" scope="session" /> <bean:write name="user" property="firstName" filter="true" scope="session"/>
If the tag:
is not taken into account during the analysis, the following objects/links will not be created:
- the JSP Bean Property "firstName"
- the "A" link between the JSP file "bean.write.jsp" and the bean "User"
- the "Ar" link between the JSP file "bean.write.jsp" and the property "firstName"
- the "Ae" link between the JSP file "bean.write.jsp" and the Java method "getFirstName"
To get the same results in both cases, it is now possible to configure the J2EE Analyzer so that it takes into account custom actions.
This can be done in two ways:
- via a configuration file (cast-tag.extensions.xml) that describes the actions that need to be undertaken for each library and each of the tags that are defined by the library in question. This file can be found in the sub-folder "configuration/J2EE/WEB-INF" located in the CAST installation folder. An XSD file (cast-tag-extensions.xsd) is available in "CAST_INSTALL_DIR\configuration\J2EE\schemas\" This file is predefined by CAST (see below).
- via a configuration file (with the extension .tagsextension) tailored to a specific framework. You can create multiple .tagsextension files, but they must be placed in the folder defined in the CAST Tags Extension Folder option in J2EE Technology options and each file must define the required taglibs for the specific framework. You can see an example of this implementation for the Struts2 language in the %PROGRAMDATA%\CAST\CAST\Extensions\com.castsoftware.jee.<version>\EnvProf\J2EE\Struts2\struts2x.tagsextension file - it contains only taglibs that are specific to Struts2. The taglibs that you specify in the .tagsextension files must use the SAME format as in the cast-tag.extensions.xml (see below). Note that you must not specify taglibs in a .tagsextension file that already exist in the cast-tag.extensions.xml file.
The cast-tag.extensions.xml consists of several tags that allow you to specify the tag libraries that need to be taken into account during the analysis, the tags that need to be configured and the actions that need to be executed when these tags are analyzed. To specify a tag library, use the "taglib" library and the "uri" attribute to design your URI. The value of this attribute is the same as the value defined in its .tld definition file.
For each tag that you want to take into account, use the "tag" element and the "name" attribute. The name is the same as the name defined in the .tld file.
Actions can be described using four elements: "declare", "call", "search", "create" and "UseOfType". "declare" allows you to declare a variable (in the code of the generated servlet). The other elements specify how this variable is defined, what its type is and how to identify the values of certain attributes of the analyzed custom tag.
To better understand how these elements are combined, the following examples provide some detail (please note that "x" is the value of an atrribute "x" in a custom action):
The custom action <bean:cookie>
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <bean:cookie id="connection" />
and its configuration:
<tag name="cookie"> <declare nameSrc="id" type="javax.servlet.http.Cookie"/> </tag>
This is the most simple use of "declare". The analyzer creates an instance called "id" that has the type "javax.servlet.http.Cookie". In the servlet that is generated, this results in:
javax.servlet.http.Cookie connection = null;
The custom action <bean:define>
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <jsp:useBean id="user" class="User" scope="session" /> <bean:define id="myBean" name="user" property="firstName" toScope="session"/>
The semantic of the code displayed above is: create a bean called myBean in the scope "session" with a type "java" that corresponds to the type of the firstName property in the bean user. Or the following configuration:
<tag name="define"> <create kind="bean" nameSrc="id" scopeSrc="toScope"> <useTypeOf instanceSrc="name" memberSrc="property"> <search kind="bean" nameSrc="name" scopeSrc="scope"> <create kind="bean.property" nameSrc="property"/> </search> </useTypeOf> </create> <declare nameSrc="id"> <useTypeOf instanceSrc="id"> <search kind="bean" nameSrc="id" scopeSrc="scope"/> </useTypeOf> </declare> <call instanceSrc="name" methodSrc="property"> <search kind="bean" nameSrc="name" scopeSrc="scope"/> </call> </tag>
The line <create kind="bean" nameSrc="id scopeSrc="toScope"> instructs the analyzer to create a bean called "id", with the scope "toScope" (n.b.: "id" signifies the value of the id attribute). Each bean is associated to a java class that implements it. To find this class, the action useTypeOf is used.
The code <useTypeOf instanceSrc="name" memberSrc="property"> specifies that the type to be used is the "property" member of the object instance "name". However, the J2EE Analyzer needs to know what type the instance is and how to find it. To do so, the configuration defined by the search element is used. search indicates that the instance is a bean (kind="bean") called "name" (nameSrc="name") and is defined in the scope "scope" (scopeSrc="scope"). When the bean is found, the analyzer can retrieve the type associated to it and which has been specified during the creation of the bean (either using a config file, or using jsp tags :useBean or bean :define). If the attribute memberSrc is specified, the type of the new bean will thus be the same as the parameter of the method set'property' of the bean type or java.lang.Object if such a method does not exist. If not, then the bean type is retained - thus equating to a copy of the already existing bean (two instances of the same bean that have different ids).
The configuration <create kind="bean.property" nameSrc="property"/> requires the creation of a bean-property called "property within the bean introduced by the mother tag (<search kind="bean"...).
The creation of the bean "id" forcing the availability - in the servlet code - of a variable "id" representing the bean, means that care must be taken to generate the corresponding code with the risk of resolution errors during the analysis of the generated code. For this, the action declare is used. Here again, the type of variable to declare is specified via the action useTypeOf.
Please note that in this version:
- The value of the attribute "kind" in the element "search" is always "bean".
- The value of the attribute "kind" in the element "create" is always "bean.property"
|New Attribute||Used in Element (Action)||Description||Possible Values|
|valueSrc||<create kind='bean' valueSrc='content'>||The name of an attribute whose value will be associated to the new bean (usually a scoped attribute).||The name of any attribute of the tag being customized.|
|resolveValueAs||<search kind='bean' resolveValueAs='path;bean'>||Type against which the searched bean's value will be resolved.|
Resolution stops on the first success.
|One or a ';' separated list of the following values:|
- javatype - java-type - java-method - url - bean - server-object - action-mapping
- property-mapping - forward - stxx-pipeline - stxx-transform
- xml-object - config-item - path - resource
|scope||<search kind='bean' scope='session'>||Scope where to search for a bean.||- page - request - session - application|
|<create kind='bean' scope='session'>||Scope where to store the newly created bean.|
In addition, since some scoped attributes used in EL expressions may be introduced by custom tags (JSTL tags for instance), it is important not to forget to configure these tags, using the CAST tags extension mechanism. Not doing so may cause resolution of the attributes to fail. The added configuration instructs the analyzer to create bean and bean properties when required by the semantic of the tag (i.e. simulation of the tag's runtime behaviour).
Default configuration is also provided for the struts-template tags library.
- If you specify the same taglib twice (i.e. once in the cast-tag.extensions.xml file and once in a .tagsextension file) an error will occur during the analysis.
- If your own configuration is not taken into account by the J2EE Analyzer, make sure that the URI of the tag libraries are the same as those in the .tld configuration file.
- When a java type can not be resolved, the default value "java.lang.Object" is used.
- A java type based on an object will not be resolved if the search for the instance is not completed. If this is a bean, make sure that its scope is correct.
- The Tiles library is handled internally and thus should not appear in the configuration file.
- If the scope is not specified (i.e.: @scopeSrc attribute not defined), the bean is searched for in the following order:
- page -request - session - application The first bean that is found will be retained.