1. Introduction

1.1. About the Rules Development Guide

This guide is for engineers, consultants, and others who want to create custom XML-based rules for Azure Migrate application and code assessment for Java (APPCAT) tools.

For more information, see the Introduction to the Azure Migrate application and code assessment for Java for an overview and the CLI Guide for details.

1.1.1. Use of <APPCAT_HOME> in this guide

This guide uses the <APPCAT_HOME> replaceable variable to denote the path to your APPCAT installation. The installation directory is the azure-migrate-appcat-for-java-cli-6.3.0 directory where you extracted the APPCAT .zip file.

Note

If you are installing on a Windows operating system:

  1. Extract the .zip file to a folder named appcat to avoid a Path too long error. Alternatively, extract the file with 7-Zip to a folder of any name you choose.

  2. If a Confirm file replace window is displayed during extraction, click Yes to all.

When you encounter <APPCAT_HOME> in this guide, replace it with the actual path to your APPCAT installation.

1.2. About APPCAT rules

The Azure Migrate application and code assessment for Java (APPCAT) contains rule-based migration tools that analyze the APIs, technologies, and architectures used by the applications you plan to migrate. In fact, the APPCAT analysis process is implemented using APPCAT rules. APPCAT uses rules internally to extract files from archives, decompile files, scan and classify file types, analyze XML and other file content, analyze the application code, and build the reports.

APPCAT builds a data model based on the rule execution results and stores component data and relationships in a graph database, which can then be queried and updated as needed by the migration rules and for reporting purposes.

APPCAT rules use the following rule pattern:

when(condition)
  perform(action)
otherwise(action)

APPCAT provides a comprehensive set of standard migration rules out-of-the-box. Because applications may contain custom libraries or components, APPCAT allows you to write your own rules to identify use of components or software that may not be covered by the existing ruleset.

If you plan to write your own custom rules, see the Rules Development Guide for detailed instructions.

2. Getting started with rules

You can get started creating custom APPCAT rules by creating a rule or by reviewing the quickstarts.

2.1. Creating your first XML rule

This section guides you through the process of creating and testing your first APPCAT XML-based rule. This assumes that you have already installed APPCAT. See Installing and running the CLI in the CLI Guide for installation instructions.

In this example, you will write a rule to discover instances where an application defines a jboss-web.xml file containing a <class-loading> element and provide a link to the documentation that describes how to migrate the code.

Creating the directory structure for the rule

Create a directory structure to contain your first rule and the data file to use for testing.

$ mkdir -p /home/<USER_NAME>/migration-rules/rules
$ mkdir -p /home/<USER_NAME>/migration-rules/data

This directory structure will also be used to hold the generated APPCAT reports.

Creating data to test the rule

  1. Create a jboss-web.xml file in the /home/<USER_NAME>/migration-rules/data/ subdirectory.

  2. Copy in the following content.

    <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 4.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_2.dtd">
    <jboss-web>
        <class-loading java2ClassLoadingCompliance="false">
            <loader-repository>
                seam.jboss.org:loader=@projectName@
                <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
            </loader-repository>
        </class-loading>
    </jboss-web>

    Creating the rule

APPCAT XML-based rules use the following rule pattern:

when(condition)
  perform(action)
otherwise(action)
Procedure
  1. In the /home/<USER_NAME>/migration-rules/rules/ directory, create a file named JBoss5-web-class-loading.windup.xml that contains the following content:

    <?xml version="1.0"?>
    <ruleset id="<UNIQUE_RULESET_ID>"
      xmlns="http://windup.jboss.org/schema/jboss-ruleset"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
      <metadata>
          <description>
              <!-- Ruleset Description -->
          </description>
          <dependencies>
              <!-- Ruleset Dependencies -->
          </dependencies>
          <sourceTechnology id="<SOURCE_ID>" versionRange="<SOURCE_VERSION_RANGE>"/>
          <targetTechnology id="<TARGET_ID>" versionRange="<TARGET_VERSION_RANGE>"/>
          <tag>Reviewed-2015-05-01</tag>
      </metadata>
      <rules>
          <rule id="<UNIQUE_RULE_ID>">
            <when>
                <!-- Test for a condition here -->
            </when>
            <perform>
                <!-- Perform an action -->
            </perform>
          </rule>
       </rules>
    </ruleset>
    Note

    The XML file name must include the .windup.xml extension. Otherwise, APPCAT does not evaluate the new rule.

  2. Add a unique identifier for the ruleset and rule:

    • Replace <UNIQUE_RULESET_ID> with an appropriate ruleset ID, for example, JBoss5-web-class-loading.

    • Replace <UNIQUE_RULE_ID> with an appropriate rule ID, for example, JBoss5-web-class-loading_001.

  3. Add the following ruleset add-on dependencies:

    <dependencies>
      <addon id="org.jboss.windup.rules,windup-rules-javaee,3.0.0.Final"/>
      <addon id="org.jboss.windup.rules,windup-rules-java,3.0.0.Final"/>
    </dependencies>
  4. Add the source and target technologies:

    • Replace <SOURCE_ID> with eap.

    • Replace <TARGET_ID> with eap.

  5. Set the source and target technology versions.

    • Replace <SOURCE_VERSION_RANGE> with (4,5).

    • Replace <TARGET_VERSION_RANGE> with (6,).

    See the Apache Maven version range specification for more information.

  6. Complete the when condition. Because this rule tests for a match in an XML file, xmlfile is used to evaluate the files.

    To match on the class-loading element that is a child of jboss-web, use the xpath expression jboss-web/class-loading.

    <when>
        <xmlfile matches="jboss-web/class-loading" />
    </when>
  7. Complete the perform action for this rule.

    • Add a classification with a descriptive title and a level of effort of 1.

    • Provide a hint with an informative message and a link to documentation that describes the migration details.

      <perform>
          <iteration>
              <classification title="JBoss Web Application Descriptor" effort="1"/>
              <hint title="JBoss Web XML class-loading element is no longer valid">
                <message>
                  The class-loading element is no longer valid in the jboss-web.xml file.
                </message>
                <link href="https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html-single/Migration_Guide/index.html#Create_or_Modify_Files_That_Control_Class_Loading_in_JBoss_Enterprise_Application_Platform_6" title="Create or Modify Files That Control Class Loading in JBoss EAP 6"/>
              </hint>
          </iteration>
      </perform>

The rule is now complete and should look like the following example.

<?xml version="1.0"?>
<ruleset id="JBoss5-web-class-loading"
    xmlns="http://windup.jboss.org/schema/jboss-ruleset"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
    <metadata>
        <description>
            This ruleset looks for the class-loading element in a jboss-web.xml file, which is no longer valid in JBoss EAP 6
        </description>
         <dependencies>
            <addon id="org.jboss.windup.rules,windup-rules-javaee,3.0.0.Final"/>
            <addon id="org.jboss.windup.rules,windup-rules-java,3.0.0.Final"/>
        </dependencies>
        <sourceTechnology id="eap" versionRange="(4,5)"/>
        <targetTechnology id="eap" versionRange="[6,)"/>
    </metadata>
    <rules>
        <rule id="JBoss5-web-class-loading_001">
            <when>
                <xmlfile matches="jboss-web/class-loading" />
            </when>
            <perform>
                <iteration>
                    <classification title="JBoss Web Application Descriptor" effort="1"/>
                    <hint title="JBoss Web XML class-loading element is no longer valid">
                      <message>
                        The class-loading element is no longer valid in the jboss-web.xml file.
                      </message>
                      <link href="https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html-single/Migration_Guide/index.html#Create_or_Modify_Files_That_Control_Class_Loading_in_JBoss_Enterprise_Application_Platform_6" title="Create or modify files that control class loading in JBoss EAP 6"/>
                    </hint>
                </iteration>
            </perform>
        </rule>
     </rules>
</ruleset>

Installing the rule

An APPCAT rule is installed by placing the rule into the appropriate directory.

Copy the JBoss5-web-class-loading.windup.xml file to the <APPCAT_HOME>/rules/ directory.

$ cp /home/<USER_NAME>/migration-rules/rules/JBoss5-web-class-loading.windup.xml <APPCAT_HOME>/rules/

Testing the rule

