Page tree
Skip to end of metadata
Go to start of metadata
Summary: this page explains how to manage XML files in a J2EE analysis.

Introduction

XML files can be managed using two methods:

  • New method: you extract with an executable of your choice (XQuery is the default choice) the XML information required to create objects, links and add object properties to generate a script in CAST Script Language to specify which object, links and properties must be managed by the J2EE analyzer.
    1. - the Java / JSP Analyzer analyzes the .java file and keeps information about Java annotations in memory. These annotations can be queried from CAST Script native function (this is new in 6.4).
    2. - the XQuery file (where the XQuery processor is used) is applied on XML files to extract information needed to create objects, links and add properties and output a castscript file that will call a custom CAST Script function that will ask the CAST Script interpreter to create objects, links and add properties.
    3. &
    4. - The CAST Script Interpreter will interpret the generated CAST Script and all custom functions and CAST Script 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 needed.
    5. - When complete, the objects, links and added properties are saved in the KB.
  • Old method: you use XML CAST Queries files to specify how to extract information and what to create and modify.

Because the new method will be extended to all our support in future versions and the old method abandoned, we recommend you start to use the new method that is also easier to use and add has scope for adding more customization possibilities (links to any technologies supported by CAST, XML namespace support...).

Associate XML to an XML Query file

The J2EE Analyzer uses Environment Profiles to define that a specific XML file is handled through a specific XML Query file (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.

Note:

  • 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 parsing mode allows you to choose how you will extract the XML information and process them:

  • XQuery: this is a new method introduced in release 6.3. You extract information and generate a script in CAST Script Language through a XQuery processing.
  • Custom: this is a new method introduced in release 6.3. You extract information and generate a script in CAST Script Language through an executable of your choice such as a XSLT processor.
  • CAST XML Query: this is the old method where the XML Query file contains specific tags to order the J2EE analyzer to create objects, links and add properties that are extracted through XPath instructions.
  • Ignore: to ignore specific XML files that are meaningless by checking the Ignore checkbox to prevent the J2EE 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 CAST Script

The method for validating 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 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 XQuery is easy and will result in errors in the CAST Analysis Manager =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 (http://www.xqdt.org/eclipse/) that you must 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 do this is to look at the EJB3_ejb-jar_GenCASTScript.xq file (in <CAST Common folder>\EnvProf\J2EE\EJB3) and EJB3.castscript (in CAST_INSTALL_DIR\configuration\Script_Libraries\Core\EJB) the reference guide, but in the next sub-chapter some more frequent situations are described.

How to manage an XML?

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 concern of extraction in the XQuery file and the logic of creation and modification in the CAST Script function.

Extracting information with XQuery

Let's look at an EJB3 sample and specifically to Message Driven Beans.

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)
  1. 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.
  2. 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.
  3. Before generating a script instruction that will call a function, we must first declare the CAST Script module that we will use.
  4. 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
  5. 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 J2EE analyzer. All the information required to create the EJB Message Driven Bean has been passed to the CAST Script function createEJBMDB.

Now we have made the XQuery to generate a call to this CAST Script function let's look at how to implement such function in the next chapter.

Note that to test your XQuery file before using the analyzer, you can type the following command to see the generated file:
$CASTDIR\ThirdParty\Zorba\bin>zorba.exe -f -q <XQuery file> --context-item <XML File>

Building a CAST Script function

With 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. Refer to the J2EE Reference Manual to know which type of information you need to create for a specific object. Note that these properties and links can be used by quality rules to perform some checks, so it is recommended to set all of them.

When you define a custom CAST Script file, you must first set the path to your Custom CAST Script Library Root Path through the Technology > J2EE > Platform Setting menu:

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 and documented in the J2EE Reference Manual. 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);
}
  1. 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.
  2. Then you have to import any modules required to build your function.
  3. Declare your function with the type returned, its name and its parameters.
  4. 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.
  5. 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.
  6. 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 rules that will be added in next versions.
If you are using an ORM framework such as Hibernate or an implementation of JPA, then you have to use 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 3.2 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 CAST Script and XQuery file. Even if there are other parsing methods to manage XML & 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:

  1. 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.
  2. Write the CAST Script function that will create the Cast_SQL_NamedQuery object
  3. 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),""");")

NOTE

  • 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: http://www.w3schools.com/Xpath/xpath_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 type the following command to see the generated file:
$CASTDIR\ThirdParty\Zorba\bin>zorba.exe -f -q <XQuery file> --context-item <XML File>

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 reference the database schema (on which the requests in the XML are run) as a dependency target of your J2EE Analysis Unit. Then you can run the J2EE analyzer.

NOTE 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.

  • 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 just have to eventually (when there are Java methods that use the name of these SQL Queries as string parameter) add the parameterization rules. To do this, you can open the Dynamic Link Manager and check who is making a link to these SQL Named Query and add rules when it make sense (refer to Review Dynamic Links).

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.

TODO: Don't forget to send this XML queries file to the PMT, it can help other consultants and increase our knowledge.

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.