Skip to content

DecisionsDev/odm-runtime-properties-sample

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Very Simple Car Rental - Sample Project

License

Table of Contents


Features

This sample demonstrates how to:

  • Access ruleset and RuleApp properties at runtime via BOM B2X code that retrieves properties from the RunContext metadata

  • Use two access patterns for properties:

    • Static attributes for built-in properties (e.g., decisionId, rulesetPath) - predefined names prevent errors
    • Static methods with key parameter for custom properties (e.g., property(key), propertyNumber(key)) - flexible for custom user-defined property names
  • Implement type-specific property methods (propertyNumber, propertyBoolean, propertyDate, propertyCollection) that convert string values in B2X, enabling appropriate navigation phrases in rules (e.g., numeric comparisons, date operations)

  • Use properties across all rule artifacts:

    • Business Action Language (BAL) rules - Use properties in conditions and actions
    • Decision tables - Reference properties in conditions
    • Functions - Validate and process property values
    • Ruleflow transitions - Control flow based on property values
  • Configure business logic dynamically using property values at runtime without modifying rules

  • Handle property precedence when ruleset properties override RuleApp properties


Requirements


How to Use This Sample

1. Import and Review the Decision Service Project

Import the VerySimpleCarRental decision service project into Rule Designer.

Then review the implementation to understand how runtime properties are accessed and used:

  • Examine the B2X code in the access-properties BOM to see how properties are retrieved
  • Review how custom properties are used in rule artifacts:
    • rules/init/ for BAL rules and decision tables
    • rules/validateInitSetting.fct for the rule function
    • the initial action of the init rule task in the ruleflow

2. Deploy the RuleApp

Deploy VerySimpleCarRental from Rule Designer to Rule Execution Server with the default RuleApp properties defined in the deployment configuration.

3. Execute the Decision Service

Execute the ruleset using the Rule Execution Server (RES) HTDS endpoint.

Sample Request (JSON)

{
   "dropOffLocation": "FRANCE",
   "customerAge": 23,
   "pickUpDate": "2028-04-29T23:34:59+01:00",
   "customerDrivingLicense": "EU",
   "dropOffDate": "2028-05-06T16:07:04+01:00",
   "pickUpLocation": "FRANCE",
   "customerPaymentMethod": "VOUCHER"
}

Sample Request (XML)

<par:Request xmlns:par="http://www.ibm.com/rules/decisionservice/VerySimpleCarRental/Simple_carrental/param">
  <par:customerAge>23</par:customerAge>
  <par:customerDrivingLicense>EU</par:customerDrivingLicense>
  <par:customerPaymentMethod>VOUCHER</par:customerPaymentMethod>
  <par:dropOffDate>2026-06-06T04:05:17</par:dropOffDate>
  <par:dropOffLocation>FRANCE</par:dropOffLocation>
  <par:pickUpDate>2026-06-04T20:21:01</par:pickUpDate>
  <par:pickUpLocation>FRANCE</par:pickUpLocation>
</par:Request>

Expected Response (XML)

<?xml version="1.0" encoding="UTF-8"?><par:Response xmlns:par="http://www.ibm.com/rules/decisionservice/VerySimpleCarRental/Simple_carrental/param">
  <par:DecisionID>4867d679-f230-445a-a58c-a3d873fc7feb</par:DecisionID>
  <par:decisionLog>
Executing /VerySimpleCarRental/1.0/simple_carrental/1.0 - decisionId: 4867d679-f230-445a-a58c-a3d873fc7feb
Approved :FRANCE pick up location is in the operating countries
Approved :FRANCE drop off location is in the operating countries
Approved: pick-up date and drop-off date are available 
Information: deposit is not required
Approved: customer's age is at least 21
Approved: customer's driver license is valid
Approved: customer's payment method is valid 
Approved: rental duration is at most 30 days
 ###### TRANSACTION SUCCEEDED ######</par:decisionLog>
</par:Response>

The decisionLog output shows:

  • The ruleset path and decision ID
  • Validation results for each business rule
  • Final approval status

