Note that the CAST Script / FlexFramework feature described in this page is deprecated. You should instead consider using the Extension SDK to handle XML configuration files.
Introduction
A web application can contain many configuration files that can be split into two categories:
- The Application Descriptor (usually called web.xml)
- Framework specific XML configuration Files such as struts-config.xml, tiles-definitions.xml, etc. - predefined Environment Profiles for specific frameworks and are selected by default or custom profiles can be created. You can also use the JEE Analysis Unit editor to select XML files individually or per folder.
Application Descriptor
The Application Descriptor is a standard file specified by JSP specifications. Hence, its format is well known and the JEE Analyzer can predict how to process it. This is in fact what it does. The only information it needs to know is the path of this file. Once located and then analyzed, the following objects/links are created:
- Application Descriptor (the whole file)
- Servlet (for each <servlet> xml element)
- Servlet Mapping (for each <servlet-mapping> xml element)
- Access Forward link between each Servlet and its corresponding Servlet Mappings.
Note that if a Tiles Definition file is referenced in the application descriptor, this file will also be located and then analyzed. This is triggered by the following code fragment:
<init-param> <param-name>definitions-config</param-name> <param-value>/WEB-INF/tiles-defs_a.xml,/WEB-INF/tiles-defs_a.xml</param-value> </init-param>
In this case, you should not associate the tiles definitions file with an XML Query File/XQuery File (see section on tiles below). Note also that this can also be triggered when present in the struts-config.xml file.
Framework specific XML Configuration Files
Framework specific files use proprietary formats. Since these files have an open structure, the JEE Analyzer does not know where relevant information is located within these files and thus requires some precision from the user. To allow this, the JEE Analyzer provides various ways to specify which piece of information to retrieve and what to do with it (create an object, create links, etc.).
The two main configuration mechanisms are listed below.
- XQuery files are the default way to handle frameworks. XML Query files will be deprecated in a future release. For new customizations, please use XQuery and castscript (FlexFramework).
- CAST provides a variety of default XML Query files/XQuery file for various frameworks, which are ordinarily provided via a predefined Environment Profile depending on the Frameworks you include in the analysis. If you require direct access to these XML Query files/XQuery files, they are located in the %PROGRAMDATA%\CAST\CAST\Extensions\com.castsoftware.jee.<version>\EnvProf\J2EE sub-folder. Before writing your own files (and creating your own custom Environment Profiles), take a look at these files and make sure your requirements are not already covered.
XQuery
This method is based on XQuery and Zorba processor (http://www.zorba-xquery.com/) outputting the results to an intermediate .castscript language. This is known as the J2EE Analyzer - FlexFramework and is the default process used.
This mechanism will take into account third-party frameworks that are increasingly difficult to manage via the existing XML Query file mechanism (see below). The analysis process functions as follows (a brief overview):
- the analyzer analyzes the .java file and retains information about Java annotations in memory. These annotations can be queried from castscript native functions.
- XML configuration files for the Frameworks used in your JEE projects are parsed with Zorba using an XQuery file either supplied by CAST (via an Environment Profile) or defined yourself.
- the resulting output is called a "CAST Script" (.castscript file). The castscript Interpreter will interpret the generated castscript and all custom functions and castscript libraries it depends on to query the Java objects, Java annotations or external technology objects (such as COBOL program, C/C++ functions...) in memory and create objects, links and properties where needed.
- when complete, the objects, links and added properties are saved in the CAST Analysis Service schema.
XML Query files
This configuration mechanism consists of an XML file containing XPATH queries that are used to locate the information required by the analyzer. This is largely a legacy method used only for certain frameworks (such as Spring).
Handling custom frameworks
The JEE Analyzer uses Environment Profiles to define that a specific XML file is handled through in a specific way (used to create objects, objects properties and links). To create the associations, you need to create an Environment Profile (if it doesn't already exist) for the framework you want to handle and then process as follow:
The Environment Profile allows you to define which XML file will be associated to an XML Parsing Mode through the following methods:
- XML Filename Pattern: when the XML filenames follow a specific pattern. You can specify for example that all hbm.xml must be analyzed with the cast-hibernate-config-2-1-7.xml query file. To do this, you must specify **.hbm.xml (note not just one wildcard!).
- XPath: when the XML files share a specific XPath that is not present in other types of XML. For example: beans/bean for spring files.
- DTD Pattern: when all XML files reference a specific DTD. For example, all spring files reference the DTD "-//SPRING//DTD BEAN//EN"
- XSD Pattern: when all XML files reference a specific XSD or namespace. You can specify for example that all orm.xml files (defined by JPA specification) reference the namespace xmlns="http://java.sun.com/xml/ns/pseristence/orm".
- XML File: when all previous methods fail, you can use this one. But this prevents you dynamically associating XML files to a specific XML Query file, since the association is a static file.
When you specify different associations, an OR is applied on them. So if one of them works, the XML will be handled by the specified XML.
The XML Parsing Mode allows you to choose how you will extract the XML information and process them:
- XQuery: Recommended method. Information is extracted and a script in CAST Script Language is generated through XQuery processing using the Zorba processor.
- Custom: Information is extracted and a script in CAST Script Language is generated through an executable of your choice such as an XSLT processor.
- CAST XML Query: legacy method where the XML Query file contains specific tags to order the JEE analyzer to create objects, links and add properties that are extracted through XPath instructions.
- Ignore: to ignore specific XML files that are meaningless to prevent the JEE Analyzer from warning you about these. Doing so when running a new analysis will mean that you are only warned about new XML types.
Manage XML with the FlexFramework
The method for validating a CAST script file is to add log instructions in the generated CAST script, start an analysis and check through the CAST Management Studio logs to see whether the objects and links are created. Also, you can use CAST Enlighten to check whether the objects are created with the correct links. Because running the analysis on the entire application can take a great deal of time, it is better to create a specific analysis that references only the specific XML files that require analyzing and related dependencies (often JAVA files that contain the classes referenced in the XML and/or other XML files that are referenced).
Making syntax errors in the XQuery is easy and will result in errors in the analysis log file. This is why you must use a tool that is able to validate the XQuery file. You can find free tools to do this, such as the XQuery Development Toolkit (XQDT) Eclipse plugin (https://wiki.eclipse.org/XQuery_Development_Tools) that you can install as an Eclipse plugin.
When these conditions are met, you can start to create your XQuery file and CAST Script functions where required. The best way to handle an XML file is to use XQuery or other XML extractor to ONLY extract information to output a CAST script that will call a custom CAST Script function with these values. This way, you separate the aspect of extraction in the XQuery file and the logic of creation and modification in the CAST Script function.
Extracting information with XQuery
If you want to create your own XQuery file for use against a framework that CAST does not yet support, you need to know various things:
- How to write an XQuery file - see https://www.w3schools.com/xml/xsl_functions.asp. You can also look at predefined XQuery files provided by CAST and located in %PROGRAMDATA%\CAST\CAST\Extensions\com.castsoftware.jee.<version>\EnvProf\J2EE
- What the JEE Analyzer expects as output resulting from the parsing process. The output needs to conform to certain syntax rules, for example:
use Core.xxx; use Core.ConstantsMetamodel; /* call to CAST Script function /* createComponent(" name ", type) ; /* for type, refer to Core.ConstantsMetamodel */
- CAST provides certain common XQuery functions that you can call in your own XQuery files. These functions are located in the file CAST_BasicFunctions.xq stored in %PROGRAMDATA%\CAST\CAST\Extensions\com.castsoftware.jee.<version>\EnvProf\J2EE\XQueryLibrary
To call them in your own XQuery files, use the line:
import module namespace castbasics = "http://www.castsoftware.com/castbasics" at "../XQueryLibrary/CAST_BasicFunctions.xq";
One way to do this is to look at the EJB3_ejb-jar_GenCASTScript.xq file (in %PROGRAMDATA%\CAST\CAST\Extensions\com.castsoftware.jee.<version>\EnvProf\J2EE\EJB3) and EJB3.castscript (in CAST_INSTALL_DIR\configuration\Script_Libraries\Core\EJB) and use them as a reference guide.
ejb-jar.xml file extract:
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee [http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd]" version="3.0"> <enterprise-beans> <!-- Configure the message driven bean that will listen to the ChatBean queue --> <message-driven> <ejb-name>ChatBean</ejb-name> <ejb-class>org.superbiz.mdb.ChatBean</ejb-class> <messaging-type>javax.jms.MessageListener</messaging-type> <transaction-type>Container</transaction-type> <message-destination-type>javax.jms.Queue</message-destination-type> <message-destination-link>ChatBean</message-destination-link> <!-- Allow the connection factory to be looked up via java:comp/env/ConnectionFactory --> <resource-ref> <res-ref-name>ConnectionFactory</res-ref-name> <res-type>javax.jms.ConnectionFactory</res-type> </resource-ref> <!-- Allow the reply queue to looked up via java:comp/env/AnswerQueue --> <resource-ref> <res-ref-name>AnswerQueue</res-ref-name> <res-type>javax.jms.Queue</res-type> </resource-ref> </message-driven> [...] </enterprise-beans> [...] </ejb-jar>
EJB3_ejb-jar_GenCASTScript.xq file extract:
declare namespace ejb3 = "http://java.sun.com/xml/ns/javaee"; (1) import module namespace castbasics = "http://www.castsoftware.com/castbasics" at "../XQueryLibrary/CAST_BasicFunctions.xq"; (2) [...] declare function local:createEJBMDB( $ejb as element()) as xs:string { let $ejbName := $ejb/ejb3:ejb-name let $ejbClassName := $ejb/ejb3:ejb-class (5) return concat("createEJBMDB (""",$ejbName, """,""",$ejbClassName,""");", castbasics:CR()) }; (: declaration of global variables :) (3) concat("use Core.J2EE;", castbasics:CR{color}()), concat("use Core.Log;", castbasics:CR{color}()), concat("use Core.Error;", castbasics:CR{color}()), concat("use Core.ConstantsMetamodel;", castbasics:CR{color}()), concat("use Core.EJB.EJB3;", castbasics:CR{color}()), (: creation of stateless EJB :) for $stateless in /ejb3:ejb-jar/ejb3:enterprise-beans/ejb3:session[contains(ejb3:session-type, 'Stateless')] return local:createEJBSession($stateless,"Stateless"), [...] (: creation of message driven bean EJB :) for $mdb in /ejb3:ejb-jar/ejb3:enterprise-beans/ejb3:message-driven return local:createEJBMDB($mdb) (4)
- Because the XML tags in the ejb-jar.xml use the default namespace (instruction xmlns) http://java.sun.com/xml/ns/javaee, it means that you must use it to query any nodes of this XML. So first we must declare this namespace that we will use after.
- The instruction import will load a XQuery library that defines basic functions. We will use some basic XQuery functions such as castbasic:CR() to output a carriage return.
- Before generating a script instruction that will call a function, we must first declare the CAST Script module that we will use.
- To create an EJB Message Driven Bean in CAST, we need the EJB name and the implementation class full name. So we will parse all nodes called message-driven and extract these values with a local XQuery function local:createEJBMDB. Note that we use the namespace to query the nodes through the alias "ejb3:". "$mdb" that refers to each XML node defined by the XPath /ejb3:ejb-jar/ejb3:enterprise-beans/ejb3:message-driven
- The local function local:createEJBMDB extracts the EJB name from the XPath $ejb/ejb3:ejb-name and the EJB implementation class from the XPath $ejb/ejb3:ejb-class. Then it will output a call to a CAST Script function: createEJBMDB. With the ejb-jar.xml sample, the output from the XQuery processor will be:
use Core.Log; use Core.Error; use Core.ConstantsMetamodel; use Core.EJB.EJB3; createEJBMDB("ChatBean", "org.superbiz.mdb.ChatBean");
This generated CAST Script will be interpreted by the JEE analyzer. All the information required to create the EJB Message Driven Bean has been passed to the CAST Script function createEJBMDB.
Note that to test your XQuery file before using the analyzer, you can use the following command to see the generated castscript file:
CAST_INSTALL_DIR\ThirdParty\Zorba_v3_0\bin>zorba.exe -f -q <XQuery file> --context-item <XML File>
Building a CAST Script function
- If you want to develop your own functions that will be outputted into the .castscript file, then you must specify these functions and their parent files in a specific location. You can use the CAST Script Library Directory option located in the Platform Settings tab (see JEE - Analysis configuration) to define this location.
- CAST provides certain castscript Native Functions that can be called by your functions. These functions are located in the folder and sub-folder CAST_INSTALL_DIR\configuration\ Script_Libraries\Core
- Write your function in a file under the location you defined in .1
- Please see FlexFramework - Description of the castscript language for more information.
- You can retain the outputted .castscript files by specifying a local or network location in the Debug options when you Run an analysis (see option Keep Generated CAST Scripts from XML and Annotations)
- You can use the Activate CAST Scripts Traces option in the Debug options when you run an analysis to display messages in the log relative to the processing of the .castscript files. This can help trace problems and issues with your XQuery files.
Continuing the EJB example, using the Message Driven Bean name and implementation class we will:
- Create the Message Driven Bean object in the Knowledge Base
- Create a prototype link from this bean to the implementation class
- Add a property on the bean to set the implementation class name
Note that these objects, properties and links depend on the type of object that you have to create. When you define a custom CAST Script file, you must first set the path to your Custom CAST Script Library Directory through the Technology > J2EE > Platform Setting menu (see JEE - Analysis configuration):
Then you can create a file with the name of your choice and you can also create sub-directories in this library in the same way you do for a Java package. Note that the difference here is that when you can't reference a set of files within a directory with the '' (like import java.), but you must reference them file by file.
Now, you can edit the script file and use all the functions and constants defined in CAST_INSTALLATION_DIR\configuration\Script_Libraries. Let's continue our previous sample and look at an extract of the function createEJBMDB:
Extract of CAST_INSTALLATION_DIR\configuration\Script_Libraries\Core\EJB\EJB3.castscript
module Core.EJB.EJB3; (1) use Core.J2EE; use Core.ConstantsMetamodel; (2) use Core.Log; use Core.Error; void createEJBMDB(string ejbName, string ejbClassName) { (3) symbol ejbSym = findOrCreateSymbol(ejbName, JV_EJB_MESSAGE); (4) if (ejbSym == null) {exit ("impossible to create the EJB MDB: " (5) + ejbName);} log("created JV_EJB_MESSAGE: " + ejbName, DEBUG); symbol ejbClassSym = findUniqueSymbol(ejbClassName, JV_CLASS); if (ejbClassSym == null) {exit ("impossible to find the class: " + ejbClassName);} addOrReplaceProperty(ejbSym, Cast_EJB_AllProperties_BeanClass, ejbClassName); createLink(ejbSym, ejbClassSym, prototypeLink); log("created link from JV_EJB_MESSAGE: " + ejbName + " (6) to JV_CLASS: " + ejbClassName, DEBUG); }
- First you have to declare the module that is equal to the name of sub-directories starting from the "Custom CAST Script Library Root Path" directory + "." + the name of your file without the extension castscript.
- Then you have to import any modules required to build your function.
- Declare your function with the type returned, its name and its parameters.
- Use the CAST Script function findOrCreateSymbol to create the Message driven bean. Note that the object type set by the second parameter is a name that is defined in the Core.ConstantsMetamodel module. This will order the J2EE analyzer to create an EJB Message Driven Bean whose name will be the value of the parameter ejbName.
- At any step of your Script, you can exit (with the exit function) if an error that stops the process occurs. This will report an error in and stop the parsing of this XML file.
- At any step of your script, you can log a message with the level DEBUG. This message will appear in the CAST Analysis Log only if you select the "Enable CAST Scripts DEBUG" checkbox in the J2EE Job under General Configuration > Trace Settings. This function is very useful when you want to understand why a function doesn't work or if it produces the expected behavior.
Managing SQL embedded in XML through CAST Scripts
Often SQL queries are externalized in an XML file and it is very important to manage them well so that you will benefit from all current SQL quality rules and metrics but also from future Quality Rules. If you are using an ORM framework such as Hibernate or an implementation of JPA, then you have to use the default Hibernate Environment Profile and it will create the right objects for native SQL requests as well as JPQL requests and HQL requests for which some rules are already available. Note that if you use an implementation of JPA that is not Hibernate, to manage it and adapt if for specific framework annotations, you have to duplicate the Hibernate Environment Profile and adapt the CAST XML Queries to manage them or use CAST Script for them in addition to CAST XML Query file already made for Hibernate.
If it's another framework, custom or another ORM, then you have to create your own Environment Profile with a CAST Script and XQuery file. Even if there are other parsing methods to manage XML and annotation based framework CAST Script and XQuery file is the most powerful way to manage them and is the method on which CAST will invest in the future to make it even more powerful.
To manage these SQL queries a dedicated object type has been defined: Cast_SQL_NamedQuery.
Whenever you meet an SQL query in an XML file, you have several things to do:
- Extract the name of the query and the SQL query itself through XQuery and output a CAST Script that will call a CAST Script function with at least these two parameters. More parameters could be needed if you have to create other objects or to make links with other objects.
- Write the CAST Script function that will create the Cast_SQL_NamedQuery object
- To create the link from the Java code to this SQL named query, you must add parameterized rule for any Java methods that take the name of the SQL Query as a parameter:
Sample:
You have an XML that looks like this:
sql_in_xml.xml
<root> <dao class="com.ltd.AccountingDao"> <sql> "SELECT NB, VALUE FROM ACCOUNT WHERE NB = ?" </sql> </dao> <dao class="com.ltd.FinanceDao"> <sql> "SELECT NB, VALUE FROM FINANCE WHERE NB = ?" </sql> </dao> [...] </root>
Extraction of Name and SQL query
To extract the SQL query, its name and generate the CAST Script, you have to write the following XQuery (we suppose here that you will create a CAST Script function in the module Custom.DaoSQL and with the signature void createSQLNamedQuery(string class, string sqlRequest)):
extract_sql_from_xml.xquery
(: definition of module to use :) "use Custom.DaoSQL;", (: creation of SQL Named Queries :) for $sql in /root/dao return concat("createSQLNamedQuery(""",$sql/@class,""",""", fn:normalize-space($sql/sql),""");")
- In this XQuery file we used the function fn:normalize-space(string) to remove leading and trailing spaces from the specified string. You can find more XQuery functions here: https://www.w3schools.com/xml/xsl_functions.asp
- To use this XQuery file with CAST, you must reference this XQuery file in an Environment Profile. For example, you can create a CustomDao Environment Profile and in the XML tab select Add XML with the XPath= /root expression, the XML Parsing Mode = XQuery and reference this XQuery file. Then you must reference this Environment Profile in your J2EE Job and ensure that Configuration Files > XML Files selection contains the XML files with the SQL requests.
This XQuery file produces the following output when applied on the previous XML:
use Custom.DaoSQL; createSQLNamedQuery("com.ltd.AccoutingDao","SELECT NB, VALUE FROM ACCOUNT WHERE NB = ?"); createSQLNamedQuery("com.ltd.FinanceDao","SELECT NB, VALUE FROM FINANCE WHERE NB = ?");
Note that to test your XQuery file before using the analyzer, you can use the following command to see the generated castscript file:
CAST_INSTALL_DIR\ThirdParty\Zorba_v3_0\bin>zorba.exe -f -q <XQuery file> --context-item <XML File>
Define the cast script function to create the object and links
Now, we have to define the CAST Script function that will create the SQL Named Query object and make the links. This CAST Script will be created in <Custom CAST Script Library Path>\Custom folder:
Custom/DaoSQL.castscript
/* module declaration */ module Custom.DaoSQL; /* use declarations */ use Core.ConstantsMetamodel; use Core.JEE.JEE; use Core.Log; /* definition of the function createSQLNamedQuery that create * the object and links */ void createSQLNamedQuery(string class, string sqlRequest) { /* Creation of the named query symbol, analysis of the query and * creation of links to the database. */ symbol namedSQL = analyzeDBQuery(CAST_SQL_NamedQuery, class, sqlRequest); if (namedSQL == null) { log(DEBUG, "Error when creating the namedSQL: " + class); } /* eventually if this query is always called from the Java class * that has the same name as the SQL query name and the way it is * invoked doesn't permit to use parameterization, we can create * a link from the Java class to this SQL Named Query object */ symbol s_class = findUniqueSymbol(class, JV_CLASS ); if (s_class == null) { log(DEBUG, "Error can't find the JV_CLASS: " + class); } else { linkCreation = createLink(s_class, namedSQL, useLink); if (linkCreation == false) { log(DEBUG, "Error when creating link between the JV_CLASS: " + class + "and the Named Query: " + class); } } }
When it's done, check that your Application references the database schema (on which the requests in the XML are run) as a dependency target of your JEE Analysis Unit. Then you can run the JEE analyzer.
The log messages will appear only if you check the Run Analysis > Debug options > Activate CAST Script traces, this menu is launched when you run the analysis from Application > Execute > Run Analysis only or Analysis Unit > Execute > Run Analysis > Activate CAST Script traces on the current analysis unit - see JEE - Analysis configuration.
- If you want error or warning messages to appear instead of DEBUG mode, you should choose another log level: INFO, WARNING, ERROR or FATAL_ERROR in the CAST Script.
- If you want this CAST Script to abort on such errors, then you can use exit (string message) instead of Log.
Run the analysis
If you run this sample, you will obtain this view in CAST Enlighten:
Add parameterization rules
And finally, you may need (when there are Java methods that use the name of these SQL Queries as string parameter) to add parameterization rules. To do this, you can open the Dynamic Link Manager and check what is making a link to these SQL Named Queries and add rules when it makes sense.
Manage XML with XML Query Files
XMl Queries Files, containing instructions in XML format intended for the JEE Analyzer, can be edited using three main instructions:
<object-node> | Used to let the JEE analyzer create an object that will be stored in the Analysis Service. The name, type, scope etc. of the object can be specified using the element's attributes. This element can have any number of <object-node> child elements (provided they have different values for the @name attribute). Relationships with other objects are specified using a <link-node> child element. |
<link-node> | Used to request link creation from the object introduced by the <object-node> parent element (or the file if parent element is the root element) toward an object that will be searched for using the <link-node> attributes values. |
<config-file-node> | the purpose of this element is to notify the J2EE Analyzer about a reference to another configuration file within the file against which the current Queries File is run. You can then specify which information to retrieve from the referenced file. To do so, just use the <object-node> and <link-node> elements beneath the <config-file-element>. |
- Sub-elements are not supported for Tiles Definitions Files yet. This is because the processing of this type of file is done internally. As a result, the <config-file-node> element is used just to indicate the location and type of the file.
- For each referenced file, an object is created and stored in the Analysis Service. The specific type of the object is given by the @content-type attribute.
Example XML Query File
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- ======================================================================================================== --> <!-- ======================================= Cast-Congfig.xml ============================================= --> <!-- ======================================= version: 6.0 ============================================= --> <!-- ========================== This file applies to struts-config.xml file type ============ --> <!-- ========================== ============ --> <!-- ========================== As of version 6.0 of CAST products this file is deprecated. ============ --> <!-- ========================== Use cast-struts-config.xml instead. ============ --> <!-- ======================================================================================================== --> <xml-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation=".\schemas\cast-config.xsd"> <!-- Notes: For each object/link node, the xpath attribute specifies the node in the configuration file that contains the information needed to create the object/link. Once this node specified, the location of each peace of information to consider is given by an XPath query relatively to this node. The xpath attribute's value is an XPath query relative to the parent node of the node using this attribute. It is recommended that this path points to an element rather than an attribute. If an object-node's type attribute is missing or has an unrecognized value, a generic xml object will be created. For more information, see the CAST-config.xsd file or online help --> <!-- ========================================================================================================--> <!-- ========================================== OBJECTS AND LINKS TO CREATE =================================--> <!-- ========================================================================================================--> <!-- Global Forwards --> <object-node xpath="/struts-config/global-forwards/forward" name="./@name" type="forward"> <link-node xpath = "." called-object = "./@path" resolve-as = "url" /> <link-node xpath = "." called-object = "./@className" resolve-as = "java-type"/> <link-node xpath = "self::node()[contains(@path, '.do')]" called-object = "./@path" resolve-as = "url" > <query-param name = "method_name" xpath = "./@path" resolve-as = "java-method" resolution-scope-src = "/struts-config/action-mappings/action/@type" default = "perform" /> <!-- Note: resolution-scope-src attribute should be set like this: resolution-scope-src = "/struts-config/action-mappings/action[ @path = (begining of this forward's path)]/@type" Since the criteria << [ @path = (begining of this forward's path)] >> can not be specified with xpath 1.0 (No mean to reference the forward within the context of an action - in the []), this filter is applied internaly:only if query-param is used to resolve url parameters of a forward's path. Elsewhere, only the first result returned by the xpath request is considered. --> </link-node> </object-node> <object-node xpath="/struts-config/queries/query" name="./@name" type="xml-object"> <link-node xpath="." called-object="./sql" resolve-as="server-object" /> </object-node> <!-- action mappings --> <object-node xpath="/struts-config/action-mappings/action" name="./@path" default="./@unknown" type="action-mapping"> <object-attribute name = "class" select = "./@type" /> <object-attribute name = "Validate" select = "./@validate" /> <!-- getting links for action mappings --> <link-node xpath="." called-object="./@type" resolve-as="java-type" link-type="relyon" /> <link-node xpath="." called-object="./@include" resolve-as="java-type" /> <link-node xpath="." called-object="./@input" resolve-as="url" /> <link-node xpath="." called-object="./@name" resolve-as="form-bean" /> <link-node xpath="." called-object="./@forward" resolve-as="forward;url" /> <link-node xpath="self::node()[count(/struts-config/controller[@processorClass = 'org.apache.struts.tiles.TilesRequestProcessor']) > 0]" called-object="./@forward" resolve-as="bean" /> <!-- Forwards with transform child elements: stxx in struts-config-integrated mode --> <object-node xpath="./forward[transform]" name="./@name" type="forward"> <!-- stxx tranforms (struts 1.0 - STXX 1.0 ) STXX 1.0 Transforms are created from struts-config file. The path attribute value is resolved as an url (file) --> <object-node xpath="./transform" name="./@name" type="stxx-transform"> <link-node xpath="." called-object="./@path" resolve-as="path" /> </object-node> </object-node> <!-- Forwards with .dox in path attribute and without transform child element: stxx in plugin mode --> <object-node xpath="./forward[contains(@path, '.dox')][count(transform) = 0]" name="./@name" type="forward"> <!-- stxx tranforms (struts 1.1 - STXX 1.1, 1.2 ) STXX 1.1 and 1.2 Transforms (and pipelines for 1.2) are created from and external file in plugin mode.(see stxx-cfg-node element). The config below traces a link toward a transform (via a pipeline in 1.2) if the parent element (forward) does not have a transform sub element. --> <link-node xpath="." called-object="./@path" resolve-as="stxx-transform"/> </object-node> <!-- Other Forwards(other than forwards for stxx) --> <object-node xpath="./forward[@path][not(contains(@path, '.dox'))]" name="./@name" type="forward"> <link-node xpath="." called-object="./@path" resolve-as="resource"/> <link-node xpath="self::node()[contains(@path, '.do')]" called-object="./@path" resolve-as="url"> <query-param name="method_name" xpath="./@path" resolve-as="java-method" resolution-scope-src ="/struts-config/action-mappings/action/@type" default="perform"/> </link-node> <link-node xpath="." called-object="./@className" resolve-as="java-type"/> </object-node> <!-- --> <object-node xpath="./exception" name="./@key" type="xml-object"> <link-node xpath="." called-object="./@path" resolve-as="url"/> <link-node xpath="." called-object="./@type" resolve-as="java-type"/> </object-node> <object-node xpath="self::node()[@scope]" name="./@name" type="form-bean" scope-src="./@scope"> <link-node xpath="." called-object="/struts-config/form-beans/form-bean[@name='{0}']/@type" resolve-as="java-type"> <variable name="{0}" select = "./@name" /> </link-node> </object-node> </object-node> <!-- getting beans --> <object-node xpath="/struts-config/form-beans/form-bean" name="./@name" type="form-bean" scope="session" java-type="./@type"> <object-attribute name = "class" select = "./@type" /> <!-- bean properties --> <object-node xpath="./form-property" name="./@name" type="bean-property" java-type="./@type"/> </object-node> <!-- ========================================================================================================--> <!-- ========================================== CONFIGURATION FILES =========================================--> <!-- ========================================================================================================--> <!-- tiles files --> <config-file-node xpath="/struts-config/plug-in/set-property[@property='definitions-config']" content-type="tiles-definitions" location="./@value" /> <!-- stxx 1.1 transforms definition file (plugin version) --> <config-file-node xpath="/struts-config/plug-in/set-property[@property='transform-config']" content-type="stxx-transforms" location="./@value" version="1.1"> <object-node xpath="/transform-definitions/transform" name="./@name" type="stxx-transform"> <link-node xpath="." called-object="./xsl/file/@name" resolve-as="path"/> </object-node> </config-file-node> <!-- stxx 1.2 pipelines/transforms definition file --> <config-file-node xpath="/struts-config/plug-in/set-property[@property='pipeline-config']" content-type="stxx-transforms" location="./@value" version="1.2"> <object-node xpath="/pipeline-definitions/pipeline" name="./@match" type="stxx-pipeline"> <param name="transform-file-path" type="path" value="./transform/param[@name='path' ]/@value"/> <param name="transform-file-path" type="path" value="./transform/param[@name='page' ]/@value"/> <param name="transform-file-path" type="path" value="./transform/param[@name='xform']/@value"/> <!-- <param name="transform-file" type="path" value="./transform[@when='MSIE']/param[@name='page' ]/@value" /> --> </object-node> </config-file-node> <!-- Forms validation configuration file --> <config-file-node xpath="/struts-config/plug-in[@className='org.apache.struts.validator.ValidatorPlugIn']" content-type="form-validation" location="./set-property[@property = 'pathnames']/@value" version = "1.1"> <object-node xpath="/form-validation/formset" type="validation-forms-set" name="./@language" suffix-src="./@country"> <object-node xpath="./form" name="./@name" type="validation-form"> <link-node xpath="." called-object="./@name" resolve-as="form-bean;action-mapping" link-type="use" /> <!-- Validation Form Fields --> <object-node xpath="./field" name="./@property" type="validation-form-field"> <link-node xpath="." called-object="./@property" resolve-as="form-property" resolution-scope-src="../@name" link-type="use" /> </object-node> </object-node> </object-node> </config-file-node> <!-- ========================================================================================================--> <!-- ========================================== PLUGINS =========================================--> <!-- ========================================================================================================--> <link-node xpath="." called-object="./plug-in/@className" resolve-as="java-type" link-type="use"/> </xml-config>
For more details on the attributes, possible child elements and allowed values for each attribute of a given element, refer to the cast-config.xsd file (located in the sub-folder "CAST_INSTALL_DIR\configuration\J2EE\schemas" in the installation folder CAST). For attributes that accept multiple values (';' separated values) or compound values (i.e. 'resource'), it is recommended that you use them rather than duplicating the containing xml element of the attribute then changing its value. Finally, set this attribute if you want to gather information from another branch. The obtained value will be used by the variable %context% in the attribute xpath.
Example: xpath="./son[@name=%context%]/val" context="../name"
cast-config.xml (Legacy)
The default cast-config.xml Query File supports struts configuration files. Once this file has been processed, the following objects are created:
- Forwards (either global forwards or forwards within actions)
- Action Mapping (for each /struts-config/action-mappings/action element)
- JSP Bean (for each /struts-config/form-beans/form-bean element)
- XML Object (for each /struts-config/queries/query , /struts/struts-config/action-mappings/action/exception elements)
For details on how relationships with other objects are created, see the <link-node> child elements of the <object-node> actions that create the objects listed above in the cast-config.xml file.
Sometimes, Forwards @path attributes values (i.e. those containing a URL with the path part ending in .do) may contain, in their query part, information we may be interested in. This is the case when the query part contains a method name as a parameter as in the following code:
<global-forwards> <forward name="logoff" path="/logoff.do?method_name=execute"/> <forward name="logon" path="/logon.jsp"/> <forward name="success" path="/mainMenu.jsp"/> </global-forwards>
In this case, we would like to have a link toward the java method execute. To allow that, the <query-param> element is provided by the JEE Analyzer. To get the link with the example above, the Queries File needs to contain the following instructions:
<object-node xpath="./forward[@path]" name="./@name" type="forward"> <link-node xpath=".[contains(@path, '.do')]" called-object="./@path" resolve-as="url"> <query-param xpath="./@path" name="method_name" resolve-as="java-method" resolution-scope-src ="/struts-config/action-mappings/action/@type" default="perform"/> </link-node> </object-node>
This tells the JEE Analyzer to resolve the value of the method_name query parameter, if any, as a java method. If query has no method_name parameter, then use perform as the default value. resolution-scope-src specifies the scope within which the method is to search for. In this example, the /struts-config/action-mappings/action/@type attribute should contain a fully qualified name of a java type.
resolution-scope-src = "/struts-config/action-mappings/action[ @path = (begining of this forward's path)]/@type"
Since the criteria [@path = (begining of this forward's path)] can not be specified with xpath 1.0 (no meanq to reference the forward within the context of an action - in the []), this filter is applied internally: only if <query-param> is used to resolve url parameters of a Forward's path. Elsewhere, only the first result returned by the xpath request is considered.
Customize an XML queries file
First ask CAST if they already have experience of this framework and have the XML queries file available.
For now, the only possibility for validating an XML queries file is to start an analysis and check through CAST Enlighten whether the objects are created with the correct links. Because running the analysis on the entire application can take a great deal of time, it is better to create a specific job that references only the specific XML files that require analyzing and related dependencies (often JAVA files that contain the classes referenced in the XML and/or other XML files that are referenced).
Making syntax errors in the XML is easy and will result in objects or links that don't appear in CAST Enlighten. This is why you must use a tool that is able to validate XML through a DTD or an XSD. You can find free tools to do this such as XMLSpy (http://www.altova.com/products/xmlspy/xml_editor.html). Another advantage of this tool is that it will give you all the possible values that you can use for an XML tag property when it is an enumeration.
When these conditions are met, you can start to create your XML query file. The best way to do this is to look at the cast-struts-config.xml file and the reference guide, but in the next sub-chapter some more frequent situations are described.
A CAST XML queries file has this structure:
<xml-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation=".\cast-config.xsd"> <!-- Add your queries here --> </xml-config>
The reference to the XSD is important because it will verify your XML queries file syntax with the tool.
To illustrate this, let's use a Hibernate configuration.
How to create an object?
Here, we will create a Hibernate bean named: de.sbs.eentry.awf.model.impl.ApprovalCategoryImpl.
To create an object in the KB, we will use the XML tag object-node:
<object-node xpath="./hibernate-mapping/class" name="./@name" type="xml-object">
- xpath property is used to select the node in the XML file to analyze. Here we specified './hibernate-mapping/class' because we will have to cross this hierarchy to reach the object 'class'.
- name property is used to set the name of the object to create. And to do that, we specify that it comes from the attribute name of the XML file to analyze through ./@name. './'. The @name indicates that the property is located in the node specified by xpath.
- type property specifies which kind of object we want to create in the KB.
NOTE: XMLSpy will give you all the possibilities that you can use for the property "type"
How to create a link?
Here, we will create a link between the hibernate bean named de.sbs.eentry.awf.model.impl.ApprovalCategoryImpl the class de.sbs.eentry.awf.model.impl.ApprovalCategoryImpl and the table AWF_APPROVAL_CATEGORY.
To create a link in the KB, we will use the XML tag link-node and to set the source of the link to the Hibernate bean, we will define this tag in the XML node defined in the previous chapter: object-node:
<object-node .> <link-node xpath = "." called-object = "./@table" resolve-as="server-object" link-type="lock"/> <link-node xpath = "." called-object = "./@name" resolve-as="javatype" link-type="prototype"/> </object-node>
- xpath property defines the XML hierarchy path relative to the parent node (object-node). As we want to retrieve the information from the ./hibernate-mapping/class path and this object-node is already positioned in this node, there is no reason to move: so we set it to "."
- called-object property is used to get the name of the object that we want to link with. For the Server Object, we want to get the name from the table property and for the Java Class, we want to get the name from the name property.
- resolve-as property is used to define the type of object to find: one will be a server-object and the other one will be a javatype. This avoids the need to create links with any type of object that has the same name.
- link-type property defines the type of link we want to create: lock for the table and prototype for the class.
How is it possible to take into account an XML file referenced by the XML that is currently being analyzed?
Here we will analyze the file fr/bdpme/gdc/beans/hibernate/referentiel/EnseigneBean.hbm.xml during the analysis of this file. To do that, we will use the XML tag config-file-node. This tag will indicate to CAST that the file must be opened and analyzed with all instructions (object-node, link-node) defined under this node.
<config-file-node xpath="./hibernate-configuration/session-factory/mapping" location="./@resource" > <object-node xpath="./hibernate-mapping/class" name="./@name" type="xml-object"> <link-node xpath = "." called-object = "./@table" resolve-as="server-object" link-type="lock"/> <link-node xpath = "." called-object = "./@name" resolve-as="javatype" link-type="prototype"/> </object-node> </config-file-node>
- xpath property defines the XML hierarchy path relative to the parent node.
- location property defines the XML file path to parse. The path is relative to the Web Server Root Path when beginning with a '/' or relative to this file in other cases. As before, to get this path, the value of this property is set with the property name of the tag in the analyzed XML file that contains the path (resource here).
- All new queries written under this tag will be applied to the retrieved XML file.