migration toolkit for applications 8.1

Configuring and using rules for an MTA analysis

Create custom rules to enhance migration coverage.

Red Hat Customer Content Services

Abstract

This guide describes how to create custom XML rules for the migration toolkit for applications.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the enormity of this endeavor, these changes will be implemented gradually over several upcoming releases. For more details, see our CTO Chris Wright’s message.

Chapter 1. Introduction to rules

Architects can create custom YAML rules to define problematic patterns for dependencies, custom libraries, and components in the application source code before migrating it to a target technology. Migration toolkit for applications (MTA) reuses the rules to identify issues when analyzing applications.

1.1. The MTA rules

Migration toolkit for applications (MTA) analyzes the application source code to find issues based on user-generated and default rule definitions. You can fix issues in an analysis report before migrating the code to a target platform. You can view the rule syntax information to create a new rule or a ruleset.

A ruleset is a collection of one or more rules. An Architect can create rulesets to organize one or more rules that analyze the source code for a specific target platform.

You can use rules or rulesets as input arguments in an analysis. You can perform a rule-based analysis in the MTA CLI, user interface, or by using one of the IDE plugins for MTA (Visual Studio Code or IntelliJ).

Red Hat Developer Lightspeed for MTA uses rules to generate AI-assisted code resolutions. Red Hat Developer Lightspeed for MTA uses the issue description and metadata in rules to form well-defined contexts. These contexts generate AI-assisted suggestions to resolve issues in the code that MTA identified through an analysis.

1.1.1. How MTA performs an analysis

Migration toolkit for applications (MTA) contains the analyzer that uses pluggable providers and rules to analyze static code, dependencies, and other files in your application.

The analyzer works with providers to detect issues that cause problems when you migrate the application to target technologies. The rule definition contains metadata description and condition patterns that describe a violation.

The analyzer runs a search query on the source code to match the violation described in the rule definition. The rule definition also contains a message that MTA displays when triggering an issue because of the violation. The analyzer uses default and user-provided (custom) rules during an analysis to identify issues.

1.2. YAML rule structure and syntax

Rules instruct the analyzer to take the specified actions when the given conditions match. In MTA, a rule file contains one or more rules.

You can write rules in YAML. They consist of:

  • metadata
  • conditions
  • actions

MTA analyzer rules have the following pattern:

ruleID: <Rule_id>
category: mandatory
effort: <Effort_number>
description:
   <Description title>
   <Description text>
labels:
  - konveyor.io/source=<Source_tech>
  - konveyor.io/target=<Target_tech>
links:
 - url: <Hyperlink>
   title: <Hyperlink_title>
when:
 <condition(s)>
message: "message"
tag:
 - <tag_1>, <tag_2>, <tag_3>
 - key_1="<value_1>, <value_2>"

where:

ruleID
A unique id for the rule within the ruleset
category
Severity level of an issue that the rule triggers can be severe, mandatory, or optional.
effort
An integer value that represents the level of effort needed to fix the issue.
description
A short sentence or a title that summarizes the issue.
labels
A key-value pair of source and target technology. You can also add filter in the label to always include or exclude this rule during an analysis.

Chapter 2. Rule metadata

As an Architect, you include information about effort, category, and label in the rule metadata. Effort measures the issue complexity while category indicates the resolution priority. Labels help the analyzer to filter the rule based on a dependency or a technology.

2.1. Rule metadata structure

Rule metadata contains a unique rule ID, labels, effort, and category so that the analyzer can select the rules for an analysis and compute the total effort to resolve the issues detected in the source code.

You can use rule metadata to:

  • Estimate the total migration effort.
  • Prioritize issues for resolution based on the effort.
  • Evaluate if a resolution is mandatory through rule category before migrating the applications to the target technologies or platforms.
  • Define labels that MTA uses to filter rules for an analysis.
ruleID: "<unique_id>"
labels:
  # key=value pair
  - "label1=<val1>"
  # valid label with value omitted
  - "label2"
  # valid label with empty value
  - "label3="
  # subdomain prefixed key
  - "konveyor.io/label1=<val1>"
effort: 1
category: mandatory

where:

  • ruleID is a unique ID for the rule. It must be unique within the ruleset.
  • labels is a list of string labels associated with the rule.
  • effort is an integer value that indicates the level of effort needed to resolve this issue.
  • category is the severity of the issue for migration. Values can be one of mandatory, potential or optional.

Additional resources

2.2. Rule labels

Labels are key=val pairs specified in rules to filter the rule by the label. During an analysis, you can use the --label-selector option to apply the filter for rules or rulesets and the --dep-label-selector option to apply the filter for dependencies.

For dependencies, a provider adds the labels to the dependencies when retrieving them. Labels on a ruleset are automatically inherited by all the rules that belong to it.

Label format
You can enter Labels under the labels field as a list of strings in key=val format as follows:
labels:
- "key1=<val1>"
- "key2=<val2>"

The key of a label can be subdomain-prefixed:

labels:
- "konveyor.io/key1=<val1>"

The value of a label can be empty:

labels:
- "konveyor.io/key="

You can omit the value of a label. In that case, MTA treats it as an empty value:

labels:
- "konveyor.io/key"

2.2.1. Reserved labels

The analyzer defines some labels that have special meaning as follows:

  • konveyor.io/source: Identifies the source technology to which a rule or a ruleset applies.
  • konveyor.io/target: Identifies the target technology to which a rule or a ruleset applies.
  • konveyor.io/include: Overrides filter behavior for a rule irrespective of the label selector used. The value can either be always or never. If you specify always, the analyzer always filters-in this rule, while for never, the analyzer excludes this rule.

    Label selector
    The analyzer CLI takes the --label-selector field as an option. It is a string expression that supports logical AND, OR, and NOT operations. You can use it to filter-in or filter-out rules by their labels.