4. Verbose Logging

The trace.verbose property controls detailed execution traces in the application server logs or Decision Warehouse execution output. This property is currently enabled by default (RuleApp property set to true).

To view verbose logging:

  • Check the application server logs or Decision Warehouse execution output
  • Look for detailed traces with timestamps and execution metadata

The trace output includes:

  • Execution metadata (rulesetPath, decisionId, rulesetEngineVersion, rulesetDeploymentDate)
  • Timestamped INFO messages for each rule execution and validation step
  • Business rule approval/rejection messages with timestamps
  • Error/warning messages when properties are missing or invalid

Example Trace Output

Since verbose logging is enabled by default, the execution produces detailed traces:

=== Start Execution ===
16:42:52.208922500 INFO Executing /VerySimpleCarRental/1.0/simple_carrental/1.0 - decisionId: 4867d679-f230-445a-a58c-a3d873fc7feb
Mon May 11 16:42:52 CEST 2026 INFO Execution
Mon May 11 16:42:52 CEST 2026 INFO rulesetPath: /VerySimpleCarRental/1.0/simple_carrental/1.0
Mon May 11 16:42:52 CEST 2026 INFO decisionId: VerySimpleCarRental_simple_carrental
Mon May 11 16:42:52 CEST 2026 INFO rulesetEngineVersion: 1.90.1
Mon May 11 16:42:52 CEST 2026 INFO rulesetDeploymentDate: Thu May 07 16:25:36 CEST 2026
16:42:52.215200 INFO Approved: FRANCE pick up location is in the operating countries
16:42:52.215200 INFO Approved: FRANCE drop off location is in the operating countries
16:42:52.215200 INFO Approved: pick-up date and drop-off date are available
16:42:52.217210100 INFO Approved: rental duration is at most 30 days
16:42:52.217210100 INFO  ###### TRANSACTION SUCCEEDED ######
=== End Execution ===

The trace output includes:

  • Execution metadata (rulesetPath, decisionId, rulesetEngineVersion, rulesetDeploymentDate)
  • Timestamped INFO messages for each rule execution and validation step
  • Business rule approval/rejection messages

5. Override with Ruleset Properties

Add ruleset properties in the Rule Execution Server console to override RuleApp defaults. When a ruleset property has the same name as a RuleApp property, it automatically overrides the RuleApp value.

Try these examples:

  1. Override maximum rental duration:

    • Add ruleset property rental.policy.max.duration.days with value 15 (overrides RuleApp default of 30)
    • Re-execute with a 7-day rental request (modify pickUpDate and/or dropOffDate)
    • Result: Transaction succeeds (7 days ≤ 15 days)
  2. Override operating countries:

    • Add ruleset property operating.countries with value GERMANY, BELGIUM, SPAIN
    • Re-execute with pickUpLocation: FRANCE
    • Result: Transaction fails (FRANCE not in operating countries)
  3. Disable verbose logging:

    • Add ruleset property trace.verbose with value false
    • Re-execute the ruleset
    • Result: No detailed traces in logs (only decisionLog output)

Note: Ruleset property changes take effect immediately without redeploying the ruleset.


Key Takeaways

  1. Properties are runtime configuration - Change behavior without modifying rules

  2. Type conversion matters - Use appropriate property methods (propertyNumber, propertyBoolean, propertyDate, propertyCollection) for type-specific comparisons and operations

  3. Ruleset properties override RuleApp properties - Provides deployment-time flexibility

  4. Always validate properties - Check for null/missing values and validate type conversions to avoid runtime errors

  5. Property prefixing is automatic - The B2X code automatically adds "ruleset." or "ruleapp." prefixes to avoid naming conflicts

  6. Use trace.verbose for debugging - Enable detailed logging without modifying rules

  7. Properties are not ruleset parameters - Properties are for runtime configuration, not for passing execution-specific data (use ruleset parameters for that)


Implementation Details

Overview