Open a terminal and run the following command, passing the test file as an input argument and a directory for the output report.

$ <APPCAT_HOME>/bin/appcat --sourceMode --input /home/<USER_NAME>/migration-rules/data --output /home/<USER_NAME>/migration-rules/reports --target eap:6

You should see the following result.

Report created: /home/<USER_NAME>/migration-rules/reports/index.html
              Access it at this URL: file:///home/<USER_NAME>/migration-rules/reports/index.html

Reviewing the reports

Review the report to be sure that it provides the expected results. For a more detailed walkthrough of APPCAT reports, see the Reviewing the reports section of the APPCAT CLI Guide.

  1. Open /home/<USER_NAME>/migration-rules/reports/index.html in a web browser.

  2. Verify that the rule ran successfully.

    1. From the main landing page, click the Rule providers execution overview link to open the Rule Providers Execution Overview.

    2. Find the JBoss5-web-class-loading_001 rule and verify that its Status? is Condition met and its Result? is success.

      Test rule execution
      Figure 1. Test rule execution
  3. Verify that the rule matches the test data:

    1. From the main landing page, click the name of the application or input folder, which is data in this example.

    2. Click the Application Details report link.

    3. Click the jboss-web.xml link to view the Source Report.

      You can see that the <class-loading> line is highlighted, and the hint from the custom rule is shown inline.

      Rule match
      Figure 2. Rule match

      The top of the file lists the classifications for matching rules. You can use the link icon to view the details for that rule. Notice that in this example, the jboss-web.xml file matched on another rule (JBoss web application descriptor (jboss-web.xml)) that produced 1 story point. This story point, combined with the 1 story point from our custom rule, brings the total story points for this file to 2.

2.2. Reviewing the Azure Migrate application and code assessment for Java quickstarts

The Azure Migrate application and code assessment for Java quickstarts provide working examples of how to create custom Java-based rule add-ons and XML rules. You can use them as a starting point for creating your own custom rules.

Each quickstart has a README.adoc file that contains instructions for that quickstart.

You can download a .zip file of the latest version of the quickstarts. If you prefer to work with the source code, you can fork and clone the windup-quickstarts project repository.

Downloading the latest quickstart

You can download the latest release of a quickstart.

Procedure
  1. Launch a browser and navigate to https://github.com/windup/windup-quickstarts/releases.

  2. Click the latest release to download the .zip file to your local file system.

  3. Extract the archive files to a local directory.

    You can review the quickstart README.adoc file.

Forking and cloning the quickstart GitHub project

You can fork and clone the Quickstart Github project on your local machine.

Prerequisites
  • You must have git client installed.

Procedure
  1. Click Fork on the Azure Migrate application and code assessment for Java quickstart GitHub page to create the project in your own Git. The forked GitHub repository URL should look like this: https://github.com/<YOUR_USER_NAME>/windup-quickstarts.git.

  2. Clone the Azure Migrate application and code assessment for Java quickstart repository to your local file system:

    $ git clone https://github.com/<YOUR_USER_NAME>/windup-quickstarts.git

    This creates a windup-quickstarts directory on your local file system.

  3. Navigate to the newly created directory:

    $ cd windup-quickstarts/
  4. To retrieve the latest code updates, add the remote upstream repository so that you can fetch changes to the original forked repository:

    $ git remote add upstream https://github.com/windup/windup-quickstarts.git
  5. Download the latest files from the upstream repository:

    $ git fetch upstream

3. Creating XML rules

3.1. XML rule structure

This section describes the basic structure of XML rules. All XML rules are defined as elements within rulesets. For more details, see the APPCAT XML rule schema.

3.1.1. Rulesets

A ruleset is a group of one or more rules that targets a specific area of migration. This is the basic structure of the <ruleset> element.

  • <ruleset id="<UNIQUE_RULESET_ID>">: Defines this as an APPCAT ruleset and gives it a unique ruleset ID.

    • <metadata>: The metadata about the ruleset.

      • <description>: The description of the ruleset.

      • <dependencies/>: The rule add-ons required by this ruleset.

      • <sourceTechnology/>: The source technology.

      • <targetTechnology/>: The target technology.

      • <overrideRules/>: Setting to true indicates that rules in this ruleset override rules with the same ID from the core ruleset distributed with APPCAT. Both the ruleset id and the rule id must match a rule within the core ruleset or the rule will be ignored. This is false by default.

    • <rules>: A set of individual rules.

      • <rule id="<UNIQUE_RULE_ID>">: Defines the rule and gives it a unique ID. It is recommended to include the ruleset ID as part of the rule ID, for example, <UNIQUE_RULESET_ID_UNIQUE_RULE_ID>. One or more rules can be defined for a ruleset.

        • <when>: The conditions to match on.

        • <perform>: The action to be performed when the rule condition is matched.

        • <otherwise>: The action to be performed when the rule condition is not matched. This element takes the same child elements as the <perform> element.

        • <where>: A string pattern defined as a parameter, which can be used elsewhere in the rule definition.

      • <file-mapping/>: Maps an extension to a graph type.

      • <package-mapping/>: Maps from a package pattern (regular expression) to an organization name.

3.1.2. Predefined rules

APPCAT provides predefined rules for common migration requirements. These core APPCAT rules are located in the APPCAT installation at <APPCAT_HOME>/rules/migration-core/.

The following is an example of a core APPCAT rule that matches on a proprietary utility class.

<?xml version="1.0"?>
<ruleset xmlns="http://windup.jboss.org/schema/jboss-ruleset" id="weblogic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">

    <metadata>
        <description>
            This ruleset provides analysis of WebLogic proprietary classes and constructs that may require individual attention when migrating to JBoss EAP 6+.
        </description>
        <dependencies>
            <addon id="org.jboss.windup.rules,windup-rules-javaee,2.0.1.Final" />
            <addon id="org.jboss.windup.rules,windup-rules-java,2.0.0.Final" />
        </dependencies>
        <sourceTechnology id="weblogic" />
        <targetTechnology id="eap" versionRange="[6,)" />
        <tag>reviewed-2015-06-02</tag>
        <tag>weblogic</tag>
    </metadata>
    <rules>
        ...
        <rule id="weblogic-02000">
            <when>
                <javaclass references="weblogic.utils.StringUtils.{*}" />
            </when>
            <perform>
                <hint title="WebLogic StringUtils usage" effort="1" category-id="mandatory">
                    <message>Replace with the `StringUtils` class from Apache Commons.</message>
                    <link href="https://commons.apache.org/proper/commons-lang/" title="Apache Commons Lang" />
                    <tag>weblogic</tag>
                </hint>
            </perform>
        </rule>
        ...
    </rules>
</ruleset>

3.2. Creating a basic XML rule

This section describes how to create an APPCAT XML rule. This assumes that you already have APPCAT installed. See the APPCAT CLI Guide for installation instructions.

3.2.1. Creating a basic XML rule template

APPCAT XML rules consist of conditions and actions and use the following rule pattern:

when(condition)
  perform(action)
otherwise(action)

Create a file with the following contents, which is the basic syntax for XML rules.

Important

The XML file name must include the .windup.xml extension. Otherwise, APPCAT does not evaluate the new rule.

<?xml version="1.0"?>
<ruleset id="unique-ruleset-id"
  xmlns="http://windup.jboss.org/schema/jboss-ruleset"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <metadata>
    <!-- Metadata about the rule including a description,
         source technology, target technology, and any
         add-on dependencies -->
  </metadata>
<rules>
    <rule id="unique-ruleset-id-01000">
        <when>
            <!-- Test a condition... -->
        </when>
        <perform>
            <!-- Perform this action when condition is satisfied -->
        </perform>
        <otherwise>
            <!-- Perform this action when condition is not satisfied -->
        </otherwise>
    </rule>
  <rules>
</ruleset>

3.2.2. Creating the ruleset metadata

The XML ruleset metadata element provides additional information about the ruleset such as a description, the source and target technologies, and add-on dependencies. The metadata also allows for specification of tags, which allow you to provide additional information about a ruleset.