Examples:

  • To filter-in all rules that have a label with the key konveyor.io/source and value eap6:

    --label-selector="konveyor.io/source=eap6"
  • To filter-in all rules that have a label with the key konveyor.io/source and any value:

    --label-selector="konveyor.io/source"
  • To perform logical AND operations on matches of multiple rules by using the && operator:

    --label-selector="key1=<val1> && key2"
  • To perform logical OR operations on matches of multiple rules by using the || operator:

    --label-selector="key1=<val1> || key2"
  • To perform a NOT operation to filter-out rules that have key1=val1 label set by using the ! operator:

    --label-selector="!key1=<val1>"
  • To group sub-expressions and control precedence by using AND:

    --label-selector="(key1=<val1> || key2=<val2>) && !<val3>"

2.2.2. Dependency labels

The analyzer engine adds labels to dependencies. These labels provide additional information about a dependency, such as its programming language and whether the dependency is open source or internal.

Currently, the analyzer adds the following labels to dependencies:

labels:
- konveyor.io/dep-source=internal
- konveyor.io/language=java
Dependency label selector
The analyzer CLI accepts the --dep-label-selector option, which allows filtering-in or filtering-out incidents generated from a dependency by their labels.

For example, the analyzer adds a konveyor.io/dep-source label to dependencies with a value that indicates whether the dependency is a known open source dependency.

To exclude incidents for all such open source dependencies, you can use --dep-label-selector as follows:

$ mta-cli ... --dep-label-selector !konveyor.io/dep-source=open-source

The Java provider in the analyzer can also add an exclude label to a list of packages. To exclude all such packages, you can use --dep-label-selector and the ! operator as follows:

$ mta-cli ... --dep-label-selector !konveyor.io/exclude
$ mta-cli ... --dep-label-selector !konveyor.io/exclude

2.3. Rule categories

Migration toolkit for applications (MTA) applies rule categories per rule. The Architect assigns one of the following rule categories to indicate the risk associated with not resolving an issue.

  • mandatory: You must resolve the issue for a successful migration. If you do not make the changes, the resulting application will not build or run successfully. Examples include the replacement of proprietary APIs that are not supported in the target platform.
  • optional: If you do not resolve the issue, the application should work, but the results might not be optimal. If you do not make the change at the time of migration, include it on the schedule soon after you complete the migration.
  • potential: You need to examine the issue 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 such an issue is migrating a third-party proprietary type when there is no directly compatible type on the target platform.

Chapter 3. Providers and rule conditions

Providers are the modular components that work with the analysis engine and the Language Server Protocol (LSP) server to analyze the application source code. They run search queries on the source code based on rule patterns to scan for issues.

3.1. Provider capabilities in custom rules

The external providers, except C#, use the Language Server Protocol (LSP) server to perform an analysis. The provider forms a search query and sends it to the LSP server to check against the application. When the LSP server returns a match for the search in the source code, the analyzer triggers a violation.

Currently, MTA supports the following providers:

  • builtin
  • Java
  • C#
  • External providers (for Python, Go, and Node.js applications) initialized by the generic provider binary
Note

You can use the generic provider binary to create an external provider for any language that is compliant with LSP specifications.

Additional resources

3.2. Provider capabilities in custom rules

As an Architect, you define conditions and patterns in custom rules that MTA uses to match against the source code and dependencies in an analysis. You can specify the conditions in the when block of the rule. You can use capabilities available in each provider to match rule patterns.

The when block contains a single condition, but that condition might have one or more conditions nested under it.

when:
  <condition>
    <nested-condition>

3.3. Rule condition

In the rule condition, the Architect defines the patterns that MTA searches for in the source code to trigger an issue. The condition you can define to search an application written in a programming language depends on the capabilities that providers offer.

A rule condition instructs the analyzer to use a specific provider and one of its capabilities. A condition follows the <provider_name>.<capability> pattern.

when:
  <provider_name>.<capability>
    <input_fields>

The analyzer currently supports the following providers:

  • builtin
  • java
  • go
  • nodejs
  • python
  • csharp
Important

csharp, python, and nodejs providers are Developer Preview features only. Developer Preview features are not supported by Red Hat in any way and are not functionally complete or production-ready. Do not use Developer Preview features for production or business-critical workloads. Developer Preview features provide early access to upcoming product features in advance of their possible inclusion in a Red Hat product offering, enabling customers to test functionality and provide feedback during the development process. These features might not have any documentation, are subject to change or removal at any time, and testing is limited. Red Hat might provide ways to submit feedback on Developer Preview features without an associated Service Level Agreement (SLA).

Provider rule conditionsProvider name

Providers that are fully supported and included in the product

java

Providers that have rules already defined in the product

  • java

Providers that require custom rulesets for analysis

  • go
  • python
  • nodejs
  • csharp

The following table summarizes all the providers and their capabilities:

Table 3.1. Summary of providers and their capabilities

Provider NameCapabilitiesDescription

java

referenced

Find references of a pattern with an optional code location for detailed searches. For example,

when:
  java.referenced:
    <fields>

dependency

Check whether the application has a given dependency. For example,

when:
  java.dependency:
    <fields>

builtin

xml

Search XML files using XPath queries.

json

Search JSON files using JSONPath queries. For example,

when:
  builtin.json:
    <fields>

filecontent

Search content in regular files using regular expression patterns. For example,

when:
  builtin.filecontent:
    <fields>

file

Find files with names matching a given pattern. For example,

when:
  builtin.file:
    <fields>

hasTags

Check whether you created a tag for the application using a tagging rule. For example,

when:
  builtin.hasTags:
    <fields>

go

referenced

Find references to a pattern. For example,

when:
  go.referenced:
    <fields>

dependency

Check whether the application has a given dependency. For example,

when:
  go.dependency:
    <fields>

csharp

referenced

Find references to a pattern. For example,

when:
  csharp.referenced:
    <fields>

Following the example in the previous table, you can create the first part of the condition that does not contain any of the condition fields.

To create a java provider condition that uses the referenced capability:

when:
  java.referenced:
    <fields>
Note

Depending on the provider and the capability, there will be different <fields> in the condition.

The following table summarizes available providers, their capabilities and their fields:

Table 3.2. Summary of providers, their capabilities, and their fields

ProviderCapabilityFieldsRequiredDescription

java

referenced

pattern

Yes

Regular expression pattern. For example,

when:
  java.referenced:
    location: PACKAGE
    pattern: org.jboss.*

location

No

Source code location. See Java locations. For example,

when:
  java.referenced:
    pattern: org.kubernetes*
    location: IMPORT

annotated

No

Additional query to inspect annotations. See Annotation inspection. For example,

when:
  java.referenced:
    location: ANNOTATION
    pattern: javax.ejb.Singleton

dependency

name

Yes

Name of the dependency. For example,

when:
  java.dependency:
    name: junit.junit

nameregex

No

Regular expression pattern to match the name.

upperbound

No

Match versions lower than or equal to. For example,

when:
  java.dependency:
    name: junit.junit
    upperbound: 4.12.2

lowerbound

No

Match versions greater than or equal to. For example,

when:
  java.dependency:
    name: junit.junit
    upperbound: 4.12.2
    lowerbound: 4.4.0

builtin

xml

xpath

Yes

an XPath query

when:
  builtin.xml:
    xpath: "//dependencies/dependency"

namespaces

No

A map to scope down query to namespaces.

when:
  builtin.xml:
    filepaths:
     - beans.xml
    namespaces:
        b: http://xmlns.jcp.org/xml/ns/javaee
    xpath: /b:beans

filepaths

No

Optional list of files to scope down search.

when:
    or:
    - builtin.xml:
        xpath: "//dependencies/dependency"
        filepaths: "{{poms.filepaths}}"
      from: poms
    - builtin.file:
        pattern: pom.xml
      as: poms
      ignore: true

json

xpath

Yes

an XPath query For example,

when:
    and:
    - builtin.json:
        xpath: //inclusionTestNode

filepaths

No

Optional list of files to scope down search. For example,

when:
    and:
    - builtin.json:
        xpath: //inclusionTestNode
        filepaths: "{{incTest.filepaths}}"

filecontent

pattern

Yes

Regular expression pattern to match in content. For example,

when:
  builtin.filecontent:
    pattern: "import.*React"

filePattern

No

Only search in files with names matching this pattern. For example,

when:
  builtin.filecontent:
    pattern: "import.*React"
    filePattern: "\\.tsx$"

file

pattern

Yes

Find files with names matching this pattern. For example,

when:
    builtin.file:
      pattern: "*.go"

hasTags

  

This is an inline list of string tags. See Tag action. For example,

when:
  or:
   - builtin.hasTags:
     - Golang
     - Kubernetes

go

referenced

pattern

Yes

Regular expression pattern. For example,

when:
  go.referenced:
    pattern: "v1beta1.CustomResourceDefinition"

dependency

name

Yes

Name of the dependency. For example,

when:
  - go.dependency:
      name: sigs.k8s.io/structured-merge-diff/v4

nameregex

No

Regular expression pattern to match the name.

upperbound

No

Match versions lower than or equal to. For example,

when:
  - go.dependency:
      name: sigs.k8s.io/structured-merge-diff/v4
      upperbound: v4.2.2

lowerbound

No

Match versions greater than or equal to. For example,

when:
  - go.dependency:
      name: sigs.k8s.io/structured-merge-diff/v4
      lowerbound: v4.2.0

csharp

referenced

pattern

Yes

Regular expression to match a reference in the source code. For example, System.Web.Mvc.*.

location

Yes

Specify one of the following for which MTA runs a search query:

  • Type reference including classes, interfaces and structure types (struct). For example:
  ----
  when:
    csharp.referenced:
      location: CLASS
      pattern: System.Web.Http.ApiController.*
  ----
  ----
  when:
    csharp.referenced:
      location: ALL
      pattern: "System.Console.Print*"
  ----
  • Method calls and definitions. For example:
  ----
  when:
    csharp.referenced:
      location: METHOD
      pattern: "*.AppDomain.Unload"
  ----
  • Field usages and declaration. For example:
  ----
  when:
    csharp.referenced:
      location: FIELD
      pattern: "DotNetOpenAuth.AspNet.AuthenticationResult.Provider"
  ----
  • Namespace imports and usages. For example:
  ----
  when:
    csharp.referenced:
      location: ALL
      pattern: "System.Windows.Forms"
  ----
  • ALL - You can also specify ALL as location to run a search query on any location in the code, including namespaces, structure types, and interfaces.

3.4. The builtin provider

The builtin is an internal provider that can analyze files and internal metadata generated by the rule engine. The builtin provider can parse XML, run regular expressions on files, and scan for application tags.

The builtin provider offers the following capabilities:

file

By using the file capability, the provider searches for files in the source code that match a given pattern.

when:
  builtin.file:
    pattern: "<regular_expression_to_match_filenames>"
filecontent

By using the filecontent capability, the provider searches for content that matches a given pattern.

when:
  builtin.filecontent:
    filePattern: "<regular_expression_to_match_filenames_to_scope_search>"
    pattern: "<regular_expression_to_match_content_in_the_matching_files>"
xml

The xml capability enables the provider to query XPath expressions on a list of provided XML files. This capability takes 2 input parameters, xpath and filepaths.

when:
  builtin.xml:
    xpath: "<xpath_expressions>"
    filepaths:
      - "/src/file1.xml"
      - "/src/file2.xml"
    namespaces:
        var: http://www.springframework.org/schema/beans
        xpath: //*/var:bean/@class[matches(self::node(), 'org.apache.camel.util.toolbox.XsltAggregationStrategy')]

where:

  • xpath is a valid XPath expression.
  • filepaths is a list of files to apply the XPath query to.
  • namespaces define namespaces and assign them to variables. You can use the variable in the xpath.
json

By using the json capability, the provider queries XPath expressions on a list of provided JSON files. Currently, json only takes XPath as input and performs the search on all JSON files in the codebase.

when:
  builtin.json:
    xpath: "<xpath_expressions>"

where xpath must be a valid XPath expression.

hasTags

By using the hasTags capability, the provider queries application tags. It queries the internal data structure to check whether the application has the given tags.

when:
  # when more than one tag is given, a logical AND is implied
  hasTags:
    - "tag1"
    - "tag2"

3.5. Java provider

The java provider offers referenced and dependency capabilities to analyze Java source code.

referenced

The referenced capability takes three input parameters: pattern, location, and annotated:

when:
  java.referenced:
    pattern: "<pattern>"
    location: "<location>"
    annotated: "<annotated>"

where:

  • pattern is a regular expression pattern to match.
  • location is the exact source code location where MTA matches the pattern, for example, IMPORT.
  • annotated checks for specific annotations and their elements, such as name and value, in the Java code by using a query. For example, the following query matches the Bean (URL = “http://www.example.com”) annotation in the method.

     annotated:
          pattern: org.framework.Bean
          elements:
          - name: url
            value: "http://www.example.com"
dependency

The Java provider has dependency capability. The dependency capability enables the provider to generate a list of dependencies for a given application.

You can use a dependency condition to query this list and check whether a certain dependency, with a version range, exists for the application. The dependency can be internal and external or open source. For example, to check if a Java application has a certain dependency, you create a java.dependency condition:

when:
  java.dependency:
    name: junit.junit
    upperbound: 4.12.2
    lowerbound: 4.4.0

You can use the dependency capability to check if a Java application has Fabric8 Kubernetes client of version 5.0.100 or lower:

- java.dependency:
    name: io.fabric8.kubernetes-client
    lowerbound: 5.0.100
Note

When you use the java provider for an analysis, the analysis results have lower precision for projects that cannot be built. For example, when MTA is unable to build a Maven project, it falls back to parsing the pom file to get the list of dependencies.

Additional resources

3.6. Go provider

The go provider offers referenced and dependency capabilities to analyze Go source code.

referenced

By using the referenced capability, the provider finds references in the source code.

when:
  go.referenced: "<regex_to_find_reference>"
dependency

By using the dependency capability, the provider finds dependencies for a Go application.

when:
  go.dependency:
    name: "<dependency_name>"
    upperbound: "<version_string>"
    lowerbound: "<version_string>"

where:

  • name is a name of the dependency to search for.
  • upperbound is an upper bound on the version of the dependency.
  • lowerbound is a lower bound on the version of the dependency.

3.7. C# provider

The C# provider can analyze .NET and C# application source code by using the referenced capability. The C# provider uses a gRPC interface to perform a semantic analysis of an application source code in the source-only mode.

The provider parses the source code by using tree-sitter and uses stack graph for the analysis to find references to types, methods, classes, and fields. Based on the custom rule definition, the analyzer identifies violations in the source code that Migrators must resolve before the application migration.

referenced
The C# provider supports the referenced capability in rules to define fields such as pattern and location. The provider uses these patterns to search the source code for violations.
when:
  csharp.referenced:
    pattern: "<pattern>"
    location: CLASS

where:

  • pattern is a regular expression pattern to match the required reference, for example, HttpNotFound.
  • namespace is a namespace to search within, for example, System.Web.Mvc.

Chapter 4. Java condition and capabilities

As an Architect, you can create custom rules to analyze the Java source code for problematic patterns before migration. The Java provider uses Eclipse Java Development Tools Language Server (JDTLS) that depends on the Eclipse Java Development Toolkit for utilities to search the source code.

4.1. Java locations

By using the fields in the referenced capability that Java provider supports, you can enable the provider to scope the search down to certain source code locations.

You can use the java.referenced capability in the when condition of the Java rules to search for the following fields:

  • Locations such as the classes, methods, packages and so on
  • Annotations
  • Patterns

Example

*IMPORT*: IMPORT allows for searches on class imports. You can use it either with Fully Qualified Names (FQNs) or an asterisk to allow for wider matches:

[source,yaml]
----
java.referenced:
  pattern: org.apache.lucene.search.*
  location: IMPORT
----

would match on each of these imports:

[source,java]
----
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
----

* *PACKAGE*: the `PACKAGE` location matches on any usage of a package, be
it in an import or used as part of an FQN in the code:

[source,yaml]
----
java.referenced:
  pattern: org.apache.lucene.search.*
  location: PACKAGE
----

would match on each of the following imports and the FQN usage:

[source,java]
----
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
----

[source,java]
----
public class Test {
  private org.apache.lucene.search.Query query;
}
----

Table 4.1. Supported Java locations

LocationDescriptionRule condition example

TYPE

Matches against all types, including classes, interfaces, enums, and annotation types that appear anywhere.

The following example looks for occurrences of java.util.List.

 when:
  java.referenced:
   location: TYPE
   pattern: java.util.List

ANNOTATION

Matches against annotations.

The following example matches the @org.framework.Bean(url = "http://www.example.com") annotation in the source code.

when:
  java.referenced:
    location: ANNOTATION
    pattern: org.framework.Bean
    annotated:
      elements:
        - name: url
          value: "http://www.example.com"

IMPLEMENTS_TYPE

Matches against any type implementing the given type.

The following example looks for a class that implements java.util.ArrayList.

 when:
  java.referenced:
   location: IMPLEMENTS_TYPE
   pattern: java.util.ArrayList

RETURN_TYPE

Matches against a type that a method returns.

The following example searches for @PersistenceContext annotation for injecting data sources and @Produces annotation on the EntityManager. These annotations are not required when you target migrating the source code to Quarkus.

when:
  java.referenced:
    location: RETURN_TYPE
      pattern: javax.persistence.EntityManager
      annotated:
        pattern: javax.enterprise.inject.Produces

VARIABLE_DECLARATION

Matches against a type declared as a variable

The following example searches for QueueConnectionFactory appearing as a variable declaration. Replace the string QueueConnectionFactory with ConnectionFactory.

when:
  - java.referenced:
      location: VARIABLE_DECLARATION
      pattern: javax.jms.QueueConnectionFactory

FIELD

Matches against a type appearing in a field declaration. It can be coupled with an annotation match happening on the field. See Annotation inspection.

The following example searches if QueueConnectionFactory appears in a field declaration. Replace the string QueueConnectionFactory with ConnectionFactory.

when:
  - java.referenced:
      location: FIELD_DECLARATION
      pattern: javax.jms.QueueConnectionFactory

METHOD

Matches against a given method declaration. You can couple it with an annotation match. See Annotation inspection.

The following example finds declarations of methods named method that accept java.lang.String and return org.konveyor.ExtendedString.

when:
 java.referenced:
   location: METHOD
   pattern: 'method(java.lang.String) org.konveyor.ExtendedString'

METHOD_CALL

Matches against the method call in the source code.

The following example matches the getConnection method call of the java.sql.DriverManager class with three parameters of type String.

when:
  java.referenced:
    location: METHOD_CALL
    pattern: java.sql.DriverManager.getConnection(java.lang.String, java.lang.String, java.lang.String)

CLASS (declaration)

Matches against a given class declaration. You can couple it with an annotation match. See Annotation inspection.

The following example locates all classes under the javax.xml package occurring in all locations of the source code.

when:
 java.referenced:
  pattern: javax.xml.*

CONSTRUCTOR_CALL

Matches against constructor calls in the source code.

The following example matches the FileOutputStream constructor call that takes a String and a boolean value as input parameters.

when:
  java.referenced:
    location: CONSTRUCTOR_CALL
    pattern: java.io.FileOutputStream(java.lang.String, boolean)

IMPORT

Matches against class imports. You can use it with FQNs or an asterisk (*) to allow for wider matches.

The following example matches with the imports of org.apache.lucene.search package and subpackages in the source code.

when:
 java.referenced:
   pattern: org.apache.lucene.search.*
   location: IMPORT

PACKAGE

Matches on any usage of a package, be it in an import or used as part of a fully qualified name in the code.

The following example matches all occurrences of org.jboss package and its subpackages in the source code.

when:
  java.referenced:
    location: PACKAGE
    pattern: org.jboss.*

INHERITANCE

Matches against a class inheriting from a given type.

The following example searches for interfaces that extend the org.jboss.system.ServiceMBeanSupport class.

 when:
  java.referenced:
    pattern: 'org.jboss.system.ServiceMBeanSupport'
    location: INHERITANCE

Additional resources

4.2. Annotation inspection

You can use the annotated field in the rule condition to match against specific Java annotations and their elements in the source code.

The following example matches against a specific annotation and its elements:

when:
  java.referenced:
    location: METHOD
    pattern: org.package.MyApplication.runApplication(java.lang.String)
    annotated:
      pattern: org.framework.Bean
      elements:
      - name: url
        value: "http://www.example.com"

This would match against the runApplication method in the following Java code:

package org.package

import org.framework.Bean;

class MyApplication {

    @Bean(url = "http://www.example.com")
    public String runApplication(String str) {
        // ...
    }
}

The structure of the annotated YAML element is:

annotated:
  pattern: a Java regular expression to match the fully qualified name of the annotation (optional)
  elements: an array of elements to match within the annotation (optional)
  - name: the exact name of the element to match against
    value: a Java regular expression to match the value of the element

It is also possible to match an annotation with specific elements without having to specify the symbol it annotates. The following example would also match on the @Bean annotation in the same code as the previous example:

when:
  java.referenced:
    location: ANNOTATION
    pattern: org.framework.Bean
    annotated:
      elements:
        - name: url
          value: "http://www.example.com"
Note

The only element specified with a pattern is the annotation itself.

4.3. Condition patterns

In the pattern field of a java.referenced condition, the analyzer can search through application code by using the Java Development Kit (JDK) utilities. You can use a wildcard or a specific string to locate classes and methods to refine what the analyzer searches for in the source code.

For more details on the JDK utilities, see Class SearchPattern documentation, which contains all the information for building these patterns for createPattern(String, int, int, int).

Review the following examples of condition patterns:

  • Search for any class under the javax.xml package, occurring in any location:

    java.referenced:
      pattern: javax.xml.*
  • Search for method declarations that return java.lang.String:

    java.referenced:
      location: METHOD
      pattern: '* java.lang.String'
  • Search for a method named “method” declared on org.konveyor.MyClass that returns a List of a type that extends java.lang.String:

    java.referenced:
      location: METHOD
      pattern: 'org.konveyor.Myclass.method(*) java.util.List<? extends java.lang.String>'
  • Search for a class that implements java.util.List:

    java.referenced:
      location: IMPLEMENTS_TYPE
      pattern: java.util.List

Additional resources

Chapter 5. Logical conditions, condition chaining, and custom variables

When you create a rule, you can limit the search query in the source code by using logical conditions, condition chaining, nested conditions, and custom variables. You can narrow the search to specific files, a pattern, or a combination of conditions.

5.1. Rule condition complexity

You can create complex rules to combine conditions, use the output of one rule as an input to another, and chain conditions.

  • Logical conditions inform the provider how to handle more than one condition in a when block. The analyzer provides the logical conditions, and and or, that you can use to combine results of many conditions.
  • Condition chaining uses the output of one condition as the input in another condition of the when block. Assign the output to a variable in one condition and reuse it in other conditions in the when block.
  • Nested conditions create conditions that depend on the evaluation of other conditions.
  • Custom variables capture specific information from the code. You can use the custom variable in the message displayed for the code if it contains a violation defined by the rule.

5.2. AND condition

The and condition performs a logical AND operation on the results of an array of conditions. The condition matches when all of its child conditions match, for example:

when:
  and:
    - <condition1>
    - <condition2>

For an example rule condition, see:

when:
  and:
    - java.dependency:
        name: junit.junit
        upperbound: 4.12.2
        lowerbound: 4.4.0
    - java.referenced:
        location: IMPORT
        pattern: junit.junit

5.3. OR condition

The or condition performs a logical OR operation on the results of an array of conditions. The condition matches when any of its child conditions match.

when:
  or:
    - <condition1>
    - <condition2>

For example:

when:
  or:
  - java.dependency:
      name: junit.junit
      upperbound: 4.12.2
      lowerbound: 4.4.0
  - java.referenced:
      location: IMPORT
      pattern: junit.junit

5.4. Chaining condition variables

You can use condition chaining, where the pattern of one condition becomes the template variable for filtering in another condition. Use condition chaining to scope down the search query to look for a pattern in a subset of files.

For example, you can search for one or more pom.xml files and find dependencies in those subset of pom files and not any other file in your project. You can use logical and and or for chaining conditions.

when:
 or:
  - builtin.xml:
      xpath: "//dependencies/dependency"
      filepaths: "{{poms.filepaths}}"
    from: poms
  - builtin.file:
      pattern: pom.xml
    as: poms
    ignore: true

In the earlier example, MTA saves the output of the builtin.file condition in poms:

[...]
      as: poms
[...]

You can use the variables of builtin.file in the builtin.xml condition, by writing from and then using Mustache templates in the provider_ condition block.

This is how the condition knows how to use the variable set to the name poms.

[...]
    from: poms
[...]

Then you can use the variables by setting them as Mustache templates in any of the inputs to the provider condition.

[...]
      filepaths: "{{poms.filepaths}}"
[...]
Note

If you only want to use the values of a condition as a chain, you can set ignore: true.

This will tell the engine not to use this condition to find a rule violation:

[...]
    ignore: true
[...]

Additional resources

5.5. Chaining in the Java provider

When you use the filepaths variable in a Java rule chained condition, the rule writer must capitalize the variable.

For example:

  when:
    and:
      - java.referenced:
          pattern: org.springframework.web.bind.annotation.RequestMapping
          location: ANNOTATION
        as: annotation
      - java.referenced:
          pattern: org.springframework.stereotype.Controller
          location: ANNOTATION
          filepaths: "{{annotation.Filepaths}}"

5.6. Nested conditions

As an Architect, you can create nested conditions in a rule to make the analyzer evaluate different levels of conditions. You can combine the logical and and or conditions in a nested condition.

when:
  and:
  - and:
    - go.referenced: "*CustomResourceDefinition*"
    - java.referenced:
        pattern: "*CustomResourceDefinition*"
  - go.referenced: "*CustomResourceDefinition*"

5.7. Custom variables

You can create custom variables in provider conditions. You can use custom variables to capture relevant information from a line in the source code that violates the rule. MTA interpolates the values of these variables with the piece of data in the source code. You can add variables to a rule in the customVariables field.

You can use the custom variable values to generate detailed template messages in a rule’s action (see Message actions).

- ruleID: lang-ref-004
   customVariables:
   - pattern: '([A-z]+)\.get\(\)'
      name: VariableName
    message: "Found generic call - {{ VariableName }}"
  when:
      java.referenced:
          location: METHOD_CALL
          pattern: com.example.apps.GenericClass.get

where:

pattern
A regular expression pattern that MTA uses to find a match on the source code line.
name
The name of the variable that can be used in templates.
message
A template for a message by using a custom variable.

Additional resources

Chapter 6. Rule actions

You can use rule actions to generate information about the source code. The rule action information can be included in a violation or used to categorize the source code.

Rules can include the following types of actions:

  • Message: use message action to display an informative message in the static report that contains the violation triggered by the rule.
  • Tag: use tags to categorize parts of the source code. For example, Backend=Java, where Backend is the key and Java is the value.

Each rule includes either one action tag or both.

6.1. Tag actions

A tag action instructs the analyzer to generate one or more tags for the application when it finds a match. Each string in the tag field can be a comma-separated list of tags. Optionally, you can assign categories to tags.

tag:
  - "<tag1>,<tag2>,<tag3>"
  - "Category=<tag4>,<tag5>"

Example

- ruleID: test-rule
  when:
    <CONDITION>
  tag:
  - Language=Golang
  - Env=production
  - Source Code

A tag can be a string or a key=val pair, where MTA treats the key as a tag category. You can consider any rule that has a tag action as a “tagging rule” in this document.

Note

Issues are not created for rules that contain only tag actions.

6.2. Message action

migration toolkit for applications (MTA) uses a message action to generate an issue with the specified message when a rule condition matches the source code.

- ruleID: test-rule
  message: Test rule matched. Please resolve this migration issue.
  when:
    <CONDITION>

Optionally, a message can include hyperlinks to external URLs that provide relevant information about the issue or a quick fix.

links:
  - url: "konveyor.io"
    title: "Short title for the link"

You can also create a template message to include information about the match by using custom variables in the rule.

- ruleID: lang-ref-004
   customVariables:
   - pattern: '([A-z]+)\.get\(\)'
      name: VariableName
    message: "Found generic call - {{ VariableName }}"
  when:
    <CONDITION>

Additional resources

Chapter 7. Creating custom rules

To analyze applications in Python, Node.js, Go, and C#, the Architect must create a custom rule. A custom rule includes conditions and patterns that describe an issue. You must resolve issues when refactoring applications before migrating them to a target platform.

7.1. Creating a YAML rule

You can create a YAML-based rule to discover instances where an application defines a jboss-web.xml file containing a <class-loading> element and to provide a link to the documentation that describes how to migrate the code.

Prerequisites

  • You installed MTA. See Installing and running the CLI.

Procedure

  1. Create a YAML file for the rule. In the following example, the rule is available in the $HOME directory.

    $ mkdir /home/<USER>/rule.yaml
  2. Create a data directory:

    mkdir /home/<USER>/data/
  3. Create a jboss-web.xml file in the data directory:

    touch /home/<USER>/data/jboss-web.xml
  4. Create a pom.xml file in the data directory:

    touch /home/<USER>/data/pom.xml
  5. In the jboss-web.xml file you created, paste 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>
  6. In the pom.xml file you created, paste the following content:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
      <groupId>test</groupId>
      <artifactId>test</artifactId>
      <version>1.1.0-SNAPSHOT</version>
    
      <properties>
    	<maven.compiler.source>1.7</maven.compiler.source>
    	<maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
      </dependencies>
    </project>
  7. In the rule.yaml file you created, paste the following contents:

    - ruleID: jboss5-web-class-loading
      description: Find class loading element in JBoss XML file.
      when:
        builtin.xml:
          xpath: /jboss-web/class-loading
      message: The class-loading element is no longer valid in the jboss-web.xml file.
      effort: 3
      links:
      - url: 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

    where:

    ruleID
    Unique ID for your rule. For example, jboss5-web-class-loading.
    description
    Text description of the rule.
    when

    Complete the when block specifying one or more conditions:

    1. Use the builtin provider’s XML capability because this rule checks for a match in an XML file.

      when:
        builtin.xml:
          xpath: /jboss-web/class-loading
    message

    Helpful message explaining the migration issue. MTA includes the message in the report when the rule matches. For example:

    message: The class-loading element is no longer valid in the jboss-web.xml file.
    labels
    List of string labels for the rule.
    effort
    Number of expected story points to resolve this issue.
    links

    One or more hyperlinks pointing to documentation around the migration issues that you find.

      links:
        - url: 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

    The rule is now complete.

Verification

To verify that the rule works:

  1. Point the CLI to the rule file you created:

    –rules /home/<USER>/rules.yaml
  2. Pass the rule by using the rules option in MTA CLI:

    mta-cli analyze --input /home/<USER>/data/ --output /home/<USER>/output/ --rules /home/<USER>/rules.yaml
  3. Open /home/<USER_NAME>/output/static-report/index.html in a web browser.

    INFO[0066] Static report created. Access it at this URL:  URL="file:/home/<USER>/output/static-report/index.html"
  4. Navigate to the Issues tab in the left menu.
  5. In the Issues table, type JBoss XML in the search bar.
  6. Verify that the issue with the title Find class loading element in JBoss XML file is present in the table.
  7. Click the jboss-web.xml link to open the affected file.

Additional resources

7.2. Creating a custom Go rule

You can create custom rules for Golang (Go) applications based on the following example.

You can use the following custom rule to check if MTA triggers an incident when it detects the v1beta1.CustomResourceDefinition pattern in the go file.

Procedure

  1. Create a go-rule-001.yml file in a directory.
  2. Copy the following rule in the yaml file:

    - message: golang apiextensions/v1/customresourcedefinitions found
      description: "golang apiextensions/v1/customresourcedefinitions found"
      ruleID: go-lang-ref-001
      effort: 1
      when:
        go.referenced:
          pattern: "v1beta1.CustomResourceDefinition"
  3. Create a test go file named example.go in your Home directory.
  4. Paste the following code in the example.go file:

    package main
    
    import (
    	"fmt"
    
    	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    )
    
    func main() {
    	fmt.Println(v1beta1.CustomResourceDefinition{})
    
    }
  5. Run the following command in the MTA CLI:

    $ ./mta-cli analyze -i _<path-to-Go-project>_ \
    -o _<path-to-report-directory>_ --run-local=false --rules \
    _<path-to-go-rule-001.yml>_
    Note

    Add the --overwrite option if you want to use the same directory for the report when you run more tests. MTA overwrites the current report with the result of the latest analysis that you run.

Verification

  1. Open the static report at /home/<USER>/output/static-report/ in your browser.
  2. Navigate to the issues to verify the golang apiextensions/v1/customresourcedefinitions found issue.

7.3. Creating a custom Node.js rule

You must create custom rules to analyze Node.js applications by using MTA. A Node.js rule contains the nodejs.referenced capability that supports the pattern field.

The following example uses a custom rule to check if a .tsx file in the Node.js project imports the React framework.

Procedure

  1. Create the test-nodejs directory.

    $ mkdir -p ~/test-nodejs
  2. Save the following rule as nodejs-rule-001.yml in the test-nodejs directory:

    - ruleID: test-tsx-support-00000
      description: Found React import in .tsx file
      message: Found React import in .tsx file
      effort: 1
      when:
        nodejs.referenced:
         pattern: "React"
  3. Create the following test application in the Component.tsx file:

    import React from 'react';
     export const MyComponent: React.FC = () => <div>Hello</div>;
  4. Run the following command in the MTA CLI:

    $ ./mta-cli analyze -i ~/test-nodejs/ -o \
    ~/test-nodejs/report --run-local=false \
    --rules ~/test-nodejs/nodejs-rule-001.yml
    Note

    Add the --overwrite option if you want to use the same directory for the report when you run more tests. MTA overwrites the current report with the result of the latest analysis that you run.

Verification

  1. Open the static report at ~/test-nodejs/report/static-report/index.html in your browser.
  2. Click the <application_name> to open the Dashboard.
  3. Review the incidents in the Issues tab.

7.4. Creating custom Python rules

You must create custom rules to analyze Python applications by using MTA. A Python rule contains the python.referenced capability with the supported fields.

The following example uses two custom rules:

  • The first rule checks if bad_method is present.
  • The second rule checks if hello_world is present in file_a.py in your project.

Procedure

  1. Create the directory test-python.

    $ mkdir -p ~/test-python
  2. Create a python-rule-001.yml file in the directory and add the following rule:

    - category: mandatory
      ruleID: python-rule-001
      effort: 1
      description: "Bad method"
      when:
        python.referenced:
          pattern: "bad_method"
  3. Create a python-rule-002.yml file in the directory and add the following rule:

      - category: mandatory
        ruleID: python-rule-002
        effort: 1
        message: "Found a python"
        when:
          python.referenced:
            pattern: "hello_world"
  4. Save the following Python code as file_b.py.

    import deprecated
    def hello_world():
              return "Hello, world!"
    @deprecated.deprecated("This method is bad!")
    def bad_method():
             return "I'm a bad method!"
  5. Save the following code as a second file, file_a.py.

    import file_b
    print(file_b.hello_world())
    print(file_b.bad_method())
  6. Run the following command in the MTA CLI:

    $ ./mta-cli analyze -i ~/test-python/ -o \
    ~/test-python/report --run-local=false \
    --rules ~/test-python/python-rule-001. \
    --rules ~/test-python/python-rule-002.yml
    Note

    Add the --overwrite option if you want to use the same directory for the report when you run more tests. MTA overwrites the current report with the result of the latest analysis that you run.

  7. Open the static report at ~/test-python/report/static-report/index.html in your browser.
  8. Click the <application_name> to open the Dashboard.
  9. Review the incidents in the Issues tab.

7.5. Creating a custom C# rule

You can create custom rules to analyze C# applications by using the MTA CLI, user interface, or IDE extension. The following example shows how to run a CLI analysis for a C# application.

You can use a custom rule to check if MTA triggers an incident when it detects the WebMatrix.WebData.WebSecurity class in a C# example project.

Prerequisites

  • You installed the ilspycmd and paket dependencies.
  • You installed the dotnet tools and exported the dotnet tools path by using the export PATH="$PATH:<path_to_.dotnet_tools>" command.

Procedure

  1. Create a csharp-rule.yaml file in your Home directory.
  2. Copy the following rule in the csharp-rule.yaml file:

    - category: mandatory
      customVariables: []
      description: WebMatrix.WebData.WebSecurity is not available in .NET
      effort: 8
      labels:
      - konveyor.io/source=dotnet
      - konveyor.io/target=dotnet-core
      links:
      - title: Introduction to Identity on ASP.NET Core
        url: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity
      - title: Migrate Authentication and Identity to ASP.NET
        url: https://learn.microsoft.com/en-us/aspnet/core/migration/identity
      message: |
        WebMatrix.WebData.WebSecurity is not available in .NET and must be replaced with ASP.NET Core Identity.
    
        Migration actions:
        - Add Microsoft.AspNetCore.Identity.EntityFrameworkCore NuGet package
        - Create ApplicationUser class inheriting from IdentityUser
        - Update DbContext to inherit from IdentityDbContext<ApplicationUser>
        - Replace WebSecurity.Login with SignInManager.PasswordSignInAsync
        - Replace WebSecurity.Logout with SignInManager.SignOutAsync
        - Replace WebSecurity.CreateUserAndAccount with UserManager.CreateAsync
        - Replace WebSecurity.ChangePassword with UserManager.ChangePasswordAsync
        - Configure Identity in Startup.ConfigureServices with AddIdentity or AddDefaultIdentity
      ruleID: dotnet-core-websecurity-01
      when:
        csharp.referenced:
          location: ALL
          pattern: WebMatrix.WebData.WebSecurity
  3. Open a C# project that has the WebMatrix.WebData.WebSecurity class.
  4. Run an analysis with the following command in the MTA CLI:

    $ ./mta-cli analyze -i <path_to_C#_app> -o <path_to_report> --overwrite --run-local=false --enable-default-rulesets=false --mode source-only --rules ~/csharp-rule.yaml
    Note

    Add the --overwrite option if you want to use the same directory for the report when you run more tests. MTA overwrites the current report with the result of the latest analysis that you ran.

  5. Open the static report at <path_to_report> in your browser.
  6. Navigate to the issues to verify the WebMatrix.WebData.WebSecurity is not available in .NET issue.

Chapter 8. Rulesets

A set of rules forms a ruleset. MTA does not require every rule file to belong to a ruleset, but you can use rulesets to group multiple rules that achieve a common goal and to pass the rules to the rules engine.

8.1. Creating and using a custom ruleset

You can create a ruleset by placing one or more custom rules in a directory and creating a ruleset.yaml file at the directory root. All rules in this directory become a part of the ruleset.

You can include multiple rules in a ruleset as follows:

  • Place the rule files in a directory and add a ruleset.yaml file. MTA treats the directory as a ruleset, and you can pass the directory path as input to the --rules option.
  • Specify multiple rules files by using the --rules option when you run an analysis.

To use a custom ruleset in an analysis:

  1. Create a <custom_rule_directory> where you save the ruleset and rules files.
  2. Create a ruleset.yaml file in the <custom_rule_directory>:

    name: "Name of the ruleset"
    description: "Description of the ruleset"
    labels:
      - key=val

    where:

    name
    The name must be unique among the provided rulesets.
    labels
    A key-value pair that identifies the source or target technology. Rules that belong to the ruleset inherit the ruleset labels.
  3. Pass the ruleset directory as the input in the --rules option:

    $ mta-cli analyze --input=<application_to_analyze> --output=<output_dir> --rules=<custom_rule_directory> --enable-default-rulesets=false
    • Replace <application_to_analyze> with the name of your application.
    • Replace <output_dir> with the directory of your choice.
    • Replace <custom_rule_directory> with the path to the custom rule directory.

      Note that if you want to use the --target or --source option in the CLI, the analyzer will only select rules that match the label for that target. Therefore, you must add reserved labels in your rules.

Additional resources

Chapter 9. Additional resources

Legal Notice

Copyright © 2026 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.