The project simulates a simplified car rental approval process that uses runtime properties to configure business rules dynamically, without modifying the rule logic itself. This capability allows you to adjust business behavior at deployment time or runtime by changing property values rather than redeploying rules.

Project Structure

BOM Entries

The project uses two BOM entries:

1. access-properties BOM - Property Access Classes

Dedicated to accessing ruleset and RuleApp properties at runtime.

properties.RuleappProperties - Provides methods to access RuleApp properties:

  • property(key) - Returns property as String
  • propertyNumber(key) - Returns property as Number
  • propertyBoolean(key) - Returns property as Boolean
  • propertyDate(key) - Returns property as Date
  • propertyCollection(key) - Returns property as String array

properties.RulesetProperties - Provides methods to access ruleset properties:

  • Same methods as RuleappProperties
  • Additional attributes for built-in properties (e.g., decisionId, rulesetPath)
2. util BOM - Helper Classes

Provides utility methods for business logic and logging.

util.RentalDecisionUtil - Utility class for business logic and logging:

  • rentalDurationCalculation - Calculates rental duration in days from pick-up and drop-off dates, with optional verbose logging
  • addToDecisionLog(text) - Appends messages to the decision log output, with optional verbose logging to application server logs

Rule Flow

The main ruleflow (ruleflow.rfl) orchestrates the car rental process:

  1. Start - Validates that all required properties are set
  2. init - Initializes configuration from properties (ruleset or ruleapp)
  3. availability - Checks date availability
  4. validation - Validates customer eligibility
  5. approval - Approves or rejects the rental request

Properties Used

Custom RuleApp Properties (defined in VerySimpleCarRental.dep)

Property Name Type Example Value Description
operating.countries Collection FRANCE, BELGIUM, SPAIN Countries where service operates
rental.policy.end.date Date 2030-01-01T21:52:16+02:00 Policy expiration date
rental.policy.max.duration.days Number 30 Maximum rental duration in days
trace.verbose Boolean true Enable verbose logging of rule execution

Important Note: RuleApp properties are retrieved only when rulesets are loaded or updated. Changes to RuleApp property values are not dynamic and will take effect only when the ruleset is initially loaded or when it is updated (e.g., ruleset redeployment, ruleset property changes).

Custom Ruleset Properties

Custom ruleset properties can be set at deployment time to override RuleApp properties. For example:

  • rental.policy.max.duration.days - Override the maximum rental duration for a specific ruleset
  • operating.countries - Override the operating countries for a specific ruleset
  • trace.verbose - Enable or disable verbose logging for a specific ruleset

Read-Only Properties

Read-only properties can only be accessed but not modified:

  • decisionId - Unique identifier for the execution
  • rulesetPath - Path of the deployed ruleset being executed

Key Implementation Patterns

1. Property Access with Type Conversion

The B2X implementation converts string property values to appropriate types:

// String access
com.ibm.decision.run.RunContext rc = getRunContext();
java.lang.String result = null;
key = "ruleset." + key;
if (rc != null && rc.getMetadata().get(key) != null && rc.getMetadata().get(key) instanceof java.lang.String) {
    result = (java.lang.String) rc.getMetadata().get(key);
}
return result;
// Numeric access with conversion (handle NumberFormatException)
com.ibm.decision.run.RunContext rc = getRunContext();
java.lang.Number result = 0;
key = "ruleset." + key;
if (rc != null && rc.getMetadata().get(key) != null && rc.getMetadata().get(key) instanceof java.lang.String) {
    try {
        result = java.lang.Double.valueOf(
            (java.lang.String) rc.getMetadata().get(key)
        );
    }
    catch (java.lang.NumberFormatException e) {
        // Invalid numeric value: default result is used
    }
}
return result;
// Boolean access
com.ibm.decision.run.RunContext rc = getRunContext();
java.lang.Boolean result = false;
key = "ruleset." + key;
if (rc != null && rc.getMetadata().get(key) != null && rc.getMetadata().get(key) instanceof java.lang.String) {
    java.lang.String value = (java.lang.String) rc.getMetadata().get(key);
    result = "true".equalsIgnoreCase(value.trim());
}
return result;
// Date access (handle DateTimeParseException)
com.ibm.decision.run.RunContext rc = getRunContext();
java.util.Date result = null;
key = "ruleset." + key;
if (rc != null && rc.getMetadata().get(key) != null && rc.getMetadata().get(key) instanceof java.lang.String) {
    try {
        java.lang.String propDate = (java.lang.String) rc.getMetadata().get(key);
        result = java.util.Date.from(java.time.Instant.parse(propDate));
    }
    catch (java.time.format.DateTimeParseException e) {
        // Invalid date value: default result is used
    }
}
return result;
// Collection access (comma-separated)
com.ibm.decision.run.RunContext rc = getRunContext();
java.lang.String[] results = null;
key = "ruleset." + key;
if (rc != null && rc.getMetadata().get(key) != null && rc.getMetadata().get(key) instanceof java.lang.String) {
    java.lang.String result = (java.lang.String) rc.getMetadata().get(key);
    results = result.split("\\s*,\\s*");
}
return results;

