Rules Development Guide
Create custom rules to enhance migration coverage.
Abstract
- Making open source more inclusive
- 1. Introduction
- 2. Creating YAML rules
- 2.1. YAML rule structure and syntax
- 2.2. Rule labels
- 2.3. Creating a basic YAML rule
- 2.3.1. Creating a basic YAML rule template
- 2.3.2. Rule categories
- 2.3.3. Rule actions
- 2.3.4. Rule conditions
- 2.3.5. Tag actions
- 2.3.6. Message action
- 2.3.7. Hyperlinks
- 2.3.8. Provider condition
- 2.3.9. Condition patterns
- 2.3.10. Custom variables
- 2.3.11. Logical conditions
- 2.3.12. Rulesets
- 2.3.13. Creating a basic YAML ruleset template
- 2.3.14. Creating a YAML rule
- 2.3.15. Running an analysis using a custom YAML rule
- 2.4. Creating your first YAML rule
- A. Reference material
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
1.1. About the Rule Development Guide
This guide is intended for software engineers who want to create custom YAML-based rules for Migration Toolkit for Applications (MTA) tools.
See the Introduction to the Migration Toolkit for Applications for an overview and the CLI Guide for details.
1.1.1. Use of <MTA_HOME>
in this guide
This guide uses the <MTA_HOME>
replaceable variable to denote the path to your MTA installation.
The mta-7.2.0-cli<OS>.zip* extracts a single binary called mta-cli
.
When you encounter <MTA_HOME>
in this guide, replace it with the actual path to your MTA installation.
1.2. The MTA rules
The Migration Toolkit for Applications (MTA) contains rule-based migration tools (analyzers) that you can use to analyze the application user interfaces (APIs), technologies, and architectures used by the applications you plan to migrate. MTA analyzer rules use the following rule pattern:
when(condition) message(message) tag(tags)
You can use the MTA rules internally to perform the following tasks:
- Extract files from archives.
- Decompile files.
- Scan and classify file types.
- Analyze XML and other file content.
- Analyze the application code.
- Build the reports.
MTA builds a data model based on the rule execution results and stores component data and relationships in a graph database. This database can then be queried and updated as required by the migration rules and for reporting purposes.
You can create your own custom analyzer rules. You can use custom rules to identify the use of custom libraries or other components that might not be covered by the provided standard migration rules.
Chapter 2. Creating YAML rules
Each analyzer rule is a set of instructions that are used to analyze source code and detect issues that are problematic for migration.
The analyzer parses user-provided rules, applies them to applications' source code, and generates issues for matched rules.
A collection of one or more rules forms a ruleset. Creating rulesets provides a way of organizing multiple rules that achieve a common goal.
The analyzer CLI takes rulesets as input arguments.
2.1. YAML rule structure and syntax
Rules are written in YAML. They consist of:
- metadata
- conditions
- actions
Rules instruct the analyzer to take specified actions when given conditions match.
A YAML rule file in MTA contains one or more YAML rules.
2.1.1. Rule metadata
Rule metadata contains general information about the rule. The structure of metadata is as follows:
ruleID: "unique_id" 1 labels: 2 # 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 3 category: mandatory 4
- 1
- ruleID: This is a unique ID for the rule. It must be unique within the ruleset.
- 2
- labels: A list of string labels associated with the rule. (See Labels)
- 3
- effort: Effort is an integer value that indicates the level of effort needed to resolve this issue.
- 4
- category: Category describes severity of the issue for migration. Values can be one of
mandatory
,potential
oroptional
. For more deails, see Rule categories.
2.2. Rule labels
Labels are key=val
pairs specified for rules or rulesets as well as 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
Labels are specified 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="
The value of a label can be omitted. In that case, it is treated as an empty value:
labels: - "konveyor.io/key"
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.
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 valueeap6
:--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"
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:
konveyor-analyzer … --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:
konveyor-analyzer … --dep-label-selector !konveyor.io/exclude
2.3. Creating a basic YAML rule
This section describes how to create a basic MTA YAML rule. This assumes that you already have MTA installed. See the MTA CLI Guide for installation instructions.
2.3.1. Creating a basic YAML rule template
MTA YAML-based rules have the following basic structure:
when(condition) message(message) tag(tags)
Procedure
In the
/home/<USER>/
directory, create a file containing the basic syntax for YAML rules as follows:- category: mandatory description: | <DESCRIPTION TITLE> <DESCRIPTION TEXT> effort: <EFFORT> labels: - konveyor.io/source=<SOURCE_TECH> - konveyor.io/target=<TARGET_TECH> links: - url: <HYPERLINK> title: <HYPERLINK_TITLE> message: <MESSAGE> tag: - <TAG1> - <TAG2> ruleID: <RULE_ID> when: <CONDITIONS>
2.3.2. Rule categories
-
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, it is recommended to include it on the schedule soon after your migration is completed. -
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.
2.3.3. Rule actions
Rules can include the following types of actions:
- message
- tag
Each rule includes either one of them or both of them.
Message actions
When a message action matches the rule, it creates an issue. The custom data that providers export can be used in the message.
- ruleID: test-rule when: <CONDITION> message: Test rule matched. Please resolve this migration issue.
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"
A message can also be a template to include information about the match interpolated through custom variables on the rule.
2.3.4. Rule conditions
Each rule has a when
block, which specifies a condition that needs to be met for MTA to perform a certain action.
The when
block contains one condition, but that condition can have multiple conditions nested under it.
when: <condition> <nested-condition>
MTA supports the following types of conditions:
-
provider
-
and
-
or
2.3.5. Tag actions
A tag action instructs the analyzer to generate one or more tags for the application when a match is found. 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 the key is treated as a tag category in MTA. Any rule that has a tag action is referred to as a “tagging rule” in this document.
Issues are not created for rules that contain only tag actions.
2.3.6. Message action
A message action is employed to generate an issue with the specified message when a rule matches, for example:
# When a match is found, the analyzer generates incidents with the same message. message: "helpful message about the violation"
You can also create a template message to include information about the match that has been interpolated through custom variables on the rule.
- ruleID: lang-ref-004 customVariables: - pattern: '([A-z]+)\.get\(\)' name: VariableName message: "Found generic call - {{ VariableName }}" when: <CONDITION>
2.3.7. Hyperlinks
Hyperlinks can be provided along with a message
or tag
action to provide relevant information about the issue, which has been discovered:
# links point to external hyperlinks # rule authors are expected to provide # relevant hyperlinks for quick fixes, docs and so on. links: - url: "konveyor.io" title: "short title for the link"
2.3.8. Provider condition
The analyzer engine enables multi-language source code analysis by using providers. The source code of a technology is analyzed by the provider.
The provider publishes what they can do with the source code in terms of capabilities.
The provider condition instructs the analyzer to use a specific provider and one of its capabilities. In general, it follows the <provider_name>.<capability>
pattern.
when: <provider_name>.<capability> <input_fields>
The analyzer currently supports the following provider
conditions:
-
builtin
-
java
-
go
-
dotnet
Support for providing a single report when analyzing multiple applications on the CLI is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
Provider rule conditions | Provider name |
---|---|
Providers that are fully supported and included in the product |
Java |
Providers that have rules already defined in the product |
.NET |
Providers that require custom rulesets for analysis |
|
Depending on the provider, the fields of the condition, for example, the pattern and location in the previous example changes.
Some providers have dependency_ capability. The dependency_capability means that the provider generates 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.
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
The Analyzer currently supports the following providers:
-
builtin
-
java
-
go
-
generic
The following table summarizes all the providers and their capabilities:
Table 2.1. Summary of providers and their capabilities
Provider Name | Capabilities | Description |
---|---|---|
|
referenced |
Find references of a pattern with an optional code location for detailed searches. |
dependency |
Check whether the application has a given dependency. | |
|
xml |
Search XML files using xpath queries. |
|
Search JSON files using | |
filecontent |
Search content in regular files using regular expression patterns. | |
file |
Find files with names matching a given pattern. | |
hasTags |
Check whether a tag is created for the application using a tagging rule. | |
|
referenced |
Find references to a pattern. |
dependency |
Check whether the application has a given dependency. |
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.
Example
To create a java
provider condition that uses the referenced
capability:
when: java.referenced: <fields>
Depending on the provider and the capability, there will be different <fields>
in the condition.
The following table summarizes available providers, their capabilities and all of their fields:
Table 2.2. Summary of providers, their capabilities, and their fields
Provider | Capability | Fields | Required | Description |
---|---|---|---|---|
java |
referenced |
pattern |
Yes |
Regex pattern |
location |
No |
Source code location (see Java locations) | ||
annotated |
No |
Additional query to inspect annotations (see Annotation inspection). | ||
dependency |
name |
Yes |
Name of the dependency. | |
nameregex |
No |
Regex pattern to match the name. | ||
upperbound |
No |
Match versions lower than or equal to | ||
lowerbound |
No |
Match versions greater than or equal to | ||
builtin |
xml |
xpath |
Yes |
Xpath query |
namespaces |
No |
A map to scope down query to namespaces | ||
filepaths |
No |
Optional list of files to scope down search | ||
json |
xpath |
Yes |
Xpath query | |
filepaths |
No |
Optional list of files to scope down search | ||
filecontent |
pattern |
Yes |
Regex pattern to match in content | |
filePattern |
No |
Only search in files with names matching this pattern | ||
file hasTags |
pattern |
Yes |
Find files with names matching this pattern | |
hasTags |
This is an inline list of string tags. See Tag action | |||
go |
referenced |
pattern |
Yes |
Regex pattern. |
dependency |
name |
Yes |
Name of the dependency. | |
nameregex |
No |
Regex pattern to match the name. | ||
upperbound |
No |
Match versions lower than or equal to. | ||
lowerbound |
No |
Match versions greater than or equal to. |
Example
For example, to complete the previous java
condition example we created earlier, search for references of a package:
when: java.referenced: location: PACKAGE pattern: org.jboss*
2.3.8.1. Builtin provider
The builtin
is an internal provider that can analyze various files and internal metadata generated by the engine. This provider has the following capabilities:
-
file
-
filecontent
-
xml
-
json
-
hasTags
file
By using the file
capability, the provider searches for files in the source code that match a given pattern.
when: builtin.file: pattern: "<regex_to_match_filenames>"
filecontent
By using the filecontent
capability, the provider searches for content that matches a given pattern.
when: builtin.filecontent: filePattern: "<regex_to_match_filenames_to_scope_search>" pattern: "<regex_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>" 1 filepaths: 2 - "/src/file1.xml" - "/src/file2.xml"
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>" 1
- 1
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: 1
- "tag1"
- "tag2"
- 1
- When more than one tag is given, a logical AND is implied.
2.3.8.2. Java provider
The java
provider analyzes Java source code.
This provider has the following capabilities:
-
referenced
-
dependency
referenced
By using the referenced
capability, the provider finds references in the source code. This capability takes three input parameters: pattern
, location
, and annotated
.
when: java.referenced: pattern: "<pattern>" 1 location: "<location>" 2 annotated: "<annotated>" 3
- 1
- A regular expression pattern to match.
- 2
- Specifies the exact location where the pattern needs to be matched, for example,
IMPORT
. - 3
- Checks for specific annotations and their elements, such as name and value, in the Java code 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"
2.3.8.3. Java locations
The java
provider allows scoping the search down to certain source code locations.
- IMPORT: IMPORT allows for searches on class imports. It can either be used with FQNs or an asterisk to allow for wider matches:
java.referenced: pattern: org.apache.lucene.search* location: IMPORT
would match on each of these imports:
import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField;
range of results, it is recommended to place it directly after the package, not after the dot:
- PACKAGE: the PACKAGE location matches on any usage of a package, be it in an import or used as part of a fully qualified name in the code:
java.referenced: pattern: org.apache.lucene.search* location: PACKAGE
would match on both the import and the fully qualified usage:
import org.apache.lucene.search.*;
public class Test { private org.apache.lucene.search.Query query; }
(*
) right after the package-separation dot (.
) for better results.
- CONSTRUCTOR_CALL and METHOD_CALL: for matching constructors and methods, respectively. The pattern possibilities are quite varied, and it is possible to match against specific return types, arguments, etc.
For instance, looking for a method named “method” declared on org.konveyor.MyClass
that returns a List
of a type that extends java.lang.String
and accepts a single parameter:
java.referenced: location: METHOD pattern: 'org.konveyor.Myclass.method(*) java.util.List<? extends java.lang.String>'
More information about the possibilities of these patterns can be found in the official Java documentaion, which contain all the information for building these patterns in the createPattern(String, int, int, int)
section.
Presently, fully qualified static method matching is prone to errors.
- TYPE: matches against types in general, appearing anywhere.
- INHERITANCE: matches against a class inheriting from a given type.
- ANNOTATION: matches against annotations.
- IMPLEMENTS_TYPE: matches against any type implementing the given type.
- ENUM_CONSTANT: matches against enum constants.
- RETURN_TYPE: matches against a type being returned by a method.
- VARIABLE_DECLARATION: matches against a type being declared as a variable.
- FIELD (declaration): matches against a type appearing in a field declaration. It can be coupled with an annotation match, this is, an annotation happening on the field (see Annotation inspection)
- METHOD: matches against a given method declaration. It can be coupled with an annotation match (see Annotation inspection).
- CLASS (declaration): matches against a given method declaration. Can be coupled with an annotation match (see Annotation inspection).
The supported locations are the following:
-
CONSTRUCTOR_CALL
-
TYPE
-
INHERITANCE
-
METHOD_CALL
-
ANNOTATION
-
IMPLEMENTS_TYPE
-
ENUM_CONSTANT
-
RETURN_TYPE
-
IMPORT
-
VARIABLE_DECLARATION
-
FIELD
-
METHOD
dependency
By using the dependency
capability, the provider finds dependencies for a given application. MTA generates a list of the application’s dependencies, and you can use this capability to query the list and check whether a certain dependency exists for the application within a given range of the dependency’s versions.
when: java.dependency: name: "<dependency_name>" 1 upperbound: "<version_string>" 2 lowerbound: "<version_string>" 3
2.3.8.4. Annotation inspection
You can add a query to match against specific annotations and their elements, for example:
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 regex 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 regex 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"
The only element specified with a pattern
is the annotation itself.
2.3.8.5. Go provider
The go
provider analyzes Go source code. This provider’s capabilities are referenced
and dependency
.
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 an application.
when: go.dependency: name: "<dependency_name>" 1 upperbound: "<version_string>" 2 lowerbound: "<version_string>" 3
2.3.8.6. Dotnet provider
The dotnet
provider is an external provider used to analyze .NET and C# source code. Currently, the provider supports the referenced
capability.
referenced
By using the referenced
capability, the provider finds references in the source code.
when: dotnet.referenced: pattern: "<pattern>" 1 namespace: "<namespace>" 2
2.3.9. Condition patterns
The Language Server used by the Java provider is Eclipse’s JDTLS. Internally, the JDTLS uses the Eclipse Java Development Toolkit, which includes utilities for searching code in projects.
In the pattern
element of a java.referenced
condition, you can search through application code by using these utilities. For more details, see Class SearchPattern, which contains all the information for building these patterns for createPattern(String, int, int, int)
.
Examples
Search for any class under the
javax.xml
package, occurring in any location:java.referenced: pattern: javax.xml*
WarningWhen matching against packages, as in the previous example, the asterisk must not be after a dot. For example: *
pattern: javax.xml*
and not: *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 aList
of a type that extendsjava.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
2.3.10. Custom variables
Provider conditions can have associated custom variables. You can use custom variables to capture relevant information from the matched line in the source code. The values of these variables are interpolated with data matched in the source code. These values can be used to generate detailed template messages in a rule’s action (see Message actions). They can be added to a rule in the customVariables
field:
- ruleID: lang-ref-004 customVariables: - pattern: '([A-z]+)\.get\(\)' 1 name: VariableName 2 message: "Found generic call - {{ VariableName }}" 3 when: java.referenced: location: METHOD_CALL pattern: com.example.apps.GenericClass.get
2.3.11. Logical conditions
The analyzer provides two basic logical conditions, and
and or
, which you can use to aggregate results of other conditions and create more complex queries.
2.3.11.1. AND condition
The and
condition performs a logical AND operation on the results of an array of conditions.
The and
condition matches when all of its child conditions match, for example:
when: and: - <condition1> - <condition2>
Example
when: and: - java.dependency: name: junit.junit upperbound: 4.12.2 lowerbound: 4.4.0 - java.referenced: location: IMPORT pattern: junit.junit
2.3.11.1.1. Nested conditions
Conditions can also be nested within other conditions.
- Example
when: and: - and: - go.referenced: "*CustomResourceDefinition*" - java.referenced: pattern: "*CustomResourceDefinition*" - go.referenced: "*CustomResourceDefinition*"
2.3.11.2. OR condition
The or
condition performs a logical OR operation on the results of an array of conditions.
The or
condition matches when any of its child conditions matches, for example:
when: or: - <condition1> - <condition2>
Example
when: or: - java.dependency: name: junit.junit upperbound: 4.12.2 lowerbound: 4.4.0 - java.referenced: location: IMPORT pattern: junit.junit
2.3.11.3. Chaining Condition Variables
You can use the output of one condition as the input for filtering another one in the and
and or
conditions. This is called condition chaining.
Example
when: or: - builtin.xml: xpath: "//dependencies/dependency" filepaths: "{{poms.filepaths}}" from: poms - builtin.file: pattern: pom.xml as: poms ignore: true
In the above example, the output of the builtin.file
condition is saved as poms
:
+
[...] as: poms [...]
The variables of builtin.file
can then be used in the builtin.xml
condition, by writing from
and then using mustache templates in the provider_ condition
block.
This is how this particular condition knows how to use the variable set to the name poms
.
+
[...] from: poms [...]
Then you can use the variables by setting them as mustached templates in any of the inputs to the provider condition.
+
[...] filepaths: "{{poms.filepaths}}" [...]
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 determine whether the rule has been violated or not:
+
[...] ignore: true [...]
2.3.11.3.1. Chaining in the Java provider
In the java
provider, the filepaths
variable must be uppercased. 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}}"
2.3.12. 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.
You can create a ruleset by placing one or more YAML rules in a directory and creating a ruleset.yaml
file at the directory root. When you pass this directory as input to the MTA CLI by using the --rules
option, all rules in this directory are treated as a part of the ruleset defined by the ruleset.yaml
file.
The ruleset.yaml
file stores the metadata of the ruleset.
name: "Name of the ruleset" 1 description: "Description of the ruleset" labels: # 2 - key=val
To perform any application analysis, enter:
$ mta-cli analyze --input=<application_to_analyze> --output=<output_dir> --rules=<custom_rule_dir> --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_dir>
with the custom rulesets file.
On initiation, the mta-cli tool determines the type of application and the provider needed for analysis. It then starts the provider in a container that has the required dependencies and tools. Finally, the provider uses the analyzer to execute a series of rulesets to analyze the source code.
2.3.13. Creating a basic YAML ruleset template
If you want to group multiple similar rules, you can create a ruleset for them by placing their files in a directory and creating a ruleset.yaml
file at the directory’s root. When you pass this directory as input to the MTA CLI using the --rules
option, MTA treats all the files in the directory as belonging to the ruleset defined in the ruleset.yaml
file.
Procedure
Create a template for
ruleset.yaml
files if you want to pass the entire directory using the--rules
option:name: <RULESET_NAME> 1 description: <RULESET_DESCRIPTION> labels: 2 - key=val
2.3.14. Creating a YAML rule
Each rule file contains one or more YAML rules. Every rule comprises metadata, conditions and actions.
Procedure
Create a
when
condition.The
when
condition of a YAML rule can beprovider
,and
oror
.Create a
provider
conditionThe provider condition is used to define a search query for a specific language provider and to invoke a certain capability of the provider.
The condition’s general format is
<provider_name>.<capability>
. The condition also has inner fields to specify details of the search. The way you create aprovider
condition and its inner fields depends on which provider you use and which capability you invoke.The table below lists the available providers and their capabilities. Select a provider and its capability that suit the purpose of the rule you want to create. This part of the condition does not contain any of the condition’s fields yet.
Provider Capability Description java
referenced
Finds references of a pattern, including annotations, with an optional code location for detailed searches
dependency
Checks whether the application has a given dependency
builtin
xml
Searches XML files using XPath queries
json
Searches JSON files using JSONPath queries
filecontent
Searches content in regular files using RegEx patterns
file
Finds files with names matching a given pattern
hasTags
Checks whether a tag is created for the application through a tagging rule
go
referenced
Finds references of a pattern
dependency
Checks whether the application has a given dependency
The example below shows a
java
provider condition that uses thereferenced
capability.Example
when: java.referenced:
Add suitable fields to the
provider
condition.The table below lists all available providers, their capabilities, and their fields. Select the fields that belong to the provider and capability that you have chosen. Note that some fields are mandatory.
Provider Capability Field Required? Description java
referenced
pattern
Yes
RegEx pattern
location
No
Source code location; see below for a list of all supported search locations
annotated
No
Annotations and their elements (name and value)
dependency
name
Yes
Name of the dependency
nameregex
No
RegEx pattern to match the name
upperbound
No
Matches version numbers lower than or equal to
lowerbound
No
Matches version numbers greater than or equal to
builtin
xml
xpath
Yes
XPath query
namespaces
No
A map to scope down query to namespaces
filepaths
No
Optional list of files to scope down search
json
xpath
Yes
XPath query
filepaths
No
Optional list of files to scope down search
filecontent
pattern
Yes
RegEx pattern to match in content
filePattern
No
Only searches in files with names matching this pattern
file
pattern
Yes
Finds files with names matching this pattern
hasTags
This is an inline list of string tags. See Tag Actions in Rule Actions for details on tag format.
go
referenced
pattern
Yes
RegEx pattern
dependency
name
Yes
Name of the dependency
nameregex
No
RegEx pattern to match the name
upperbound
No
Matches version numbers lower than or equal to
lowerbound
No
Matches version numbers greater than or equal to
The following search locations can be used to scope down
java
searches:- CONSTRUCTOR_CALL
- TYPE
- INHERITANCE
- METHOD_CALL
- ANNOTATION
- IMPLEMENTS_TYPE
- ENUM_CONSTANT
- RETURN_TYPE
- IMPORT
VARIABLE_DECLARATION
The example below shows the
when
condition of a rule that searches for references of a package.Example
when: java.referenced: location: PACKAGE pattern: org.jboss*
Create an
AND
orOR
conditionAn
and
condition matches when all of its child conditions match. Create anand
condition as follows:when: and: - java.dependency: name: junit.junit upperbound: 4.12.2 lowerbound: 4.4.0 - java.referenced: location: IMPORT pattern: junit.junit
An
or
condition matches when any of its child conditions match. Create anor
condition as follows:when: or: - java.dependency: name: junit.junit upperbound: 4.12.2 lowerbound: 4.4.0 - java.referenced: location: IMPORT pattern: junit.junit
2.3.15. Running an analysis using a custom YAML rule
To run an analysis, use the --rules
option in the CLI.
Procedure
To use the rules in a single rule file,
/home/<USER>/rule.yaml
, run the following command:mta-cli analyze --input /home/<USER>/data/ --output /home/<USER>/output/ --rules /home/<USER>/rule.yaml
where:
-
/home/<USER>/data/
- the directory of the source code or binary -
/home/<USER>/output/
- the directory for reports (HTML and YAML)
-
-
To use multiple rule files, you need to place them in a directory and to add a
ruleset.yaml
file. Then the directory is treated as a ruleset, and you can pass it as input to the--rules
option.
Note that if you wish to use the --target
or --source
option in the CLI, the engine will only select rules that match the label for that target. Therefore, make sure that you have added target or source labels on your rules. See Reserved labels for more details.
2.4. Creating your first YAML rule
This section guides you through the process of creating and testing your first MTA YAML-based rule. This assumes that you have already installed MTA. See Installing and running the CLI in the CLI Guide for installation instructions.
In this example, you will create a 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.
2.4.1. Creating a YAML file for the rule
- Create a YAML file for your first rule.
$ mkdir /home/<USER>/rule.yaml
2.4.2. Creating data to test the rule
Create
jboss-web.xml
andpom.xml
files in a directory:mkdir /home/<USER>/data/ touch /home/<USER>/data/jboss-web.xml touch /home/<USER>/data/pom.xml
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>
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>
2.4.3. Creating the rule
MTA YAML-based rules use the following rule pattern:
when(condition) perform(action)
Procedure
In the
rule.yaml
file you created, paste the following contents:- ruleID: <UNIQUE_RULE_ID> 1 description: <DESCRIPTION> 2 when: <CONDITION(S)> 3 message: <MESSAGE> 4 labels: <LABELS> 5 effort: <EFFORT> 6 links: - <LINKS> 7
- 1
- Unique ID for your rule. For example,
jboss5-web-class-loading
. - 2
- Text description of the rule.
- 3
- Complete the
when
block specifying one or more conditions:-
Use the
builtin
provider’s XML capability because this rule checks for a match in an XML file. To match on the
class-loading
element that is a child ofjboss-web
, use the XPath expressionjboss-web/web-loading
as an XML query. In this case, you need just one condition:when: builtin.xml: xpath: jboss-web/class-loading
-
Use the
- 4
- Helpful message explaining the migration issue. The message is generated in the report when the rule matches. For example:
message: The class-loading element is no longer valid in the jboss-web.xml file.
- 5
- List of string labels for the rule.
- 6
- Number of expected story points to fix this issue.
- 7
- 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 and looks similar to the following:
- 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
2.4.4. Installing the rule
Procedure
Point the CLI to the rule file you created :
–rules /home/<USER>/rules.yaml
2.4.5. Testing the rule
Procedure
To test the rule, point the input to the test data you created and pass the rule using the rules option in MTA CLI:
mta-cli analyze --input /home/<USER>/data/ --output /home/<USER>/output/ --rules /home/<USER>/rules.yaml
2.4.6. Reviewing the report
Review the report to be sure that it provides the expected results.
Procedure
Once the analysis is complete, the command outputs the path to the HTML report:
INFO[0066] Static report created. Access it at this URL: URL="file:/home/<USER>/output/static-report/index.html"
Open
/home/<USER_NAME>/output/static-report/index.html
in a web browser.- Navigate to the Issues tab in the left menu.
Verify that the rule is executed:
-
In the Issues table, type
JBoss XML
in the search bar. -
Verify that the issue with the title
Find class loading element in JBoss XML file
is present in the table.
-
In the Issues table, type
- Click the jboss-web.xml link to open the affected file.
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 Migration Toolkit for Applications 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 MTA 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.
- 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.
A.2. Additional resources
A.2.1. Additional resources
- MTA Jira issue tracker: https://issues.redhat.com/projects/MTA/issues
- MTA mailing list: windup-eng@redhat.com
Revised on 2025-03-05 15:35:29 UTC