<metadata> example
<ruleset id="unique-ruleset-id"
  xmlns="http://windup.jboss.org/schema/jboss-ruleset"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <metadata>
    <description>
            This is the description.
    </description>
    <dependencies>
            <addon id="org.jboss.windup.rules,windup-rules-javaee,2.0.1.Final"/>
            <addon id="org.jboss.windup.rules,windup-rules-java,2.0.0.Final"/>
    </dependencies>
    <sourceTechnology id="weblogic" versionRange="(10,12]"/>
    <sourceTechnology id="ejb" versionRange="(2,3]"/>
    <targetTechnology id="eap" versionRange="(5,6]"/>
    <targetTechnology id="ejb" versionRange="(2,3]"/>
    <tag>require-stateless</tag>
    <tag>require-nofilesystem-io</tag>
    <executeAfter>AfterRulesetId</executeAfter>
    <executeBefore>BeforeRulesetId</executeBefore>
  </metadata>
  <rules>
    ...
  </rules>
</ruleset>

3.2.3. Creating a rule

Individual rules are contained within the <rules> element. They comprise one or more when conditions and perform actions.

See the XML rule schema for valid rule syntax.

Creating a <when> condition

The XML rule <when> element tests for a condition. The following is a list of valid <when> conditions.

Element Description

<and>

The standard logical and operator.

<filecontent>

Find strings or text within files, for example, properties files.

<file-mapping>

Define file names to internal stored File model.

<javaclass>

Test for a match in a Java class.

<javaclass-ignore>

Exclude javaclass which you would like to ignore in processing discovery.

<not>

The standard logical not operator.

<or>

The standard logical or operator.

<package-mapping>

Define package names to organization or libraries.

<project>

Test for project characteristics, such as dependencies.

<true>

Always match.

<xmlfile>

Test for a match in an XML file.

The specific syntax is dependent on whether you are creating a rule to evaluate Java class, an XML file, a project, or file content.

Creating a <perform> action

The XML rule <perform> element performs the action when the condition is met. Operations allowed in this section of the rule include the classification of application resources, in-line hints for migration steps, links to migration information, and project line item reporting. The following is a list of valid <perform> actions.

Element Description

<classification>

This operation adds metadata that you want to apply to the entire file. For example, if the Java Class is a JMS Message Listener, you can add a Classification with the title "JMS Message Listener" that includes information that applies to the entire file. You can also set an effort level for the entire file.

<hint>

This operation adds metadata to a line within the file. This provides a hint or inline information about how to migrate a section of code.

<iteration>

This specifies to iterate over an implicit or explicit variable defined within the rule.

<lineitem>

This provides a high-level message that is displayed in the application overview page.

<link>

This provides an HTML link to additional information or documentation about the migration task.

<xslt>

This specifies how to transform an XML file.

3.3. XML rule syntax

3.3.1. <when> syntax

Conditions allowed in the when portion of a rule must extend GraphOperation and currently include evaluation of Java classes, XML files, projects, and file content. Because XML rules are modeled after the Java-based rule add-ons, links to JavaDocs for the related Java classes are provided for a better understanding of how they behave.

The complete XML rule schema is located here: http://windup.jboss.org/schema/windup-jboss-ruleset.xsd.

The following sections describe the more common XML when rule conditions.

  • <javaclass> condition syntax

  • <xmlfile> condition syntax

  • <project> condition syntax

  • <filecontent> condition syntax

  • <file> condition syntax

  • <has-hint> condition syntax

  • <has-classification> condition syntax

  • <graph-query> condition syntax

  • <dependency> condition syntax

By default, if more than one when rule condition is provided, then all conditions must be met for the rule to match.

<javaclass> syntax
Summary

Use the <javaclass> element to find imports, methods, variable declarations, annotations, class implementations, and other items related to Java classes. For a better understanding of the <javaclass> condition, see the JavaDoc for the JavaClass class.

The following is an example of a rule that tests for WebLogic-specific Apache XML packages:

<rule id="weblogic-03000">
    <when>
        <javaclass references="weblogic.apache.xml.{*}" />
    </when>
    <perform>
        <hint title="WebLogic Specific Apache XML Package" effort="1" category-id="mandatory">
            <message>
                Code using this package should be replaced with code using the org.apache.xml package from [Apache
                Xerces](http://xerces.apache.org/).
            </message>
        </hint>
    </perform>
</rule>
Construct a <javaclass> element
<javaclass> element attributes
Attribute name Type Description

references

CLASS_NAME

The package or class name to match on. Wildcard characters can be used. This attribute is required.

Note
For performance reasons, you should not start the reference with wildcard characters. For example, use weblogic.apache.xml.{*} instead of {web}.apache.xml.{*}.
references="weblogic.apache.xml.{*}"

matchesSource

STRING

An exact regex to match. This is useful to distinguish hard-coded strings. This attribute is required.

matchesSource="log4j.logger"

as

VARIABLE_NAME

A variable name assigned to the rule so that it can be used as a reference in later processing. See the from attribute below.

as="MyEjbRule"

from

VARIABLE_NAME

Begin the search query with the filtered result from a previous search identified by its as VARIABLE_NAME.

from="MyEjbRule"

in

PATH_FILTER

Filter input files matching this regex (regular expression) naming pattern. Wildcard characters can be used.

in="{*}File1"
<javaclass> child elements
Child Element Description

<location>

The location where the reference was found in a Java class. Location can refer to annotations, field and variable declarations, imports, and methods. For the complete list of valid values, see the JavaDoc for TypeReferenceLocation.

<location>IMPORT</location>

<annotation-literal>

Match on literal values inside of annotations.

The following example matches on @MyAnnotation(myvalue="test").

<javaclass references="org.package.MyAnnotation">
    <location>ANNOTATION</location>
    <annotation-literal name="myvalue" pattern="test"/>
</javaclass>

Note that in this case, the <javaclass> refers to an annotation (@MyAnnotation), so the top-level annotation filter, <annotation-literal> must specify the name attribute. If the <javaclass> referred to a class that is annotated, then the top-level annotation filter used would be <annotation-type>.

<annotation-type>

Match on a particular annotation type. You can supply subconditions to be matched against the annotation elements.

The below example would match on a Calendar field declaration annotated with @MyAnnotation(myvalue="test").

<javaclass references="java.util.Calendar">
    <location>FIELD_DECLARATION</location>
    <annotation-type pattern="org.package.MyAnnotation">
        <annotation-literal name="myvalue" pattern="test"/>
    </annotation-type>
</javaclass>

<annotation-list>

Match on an item in an array within an annotation. If an array index is not specified, the condition will be matched if it applies to any item in the array. You can supply subconditions to be matched against this element.

The below example would match on @MyAnnotation(mylist={"one","two"}).

<javaclass references="org.package.MyAnnotation" >
    <location>ANNOTATION</location>
    <annotation-list name="mylist">
        <annotation-literal pattern="two"/>
    </annotation-list>
</javaclass>

Note that in this case, the <javaclass> refers to an annotation (@MyAnnotation), so the top-level annotation filter, <annotation-list> must specify the name attribute. If the <javaclass> referred to a class that is annotated, then the top-level annotation filter used would be <annotation-type>.

<xmlfile> syntax
Summary

Use the <xmlfile> element to find information in XML files. For a better understanding of the <xmlfile> condition, see the JavaDoc for the XmlFile class.

The following is an example of a rule that tests for an XML file:

<rule id="<UNIQUE_RULE_ID>">
    <when>
        <xmlfile matches="/w:web-app/w:resource-ref/w:res-auth[text() = 'Container']">
            <namespace prefix="w" uri="http://java.sun.com/xml/ns/javaee"/>
        </xmlfile>
    </when>
    <perform>
        <hint title="Title for Hint from XML">
            <message>Container Auth</message>
        </hint>
        <xslt description="Example XSLT Conversion" extension="-converted-example.xml"
              template="/exampleconversion.xsl"/>
    </perform>
</rule>
Construct an <xmlfile> element
<xmlfile> element attributes
Attribute name Type Description

matches

XPATH

Match on an XML file condition.

matches="/w:web-app/w:resource-ref/w:res-auth[text() = 'Container']"

xpathResultMatch

XPATH_RESULT_STRING

Return results that match the given regex.

<xmlfile matches="//foo/text()"
  xpathResultMatch="Text from foo."/>

as

VARIABLE_NAME

A variable name assigned to the rule so that it can be used as a reference in later processing. See the from attribute below.

as="MyEjbRule"

in

PATH_FILTER

Used to filter input files matching this regex (regular expression) naming pattern. Wildcard characters can be used.

in="{*}File1"

from

VARIABLE_NAME

Begin the search query with the filtered result from a previous search identified by its as VARIABLE_NAME.

from="MyEjbRule"

public-id

PUBLIC_ID

The DTD public-id regex.

public-id="public"
<xmlfile> matches custom functions

The matches attribute may use several built-in custom XPath functions, which may have useful side effects, like setting the matched value on the rule variables stack.

Function Description

windup:matches()

Match a XPath expression against a string, possibly containing APPCAT parameterization placeholders.

matches="windup:matches(//foo/@class, '{javaclassname}')"

This will match all <foo/> elements with a class attribute and store their value into javaclassname parameter for each iteration.

<xmlfile> child elements
Child element Description

<namespace>

The namespace referenced in XML files. This element contains two optional attributes: The prefix and the uri.

<namespace prefix="abc" uri="http://maven.apache.org/POM/4.0.0"/>
<project> syntax
Summary

Use the <project> element to query the Maven POM file for the project characteristics. For a better understanding of the <project> condition, see the JavaDoc for the Project class.

The following is an example of a rule that checks for a JUnit dependency version between 2.0.0.Final and 2.2.0.Final.

<rule id="UNIQUE_RULE_ID">
    <when>
        <project>
            <artifact groupId="junit" artifactId="junit" fromVersion="2.0.0.Final" toVersion="2.2.0.Final"/>
        </project>
    </when>
    <perform>
        <lineitem message="The project uses junit with the version between 2.0.0.Final and 2.2.0.Final"/>
    </perform>
</rule>
Construct a <project> element
<project> element attributes

The <project> element is used to match against the project’s Maven POM file. You can use this condition to query for dependencies of the project. It does not have any attributes itself.

<project> child elements
Child element Description

<artifact>

Subcondition used within <project> to query against project dependencies. The <artifact> element attributes are described below.

<artifact> element attributes
Attribute name Type Description

groupId

PROJECT_GROUP_ID

Match on the project <groupId> of the dependency.

artifactId

PROJECT_ARTIFACT_ID

Match on the project <artifactId> of the dependency.

fromVersion

FROM_VERSION

Specify the lower version bound of the artifact. For example 2.0.0.Final.

toVersion

TO_VERSION

Specify the upper version bound of the artifact. For example 2.2.0.Final.

It is possible to qualify the element within the POM file that contains the artifact that the rule is searching for. This is achieved using the optional <location> element. The example below shows a rule that is searching for an artifact within the <plugins> element of the POM file.

rule searching for artifact

The valid list of locations is as follows:

  • DEPENDENCY_MANAGEMENT

  • DEPENDENCIES

  • PLUGIN_MANAGEMENT

  • PLUGINS

  • PARENT

<filecontent> syntax
Summary

Use the <filecontent> element to find strings or text within files, for example, a line in a Properties file. For a better understanding of the <filecontent> condition, see the JavaDoc for the FileContent class.

Construct a <filecontent> element
<filecontent> element attributes
Attribute name Type Description

pattern

String

Match the file contents against the provided parameterized string. This attribute is required.

filename

String

Match the file names against the provided parameterized string.

as

VARIABLE_NAME

A variable name assigned to the rule so that it can be used as a reference in later processing. See the from attribute below.

as="MyEjbRule"

from

VARIABLE_NAME

Begin the search query with the filtered result from a previous search identified by its as VARIABLE_NAME.

from="MyEjbRule"
<file> syntax
Summary

Use the <file> element to find the existence of files with a specific name, for example, an ibm-webservices-ext.xmi file. For a better understanding of the <file> condition, see the JavaDoc for the File class.

Construct a <file> element
<file> element attributes
Attribute name Type Description

filename

String

Match the file names against the provided parameterized string. This attribute is required.

as

VARIABLE_NAME

A variable name assigned to the rule so that it can be used as a reference in later processing. See the from attribute below.

as="MyEjbRule"

from

VARIABLE_NAME

Begin the search query with the filtered result from a previous search identified by its as VARIABLE_NAME.

Example:

from="MyEjbRule"
<has-hint> syntax
Summary

Use the <has-hint> element to test whether a file or line has a hint already associated with it. It is primarily used to prevent firing if a hint already exists, or to implement rules for default execution when no other conditions apply. For a better understanding of the <has-hint> condition, see the JavaDoc for the HasHint class.

The following is an example of a rule that checks to see if a hint exists for an IBM JMS destination message, and if not includes it.

<rule id="websphere-jms-eap7-03000">
  <when>
    <javaclass references="{package}.{prefix}{type}Message" />
  </when>
  <perform>
    <iteration>
      <when>
        <not>
          <has-hint />
        </not>
      </when>
      <perform>
        <hint title="IBM JMS destination message" effort="1" category-id="mandatory">
          <message>
            JMS `{package}.{prefix}{type}Message` messages represent the actual data passed through JMS destinations. This reference should be
            replaced with the Java EE standard API `javax.jms.{type}Message`.
          </message>
          <link href="https://docs.oracle.com/javaee/7/tutorial/jms-concepts003.htm#sthref2271" title="Java EE 7 JMS Tutorial - Message API" />
          <tag>jms</tag>
          <tag>websphere</tag>
        </hint>
      </perform>
    </iteration>
  </perform>
  <where param="type">
    <matches pattern="(Text|Stream|Object|Map|Bytes)?" />
  </where>
  <where param="prefix">
    <matches pattern="(JMS|MQe|MQ)" />
  </where>
  <where param="package">
    <matches pattern="com.ibm(\..*)?\.jms" />
  </where>
</rule>
Construct a <has-hint>

The <has-hint> element is used to determine if a hint exists for a file or line. It does not have any child elements.

<has-hint> element attributes
Attribute name Type Description

message

String

An optional argument allowing you to match the hint against the provided message string.

<has-classification> syntax
Summary

Use the <has-classification> element to test whether a file or line has a classification. It is primarily used to prevent firing if a classification already exists, or to implement rules for default execution when no other conditions apply. For a better understanding of the <has-classification> condition, see the JavaDoc for the HasClassification class.

Construct a <has-classification>

The has-classification element is used to determine if a specified classification exists. It does not have any child elements.

<has-classification> element attributes
Attribute name Type Description

title

String

An optional title to match the classification against.

<graph-query> syntax
Summary

Use the <graph-query> element to search the generated graph for any elements. This element is primarily used to search for specific archives. For a better understanding of the <graph-query> condition, see the JavaDoc for the QueryHandler class.

The following is an example of a rule that tests to determine if any ehcache packages are found.

<rule id="embedded-cache-libraries-01000">
    <when>
        <graph-query discriminator="JarArchiveModel">
            <property name="fileName" searchType="regex">.*ehcache.*\.jar$</property>
        </graph-query>
    </when>
    <perform>
        <classification title="Caching - Ehcache embedded library" category-id="cloud-mandatory" effort="5">
            <description>
                The application embeds an Ehcache library.

                Cloud readiness issue as potential state information that is not persisted to a backing service.
            </description>
        </classification>
        <technology-tag level="INFORMATIONAL">Ehcache (embedded)</technology-tag>
    </perform>
</rule>
Construct a <graph-query>
<graph-query> element attributes
Attribute Name Type Description

discriminator

MODEL_TYPE

The type of model to use for searching. This can be any valid model; however, it is recommended to use the JarArchiveModel for examining archives. This attribute is required.

as

VARIABLE_NAME

A variable name assigned to the rule so that it can be used as a reference in later processing. See the from attribute below.

as="MyEjbRule"

from

VARIABLE_NAME

Begin the search query with the filtered result from a previous search identified by its as VARIABLE_NAME.

from="MyEjbRule"
<graph-query> properties
Property Name Type Description

name

String

The name of the attribute to match against within the chosen model. When using any file-based models it is recommended to match on fileName. This attribute is required.

type

property-type

Defines the expected type of property, either STRING or BOOLEAN.

searchType

property-search-type

Defines how the condition is matched. If set to equals, then an exact match must be made. If using regex, then regular expressions can be used.

<dependency> syntax
Summary

Use the <dependency> element to search dependencies defined within the application’s POM file to determine whether they are supported by the target runtime.

The following is an example of a rule that checks for all artifacts belonging to the org.springframework.boot group that have a version up to, and including, 1.6.0.

<rule id="springboot-00001">
    <!-- rule condition, when it could be fired -->
    <when>
        <dependency groupId="org.springframework.boot" artifactId="{*}" toVersion="1.6.0" />
    </when>
    <!-- rule operation, what to do if it is fired -->
    <perform>
        <hint title="Unsupported version of Spring Boot" effort="3" category-id="mandatory">
            <message>Spring Boot has to be updated to Spring Boot 2.0 before being able to be migrated to a version supported by Red Hat Runtimes</message>
            <link href="https://access.redhat.com/articles/3349341" title="RHOAR Spring Boot Supported Configurations" />
            <link href="https://access.redhat.com/articles/3348731" title="RHOAR Component Details Overview" />
            <link href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide" title="Spring Boot 2.0 Migration Guide" />
        </hint>
    </perform>
</rule>

3.3.2. <perform> syntax

Operations available in the perform section of the rule include the classification of application resources, in-line hints for migration steps, links to migration information, and project lineitem reporting. Because XML rules are modeled after the Java-based rule add-ons, links to JavaDocs for the related Java classes are provided for a better understanding of how they behave.

You can view the complete XML rule schema.

The following sections describe the more common XML rule perform actions.

<classification> syntax
Summary

The <classification> element is used to identify or classify application resources that match the rule. It provides a title that is displayed in the report, a level of effort, and it can also provide links to additional information about how to migrate this resource classification. For a better understanding of the <classification> action, see the JavaDoc for the Classification class.

The following is an example of a rule that classifies a resource as a WebLogic EAR application deployment descriptor file.

<rule id="XmlWebLogicRules_10vvyf">
    <when>
        <xmlfile as="default" matches="/*[local-name()='weblogic-application']"></xmlfile>
    </when>
    <perform>
        <iteration>
            <classification title="Weblogic EAR Application Descriptor" effort="3"/>
        </iteration>
    </perform>
</rule>
<classification> element attributes
Attribute name Type Description

title

STRING

The title given to this resource. This attribute is required.

title="JBoss Seam Components"

effort

BYTE

The level of effort assigned to this resource.

effort="2"

category-id

STRING

A reference to a category as defined in APPCAT_HOME/rules/migration-core/core.windup.categories.xml. The default categories are mandatory, optional, potential, and information.

category-id="mandatory"

of

VARIABLE_NAME

Create a new classification for the given reference.

of="MySeamRule"
<classification> child elements
Child element Description

<link>

Provides a link URI and text title for additional information.

<classification title="Websphere Startup Service" effort="4">
   <link href="http://docs.oracle.com/javaee/6/api/javax/ejb/Singleton.html" title="EJB3.1 Singleton Bean"/>
   <link href="http://docs.oracle.com/javaee/6/api/javax/ejb/Startup.html" title="EJB3.1 Startup Bean"/>
</classification>

<tag>

Provides additional custom information for the classification.

<tag>Seam3</tag>

<description>

Description of this resource

<description>JBoss Seam components must be replaced</description>
Summary

The <link> element is used in classifications or hints to provide links to informational content. For a better understanding of the <link> action, see the JavaDoc for the Link class.

The following is an example of a rule that creates links to additional information.

<rule id="SeamToCDIRules_2fmb">
    <when>
        <javaclass references="org.jboss.seam.{*}" as="default"/>
    </when>
    <perform>
        <iteration>
            <classification title="SEAM Component" effort="1">
                <link href="http://www.seamframework.org/Seam3/Seam2ToSeam3MigrationNotes" title="Seam 2 to Seam 3 Migration Notes"/>
                <link href="http://docs.jboss.org/weld/reference/latest/en-US/html/example.html" title="JSF Web Application Example"/>
                <link href="http://docs.jboss.org/weld/reference/latest/en-US/html/contexts.html" title="JBoss Context Documentation"/>
                <link href="http://www.andygibson.net/blog/tutorial/cdi-conversations-part-2/" title="CDI Conversations Blog Post"/>
            </classification>
        </iteration>
    </perform>
</rule>
Attribute Name Type Description

href

URI

The URI for the referenced link.

href="https://access.redhat.com/articles/1249423"

title

STRING

A title for the link.

title="Migrate WebLogic Proprietary Servlet Annotations"
<hint> syntax
Summary

The <hint> element is used to provide a hint or inline information about how to migrate a section of code. For a better understanding of the <hint> action, see the JavaDoc for the Hint class.

The following is an example of a rule that creates a hint.

<rule id="WebLogicWebServiceRules_8jyqn">
    <when>
        <javaclass references="weblogic.wsee.connection.transport.http.HttpTransportInfo.setUsername({*})" as="default">
            <location>METHOD</location>
        </javaclass>
    </when>
    <perform>
        <iteration>
            <hint title="Proprietary web-service" category-id="mandatory" effort="3">
                <message>Replace proprietary web-service authentication with JAX-WS standards.</message>
                <link href="http://java-x.blogspot.com/2009/03/invoking-web-services-through-proxy.html" title="JAX-WS Proxy Password Example"/>
            </hint>
        </iteration>
    </perform>
</rule>
<hint> element attributes
Attribute name Type Description

title

STRING

Title this hint using the specified string. This attribute is required.

title="JBoss Seam Component Hint"

category-id

STRING

A reference to a category as defined in APPCAT_HOME/rules/migration-core/core.windup.categories.xml. The default categories are mandatory, optional, potential, and information.

category-id="mandatory"

in

VARIABLE_NAME

Create a new Hint in the FileLocationModel resolved by the given variable.

in="Foo"

effort

BYTE

The level of effort assigned to this resource.

effort="2"
<hint> child elements
Child element Description

<message>

A message describing the migration hint.

<message>EJB 2.0 is deprecated</message>

<link>

Identify or classify links to informational content.

<link href="http://docs.oracle.com/javaee/6/api/" title="Java Platform, Enterprise Edition 6
API Specification" />

<tag>

Define a custom tag for this hint.

<tag>Needs review</tag>

<quickfix>

Contains information to be used by the AppCAT plugin to perform quick fixes when the rule condition is met.

<quickfix name="slink-qf" type="REPLACE">
    <replacement>h:link</replacement>
    <search>s:link</search>
</quickfix>
<xslt> syntax
Summary

The <xslt> element specifies how to transform an XML file. For a better understanding of the <xslt> action, see the JavaDoc for the XSLTTransformation class.

The following is an example of rule that defines an XSLT action.

<rule id="XmlWebLogicRules_6bcvk">
    <when>
        <xmlfile as="default" matches="/weblogic-ejb-jar"/>
    </when>
    <perform>
        <iteration>
            <classification title="Weblogic EJB XML" effort="3"/>
            <xslt title="JBoss EJB Descriptor (Windup-Generated)" template="transformations/xslt/weblogic-ejb-to-jboss.xsl" extension="-jboss.xml"/>
        </iteration>
    </perform>
</rule>
<xslt> element attributes
Attribute Name Type Description

title

STRING

Sets the title for this XSLTTransformation in the report. This attribute is required.

title="XSLT Transformed Output"

of

STRING

Create a new transformation for the given reference.

of="testVariable_instance"

extension

STRING

Sets the extension for this XSLTTransformation. This attribute is required.

extension="-result.html"

template

STRING

Sets the XSL template. This attribute is required.

template="simpleXSLT.xsl"

effort

BYTE

The level of effort required for the transformation.

<xslt> child elements
Child element Description

<xslt-parameter>

Specify XSLTTransformation parameters as property value pairs

<xslt-parameter property="title" value="EJB Transformation"/>
<lineitem> syntax
Summary

The <lineitem> element is used to provide general migration requirements for the application, such as the need to replace deprecated libraries or the need to resolve potential class loading issues. This information is displayed on the project or application overview page. For a better understanding of the <lineitem> action, see the JavaDoc for the LineItem class.

The following is an example of a rule that creates a lineitem message.

<rule id="weblogic_servlet_annotation_1000">
    <when>
        <javaclass references="weblogic.servlet.annotation.WLServlet" as="default">
            <location>ANNOTATION</location>
        </javaclass>
    </when>
    <perform>
        <hint effort="1">
            <message>Replace the proprietary WebLogic @WLServlet annotation with the Java EE 6 standard @WebServlet annotation.</message>
            <link href="https://access.redhat.com/articles/1249423" title="Migrate WebLogic Proprietary Servlet Annotations" />
            <lineitem message="Proprietary WebLogic @WLServlet annotation found in file."/>
        </hint>
    </perform>
</rule>
<lineitem> element attributes
Attribute Name Type Description

message

STRING

A lineitem message.

message="Proprietary code found."
<iteration> syntax
Summary

The <iteration> element specifies to iterate over an implicit or explicit variable defined within the rule. For a better understanding of the <iteration> action, see the JavaDoc for the Iteration class.

The following is an example of a rule that performs an iteration.

<rule id="jboss-eap5-xml-19000">
    <when>
        <xmlfile as="jboss-app" matches="/jboss-app"/>
        <xmlfile as="jboss-app-no-DTD" matches="/jboss-app" public-id=""/>
    </when>
    <perform>
        <iteration over="jboss-app">
            <classification title="JBoss application Descriptor" effort="5"/>
        </iteration>
        <iteration over="jboss-app-no-DTD">
            <classification title="JBoss application descriptor with missing DTD" effort="5"/>
        </iteration>
        <iteration over="jboss-app-no-DTD">
            <xslt title="JBoss application descriptor - JBoss 5 (Windup-generated)" template="transformations/xslt/jboss-app-to-jboss5.xsl" extension="-jboss5.xml"/>
        </iteration>
    </perform>
</rule>
<iteration> element attributes
Attribute name Type Description

over

VARIABLE_NAME

Iterate over the condition identified by this VARIABLE_NAME.

over="jboss-app"
<iteration> child elements
Child Element Description

<iteration>

Child elements include a when condition, along with the actions iteration, classification, hint, xslt, lineitem, and otherwise.

3.3.3. <where> syntax

You can define parameters that specify a matching pattern to be used in other elements of an XML rule. This can help simplify the patterns for complex matching expressions.

Use the <where> element to define a parameter. Specify the parameter name using the param attribute and supply the pattern using the <matches> element. This parameter can then be referenced elsewhere in the rule definition using the syntax {<PARAM_NAME>}.

You can view the complete XML rule schema.

The following example rule defines a parameter named subpackage that specifies a pattern of (activeio|activemq).

<rule id="generic-catchall-00600">
  <when>
    <javaclass references="org.apache.{subpackage}.{*}">
    </javaclass>
  </when>
  <perform>
    ...
  </perform>
  <where param="subpackage">
    <matches pattern="(activeio|activemq)" />
  </where>
</rule>

The pattern defined by subpackage will then be substituted in the <javaclass> references attribute. This causes the rule to match on org.apache.activeio.* and org.apache.activemq.* packages.

3.4. Adding a rule to the Azure Migrate application and code assessment for Java

A Azure Migrate application and code assessment for Java rule is installed by copying the rule to the appropriate APPCAT folder. APPCAT scans for rules, which are files with the .windup.xml extension in the following locations:

  • Directory specified by the --userRulesDirectory argument on the APPCAT command line.

  • <APPCAT_HOME>/rules/ directory. <APPCAT_HOME> is the directory where you install and run the Azure Migrate application and code assessment for Java executable.

  • ${user.home}/.appcat/rules/ directory. This directory is created by APPCAT the first time it is run. it contains rules, add-ons, and the APPCAT log.

    Note

    In a Windows operating system, the rules are located in \Documents and Settings\<USER_NAME>\.appcat\rules\ or \Users\<USER_NAME>\.appcat\rules\.

4. Testing XML rules

After you have created an XML rule, you should create a test rule to ensure that it works.

4.1. Creating a test rule

Test rules are created using a process similar to the process for creating a test rule, with the following differences:

  • Test rules should be placed in a tests/ directory beneath the rule to be tested.

  • Any data, such as test classes, should be placed in a data/ directory beneath the tests/ directory.

  • Test rules should use the .windup.test.xml extension.

  • These rules use the structure defined in the Test XML Rule Structure.

In addition, it is recommended to create a test rule that follows the name of the rule it tests. For instance, if a rule were created with a filename of proprietary-rule.appcat.xml, the test rule should be called proprietary-rule.windup.test.xml.

4.1.1. Test XML rule structure

All test XML rules are defined as elements within ruletests which contain one or more rulesets. For more details, see the APPCAT XML rule schema.

A ruletest is a group of one or more tests that targets a specific area of migration. This is the basic structure of the <ruletest> element.

  • <ruletest id="<RULE_TOPIC>-test">: Defines this as a unique APPCAT ruletest and gives it a unique ruletest id.

    • <testDataPath>: Defines the path to any data, such as classes or files, used for testing.

    • <sourceMode>: Indicates if the passed in data only contains source files. If an archive, such as an EAR, WAR, or JAR, is in use, then this should be set to false. Defaults to true.

    • <rulePath>: The path to the rule to be tested. This should end in the name of the rule to test.

    • <ruleset>: Rulesets containing the logic of the test cases. These are identical to the ones defined in Rulesets.

4.1.2. Test XML rule syntax

In addition to the tags in the standard XML rule syntax, the following when conditions are commonly used for creating test rules:

  • <not>

  • <iterable-filter>

  • <classification-exists>

  • <hint-exists>

In addition to the tags in the standard perform action syntax, the following perform conditions are commonly used as actions in test rules:

  • <fail>

<not> syntax
Summary

The <not> element is the standard logical not operator, and is commonly used to perform a <fail> if the condition is not met.

The following is an example of a test rule that fails if only a specific message exists at the end of the analysis.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../proprietary-servlet.windup.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="proprietary-servlet-01000-test">
        <when>
          <!--
	    The `<not>` will perform a logical _not_ operator on the elements within.
	  -->
          <not>
            <!--
	      The defined `<iterable-filter>` has a size of `1`. This rule will only match on a single instance of the defined hint.
	    -->
            <iterable-filter size="1">
              <hint-exists message="Replace the proprietary @ProprietaryServlet annotation with the Java EE 7 standard @WebServlet annotation*" />
            </iterable-filter>
          </not>
        </when>
        <!--
	  This `<perform>` element is only executed if the previous `<when>` condition is false.
          This ensures that it only executes if there is not a single instance of the defined hint.
        -->
        <perform>
          <fail message="Hint for @ProprietaryServlet was not found!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <not> element has no unique attributes or child elements.

<iterable-filter> syntax
Summary

The <iterable-filter> element counts the number of times a condition is verified. For additional information, see the IterableFilter class.

The following is an example that looks for four instances of the specified message.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../proprietary-servlet.appcat.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="proprietary-servlet-03000-test">
        <when>
          <!--
	    The `<not>` will perform a logical _not_ operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined `<iterable-filter>` has a size of `4`. This rule will only match on four instances of the defined hint.
	    -->
            <iterable-filter size="4">
              <hint-exists message="Replace the proprietary @ProprietaryInitParam annotation with the Java EE 7 standard @WebInitParam annotation*" />
            </iterable-filter>
          </not>
        </when>
	<!--
	  This `<perform>` element is only executed if the previous `<when>` condition is false.
	  In this configuration, it only executes if there are not four instances of the defined hint.
	-->
        <perform>
          <fail message="Hint for @ProprietaryInitParam was not found!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <iterable-filter> element has no unique child elements.

<iterable-filter> element attributes
Attribute Name Type Description

size

integer

The number of times to be verified.

<classification-exists> syntax

The <classification-exists> element determines if a specific classification title has been included in the analysis. For additional information, see the ClassificationExists class.

Important

When testing for a message that contains special characters, such as [ or ', you must escape each special character with a backslash (\) to correctly match.

The following is an example that searches for a specific classification title.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../weblogic.appcat.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="weblogic-01000-test">
        <when>
          <!--
	    The `<not>` will perform a logical _not_ operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined `<classification-exists>` is attempting to match on the defined title.
	      This classification would have been generated by a matching `<classification title="WebLogic scheduled job" .../>` rule.
	    -->
            <classification-exists classification="WebLogic scheduled job" />
          </not>
        </when>
	<!--
	  This `<perform>` element is only executed if the previous `<when>` condition is false.
	  In this configuration, it only executes if there is not a matching classification.
	-->
        <perform>
          <fail message="Triggerable not found" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <classification-exists> has no unique child elements.

<classification-exists> element attributes
Attribute Name Type Description

classification

String

The <classification> title to search for.

in

String

An optional argument that restricts matching to files that contain the defined filename.

<hint-exists> syntax

The <hint-exists> element determines if a specific hint has been included in the analysis. It searches for any instances of the defined message, and is typically used to search for the beginning or a specific class inside of a <message> element. For additional information, see the HintExists class.

Important

When testing for a message that contains special characters, such as [ or ', you must escape each special character with a backslash (\) to correctly match.

The following is an example that searches for a specific hint.

<ruletest xmlns="http://windup.jboss.org/schema/jboss-ruleset"
          id="proprietary-servlet-test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
  <testDataPath>data/</testDataPath>
  <rulePath>../weblogic.windup.xml</rulePath>
  <ruleset>
    <rules>
      <rule id="weblogic-eap7-05000-test">
        <when>
          <!--
	    The `<not>` will perform a logical _not_ operator on the elements within.
	  -->
          <not>
	    <!--
	      The defined `<hint-exists>` is attempting to match on the defined message.
	      This message would have been generated by a matching `<message>` element on the `<hint>` condition.
	    -->
            <hint-exists message="Replace with the Java EE standard method .*javax\.transaction\.TransactionManager\.resume\(Transaction tx\).*" />
          </not>
        </when>
	<!--
	  This `<perform>` element is only executed if the previous `<when>` condition is false.
	  In this configuration, it only executes if there is not a matching hint.
	-->
        <perform>
          <fail message="Note to replace with standard TransactionManager.resume is missing!" />
        </perform>
      </rule>
    </rules>
  </ruleset>
</ruletest>

The <hint-exists> element has no unique child elements.

<hint-exists> element attributes
Attribute Name Type Description

message

String

The <hint> message to search for.

in

String

An optional argument that restricts matching to InLineHintModels that reference the given filename.

<fail> syntax

The <fail> element reports the execution as a failure and displays the associated message. It is commonly used in conjunction with the <not> condition to display a message only if the conditions are not met.

The <fail> element has no unique child elements.

<fail> element attributes
Attribute Name Type Description

message

String

The message to be displayed.

4.2. Manually testing an XML rule

You can run an XML rule against your application file to test it:

$ <APPCAT_HOME>/bin/appcat [--sourceMode] --input <INPUT_ARCHIVE_OR_FOLDER> --output <OUTPUT_REPORT_DIRECTORY> --target <TARGET_TECHNOLOGY> --packages <PACKAGE_1> <PACKAGE_2> <PACKAGE_N>

You should see the following result:

Report created: <OUTPUT_REPORT_DIRECTORY>/index.html
              Access it at this URL: file:///<OUTPUT_REPORT_DIRECTORY>/index.html

More examples of how to run APPCAT are located in the Azure Migrate application and code assessment for Java CLI Guide.

4.3. Testing the rules by using JUnit

Once a test rule has been created, it can be analyzed as part of a JUnit test to confirm that the rule meets all criteria for execution. The WindupRulesMultipleTests class in the APPCAT rules repository is designed to test multiple rules simultaneously, and provides feedback on any missing requirements.

Prerequisites
  • Fork and clone the APPCAT XML rules. The location of this repository will be referred to as <RULESETS_REPO>.

  • Create a test XML rule.

Creating the JUnit test configuration

The following instructions detail creating a JUnit test using the Red Hat CodeReady Studio. When using a different IDE it is recommended to consult your IDE’s documentation for instructions on creating a JUnit test.

  1. Import the APPCAT rulesets repository into your IDE.

  2. Copy the custom rules, along with the corresponding tests and data, into </path/to/RULESETS_REPO>/rules-reviewed/<RULE_NAME>/. This should create the following directory structure.

    Directory structure
    ├── *rules-reviewed/*  _(Root directory of the rules found within the project)_
    │   ├── *<RULE_NAME>/*  _(Directory to contain the newly developed rule and tests)_
    │   │   ├── *<RULE_NAME>.windup.xml*  _(Custom rule)_
    │   │   ├── *tests/*  _(Directory that contains any test rules and data)_
    │   │   │   ├── *<RULE_NAME>.windup.test.xml* _(Test rule)_
    │   │   │   └── *data/*  _(Optional directory to contain test rule data)_
  3. Select Run from the top menu bar.

  4. Select Run Configurations…​ from the drop down that appears.

  5. Right-click JUnit from the options on the left side and select New.

  6. Enter the following:

    • Name: A name for your JUnit test, such as WindupRulesMultipleTests.

    • Project: Ensure this is set to appcat-rulesets.

    • Test class: Set this to org.jboss.windup.rules.tests.WindupRulesMultipleTests.

      junit test
  7. Select the Arguments tab, and add the -DrunTestsMatching=<RULE_NAME> VM argument. For instance, if your rule name was community-rules, then you would add -DrunTestsMatching=community-rules as seen in the following image.

    junit test arguments
  8. Click Run in the bottom right corner to begin the test.

    When the execution completes, the results are available for analysis. If all tests passed, then the test rule is correctly formatted. If all tests did not pass, it is recommended to address each of the issues raised in the test failures.

4.4. About validation reports

Validation reports provide details about test rules and failures and contain the following sections:

  • Summary

    This section contains the total number of tests run and reports the number of errors and failures. It displays the total success rate and the time taken, in seconds, for the report to be generated.

  • Package List

    This section contains the number of tests executed for each package and reports the number of errors and failures. It displays the success rate and the time taken, in seconds, for each package to be analyzed.

    A single package named org.jboss.windup.rules.tests is displayed unless additional test cases have been defined.

  • Test Cases

    This section describes the test cases. Each failure includes a Details section that can be expanded to show the stack trace for the assertion, including a human-readable line indicating the source of the error.

4.4.1. Creating a validation report

You can create a validation report for your custom rules.

Prerequisites
  • You must fork and clone the APPCAT XML rules.

  • You must have one or more test XML rules to validate.

Procedure
  1. Navigate to the local appcat-rulesets repository.

  2. Create a directory for your custom rules and tests: appcat-rulesets/rules-reviewed/myTests.

  3. Copy your custom rules and tests to the appcat-rulesets/rules-reviewed/<myTests> directory.

  4. Run the following command from the root directory of the appcat-rulesets repository:

    $ mvn -Dtest=WindupRulesMultipleTests -DrunTestsMatching=<myTests> clean <myReport>:report (1) (2)
    1. Specify the directory containing your custom rules and tests. If you omit the -DrunTestsMatching argument, the validation report will include all the tests and take much longer to generate.

    2. Specify your report name.

    The validation report is created in the appcat-rulesets/target/site/ repository.

4.4.2. Validation report error messages

Validation reports contain errors encountered while running the rules and tests.

The following table contains error messages and how to resolve the errors.

Table 1. Validation report error messages
Error message Description Resolution

No test file matching rule

This error occurs when a rule file exists without a corresponding test file.

Create a test file for the existing rule.

Test rule Ids <RULE_NAME> not found!

This error is thrown when a rule exists without a corresponding ruletest.

Create a test for the existing rule.

XML parse fail on file <FILE_NAME>

The syntax in the XML file is invalid, and unable to be parsed successfully by the rule validator.

Correct the invalid syntax.

Test file path from <testDataPath> tag has not been found. Expected path to test file is: <RULE_DATA_PATH>

No files are found in the path defined in the <testDataPath> tag within the test rule.

Create the path defined in the <testDataPath> tag, and ensure all necessary data files are located within this directory.

The rule with id="<RULE_ID>" has not been executed.

The rule with the provided id has not been executed during this validation.

Ensure that a test data file exists that matches the conditions defined in the specified rule.

5. Overriding rules

You can override core rules distributed with APPCAT or even custom rules. For example, you can change the matching conditions, effort, or hint text for a rule. This is done by making a copy of the original rule, marking it as a rule override, and making the necessary adjustments.

You can disable a rule by creating a rule override with an empty <rule> element.

5.1. Overriding a rule

You can override a core or custom rule.

Procedure
  1. Copy the XML file that contains the rule you want to override to the custom rules directory.

    Custom rules can be placed in <APPCAT_HOME>/rules, ${user.home}/.appcat/rules/, or a directory specified by the --userRulesDirectory command-line argument.

  2. Edit the XML file so that it contains only the <rule> elements for the rules that you want to override.

    Note

    Rules from the original ruleset that are not overridden by the new ruleset are run as normal.

  3. Ensure that you keep the same rule and ruleset IDs. When you copy the original rule XML, this ensures that the IDs match.

  4. Add the <overrideRules>true</overrideRules> element to the ruleset metadata.

  5. Update the rule definition.

    You can change anything in the rule definition. The new rule overrides the original rule in its entirety.

The following rule override example changes the effort of the weblogic-02000 rule in the weblogic ruleset from 1 to 3:

Rule override definition example
<?xml version="1.0"?>
<ruleset id="weblogic"
    xmlns="http://windup.jboss.org/schema/jboss-ruleset"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd"> (1)
    <metadata>
        ...
        <overrideRules>true</overrideRules> (2)
    </metadata>
    <rules>
        <rule id="weblogic-02000" xmlns="http://windup.jboss.org/schema/jboss-ruleset"> (3)
            <when>
                <javaclass references="weblogic.utils.StringUtils.{*}"/>
            </when>
            <perform>
                <hint effort="3" category-id="mandatory" title="WebLogic StringUtils Usage"> (4)
                    <message>Replace with the StringUtils class from Apache Commons.</message>
                    <link href="https://commons.apache.org/proper/commons-lang/" title="Apache Commons Lang"/>
                    <tag>weblogic</tag>
                </hint>
            </perform>
        </rule>
    </rules>
</ruleset>
  1. Ensure that the ruleset id matches the original ruleset id.

  2. Add <overrideRules>true</overrideRules> to the <metadata> section.

  3. Ensure that the rule id matches the original rule id.

  4. Updated effort.

When you run APPCAT, this rule overrides the original rule with the same rule ID. You can verify that the new rule was used by viewing the contents of the Rule Provider Executions Overview.

5.2. Disabling a rule

To disable a rule, create a rule override definition with an empty <rule> element according to the following example:

Rule override definition example to disable a rule
<?xml version="1.0"?>
<ruleset id="weblogic"
    xmlns="http://windup.jboss.org/schema/jboss-ruleset"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
    <metadata>
        ...
        <overrideRules>true</overrideRules>
    </metadata>
    <rules>
        <rule id="weblogic-02000" xmlns="http://windup.jboss.org/schema/jboss-ruleset">
        (1)
        </rule>
    </rules>
</ruleset>
  1. The <rule> element is empty so that the weblogic-02000 rule in the weblogic ruleset is disabled.

6. Using custom rule categories

You can create custom rule categories and assign APPCAT rules to them.

Note

Although APPCAT processes rules with the legacy severity field, you must update your custom rules to use the new category-id field.

Adding a custom category

You can add a custom category to the rule category file.

Procedure
  1. Edit the rule category file, which is located at <APPCAT_HOME>/rules/migration-core/core.windup.categories.xml.

  2. Add a new <category> element and fill in the following parameters:

    • id: The ID that APPCAT rules use to reference the category.

    • priority: The sorting priority relative to other categories. The category with the lowest value is displayed first.

    • name: The display name of the category.

    • description: The description of the category.

      Custom rule category example
      <?xml version="1.0"?>
      <categories>
          ...
          <category id="custom-category" priority="20000">
              <name>Custom Category</name>
              <description>This is a custom category.</description>
          </category>
      </categories>

      This category is ready to be referenced by APPCAT rules.

Assigning a rule to a custom category

You can assign a rule to your new custom category.

Procedure

In your APPCAT rule, update the category-id field as in the following example.

<rule id="rule-id">
    <when>
        ...
    </when>
    <perform>
        <hint title="Rule Title" effort="1" category-id="custom-category">
            <message>Hint message.</message>
        </hint>
    </perform>
 </rule>

If this rule condition is met, incidents identified by this rule use your custom category. The custom category is displayed on the dashboard and in the Issues report.

Custom rule category on the Dashboard
Figure 3. Custom category on the dashboard

Appendix A: Reference material

A.1. About rule story points

A.1.1. What are story points?

Story points are an abstract metric commonly used in Agile software development to estimate the level of effort needed to implement a feature or change.

The Azure Migrate application and code assessment for Java uses story points to express the level of effort needed to migrate particular application constructs, and the application as a whole. It does not necessarily translate to man-hours, but the value should be consistent across tasks.

A.1.2. How story points are estimated in rules

Estimating the level of effort for the story points for a rule can be tricky. The following are the general guidelines APPCAT uses when estimating the level of effort required for a rule.

Level of Effort Story Points Description

Information

0

An informational warning with very low or no priority for migration.

Trivial

1

The migration is a trivial change or a simple library swap with no or minimal API changes.

Complex

3

The changes required for the migration task are complex, but have a documented solution.

Redesign

5

The migration task requires a redesign or a complete library change, with significant API changes.

Rearchitecture

7

The migration requires a complete rearchitecture of the component or subsystem.

Unknown

13

The migration solution is not known and may need a complete rewrite.

A.1.3. Task category

In addition to the level of effort, you can categorize migration tasks to indicate the severity of the task. The following categories are used to group issues to help prioritize the migration effort.

Mandatory

The task must be completed for a successful migration. If the changes are not made, the resulting application will not build or run successfully. Examples include replacement of proprietary APIs that are not supported in the target platform.

Optional

If the migration task is not completed, the application should work, but the results may not be optimal. If the change is not made at the time of migration, it is recommended to put it on the schedule soon after your migration is completed. An example of this would be the upgrade of EJB 2.x code to EJB 3.

Potential

The task should be examined during the migration process, but there is not enough detailed information to determine if the task is mandatory for the migration to succeed. An example of this would be migrating a third-party proprietary type where there is no directly compatible type.

Information

The task is included to inform you of the existence of certain files. These may need to be examined or modified as part of the modernization effort, but changes are typically not required. An example of this would be the presence of a logging dependency or a Maven pom.xml.

For more information on categorizing tasks, see Using custom rule categories.

A.2. Additional resources

A.2.1. Reviewing existing APPCAT XML rules

APPCAT XML-based rules are located on GitHub at the following location: https://github.com/Azure/appcat-rulesets/tree/master/rules/rules-reviewed.

You can fork and clone the APPCAT XML rules on your local machine.

Rules are grouped by target platform and function. When you create a new rule, it is helpful to find a rule that is similar to the one you need and use it as a starting template.

New rules are continually added, so it is a good idea to check back frequently to review the updates.

Forking and cloning the Azure Migrate application and code assessment for Java XML rules

The Azure Migrate application and code assessment for Java appcat-rulesets repository provide working examples of how to create custom Java-based rule add-ons and XML rules. You can use them as a starting point for creating your own custom rules.

You must have the git client installed on your machine.

  1. Click the Fork link on the Azure Migrate application and code assessment for Java Rulesets GitHub page to create the project in your own Git. The forked GitHub repository URL created by the fork should look like this: https://github.com/<YOUR_USER_NAME>/appcat-rulesets.git.

  2. Clone your Azure Migrate application and code assessment for Java rulesets repository to your local file system:

    $ git clone https://github.com/<YOUR_USER_NAME>/appcat-rulesets.git
  3. This creates and populates a appcat-rulesets directory on your local file system. Navigate to the newly created directory, for example

    $ cd appcat-rulesets/
  4. If you want to be able to retrieve the latest code updates, add the remote upstream repository so you can fetch any changes to the original forked repository.

    $ git remote add upstream https://github.com/Azure/appcat-rulesets.git
  5. Get the latest files from the upstream repository.

    $ git fetch upstream





Revised on 2023-11-14 15:17:32 UTC