Note: Always wrap type conversions in try-catch blocks to handle invalid property values with proper error handling.

2. Property Naming and Prefix Requirement

To avoid naming conflicts, RuleApp and ruleset properties are stored in the same RunContext metadata with different prefixes. The B2X code must add the appropriate prefix:

For Ruleset Properties:

// User provides logical name: "rental.policy.max.duration.days"
key = "ruleset." + key;  // Becomes: "ruleset.rental.policy.max.duration.days"
result = (java.lang.String) rc.getMetadata().get(key);

For RuleApp Properties:

// User provides logical name: "rental.policy.max.duration.days"
key = "ruleapp." + key;  // Becomes: "ruleapp.rental.policy.max.duration.days"
result = (java.lang.String) rc.getMetadata().get(key);

This prefixing allows both RuleApp and ruleset to define properties with the same name without conflict. In rules, users reference properties by their logical name (e.g., "rental.policy.max.duration.days"), and the B2X code handles the prefixing automatically.

3. Accessing Runtime Attributes (Not in Metadata)

Some runtime attributes are not stored in the RunContext metadata and require different access methods:

DecisionId (ExecutionId):

// Access directly from RunContext, not from metadata
getRunContext().getExecutionId();

RulesetPath:

// Access from RunContext using get(), not getMetadata()
getRunContext().get("rulesetPath");

Key Difference: Properties use getRunContext().getMetadata().get(key), while these runtime attributes use getRunContext().getExecutionId() or getRunContext().get(key) directly.

4. Property Precedence Pattern

Rules check ruleset properties first, then fall back to RuleApp properties:

Example from initialization rules:

if
    the ruleset property "rental.policy.max.duration.days" is not null
    and the ruleset property "rental.policy.max.duration.days" is not empty
    and the number ruleset property "rental.policy.max.duration.days" is more than 0
then
    set 'rental policy max duration days' to the number ruleset property "rental.policy.max.duration.days";
else
    set 'rental policy max duration days' to the number ruleapp property "rental.policy.max.duration.days";

5. Property Validation

The validateInitSetting function checks that all required properties are set and valid before execution:

// Check if property is set (either as RuleApp or ruleset property)
boolean ruleappPropSet = properties.RuleappProperties.property(key) != null;
boolean rulesetPropSet = properties.RulesetProperties.property(key) != null;

if (!ruleappPropSet && !rulesetPropSet) {
    util.DecisionLog.addToDecisionLog("Error Setting: " + key + " is not SET");
    return false;
}

// Validate numeric properties can be converted
if (key.equals("rental.policy.max.duration.days")) {
    if (ruleappPropSet && properties.RuleappProperties.propertyNumber(key) == null) {
        util.DecisionLog.addToDecisionLog("Error Setting: " + key + " is not valid");
        return false;
    }
}

// Validate date properties can be parsed
if (key.equals("rental.policy.end.date")) {
    if (ruleappPropSet && properties.RuleappProperties.propertyDate(key) == null) {
        util.DecisionLog.addToDecisionLog("Error Setting: " + key + " is not valid");
        return false;
    }
}

This validation ensures:

  • All required properties exist (either at RuleApp or ruleset level)
  • Numeric properties contain valid numbers
  • Date properties contain valid ISO 8601 dates

6. Verbose Logging with trace.verbose Property

The trace.verbose boolean property controls detailed logging throughout rule execution. The property is loaded at the start of execution in the validateInitSetting() function and stored in the traceVerbose variable.

Loading trace.verbose in validateInitSetting():

// Called at the start node of the ruleflow
boolean traceVerbose = false;
if (properties.RulesetProperties.propertyBoolean("trace.verbose") != null) {
    traceVerbose = properties.RulesetProperties.propertyBoolean("trace.verbose");
}

Using in ruleflow initial action (init task):

if (traceVerbose) {
    note(new java.util.Date() + " INFO " + "rulesetPath: " + properties.RulesetProperties.rulesetPath);
    note(new java.util.Date() + " INFO " + "decisionId: " + properties.RulesetProperties.decisionId);
    note(new java.util.Date() + " INFO " + "rulesetEngineVersion: " + properties.RulesetProperties.rulesetEngineVersion);
    note(new java.util.Date() + " INFO " + "rulesetDeploymentDate: " + properties.RulesetProperties.rulesetDeploymentDate);
}

Using in B2X (RentalDecisionUtil.addToDecisionLog):

if (traceVerbose)
    note(java.time.LocalTime.now() + " INFO " + text);

This allows you to enable or disable detailed execution traces without modifying rules, useful for debugging and monitoring. The traces are written to the application server logs using the note() function.

Variables

Input Parameters (vars-params.var)

  • customerAge (int) - Customer's age
  • pickUpLocation (String) - Rental start location
  • dropOffLocation (String) - Rental end location
  • pickUpDate (Date) - Rental start date
  • dropOffDate (Date) - Rental end date
  • customerDrivingLicense (String) - Customer's driver license type
  • customerPaymentMethod (String) - Customer's payment method

Output Parameters (vars-params.var)

  • decisionLog (String) - Execution log with approval/rejection messages

Constant Variables (vars-constant.var)

These variables provide default/fallback values used in business rules:

  • earliestStartDate (Date) - Earliest possible rental start date (initialized to current date)
  • minimumDriverAge (int) - Minimum age to rent a car (default: 21)
  • acceptedLicenseTypes (String[]) - Accepted driver license types (default: INTERNATIONAL, EU)
  • depositRequired (boolean) - Whether deposit is required (default: false)
  • acceptedpaymentMethods (String[]) - Accepted payment methods (default: CREDITCARD, DIGITALWALLET, VOUCHER)

Property Mapping Variables (vars-props-mapping.var)

These variables store property values loaded during initialization from ruleset or RuleApp properties:

  • operatingCountries (String[]) - List of countries where service operates
  • rentalPolicyEndDate (Date) - Date when rental policy expires
  • rentalPolicyMaxDurationDays (int) - Maximum number of days for a rental
  • traceVerbose (boolean) - Whether to enable verbose logging

Reusing the Property Access BOM

The access-properties BOM can be reused in your own ODM projects. Simply copy the BOM files (access-properties.b2xa, access-properties.bom, access-properties_en_US.voc) from this project's bom/ directory to your project.

Note: The B2X file contains sample-specific code that will cause compilation errors. These can be easily fixed by removing references to the traceVerbose variable in the catch blocks.


Related Documentation

For detailed information about the feature, see: Accessing RuleApp and ruleset properties at run time.


Issues and contributions

For issues relating specifically to this sample, please use the GitHub issue tracker. We welcome contributions following our guidelines.

License

The Dockerfiles and associated scripts found in this project are licensed under the Apache License 2.0.

Notice

© Copyright IBM Corporation 2018-2026.

About

This sample demonstrates how to access ruleset and RuleApp properties at runtime via BOM B2X code

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors