Home > Tutorial

Develop Programmatic Constraints

So far, starting from a relational database structure, we saw how to implement the corresponding model using both XML Schema native declarations and webMethods MDM extensions.

However, some features are not always easy to implement. It is generally the case for customer specific business rules. In those cases, the underlying logic has to be described in a programmatic manner, using Java code. We will see in this chapter how to implement these programmatic extensions.

Constraints

Learn MoreAs for any other facet extension, the constraint implemented in a specific Java class is declared in an mdm:otherFacets element. It uses class as an attribute to specify the path to the Java class.

Example: Implement a constraint where the range between elements lo_range and hi_range in table Royalties is lower than 1000.

First, we declare the class implementing the constraint in the lo_range element of the schema:

<xs:element name="lo_rangetype="xs:intminOccurs="0">
    <xs:annotation>
        <xs:appinfo>
            <mdm:otherFacets>
                <mdm:constraint class="com.softwareag.mdm.tutorial.constraints.CheckRoyaltyLowRange"/>
            </mdm:otherFacets>
        </xs:appinfo>
    </xs:annotation>
</xs:element>

Next, we have to develop the corresponding Java code.

JavaDocThe class must implement the com.softwareag.mdm.schema.Constraint interface, i.e. overrides methods setup, checkOccurrence and to UserDocumentation

Here is an implementation example:

/*
 * Copyright © Software AG 2000-2007. All rights reserved.
 */

package com.softwareag.mdm.tutorial.constraints;

import java.util.*;
import com.softwareag.mdm.instance.*;
import com.softwareag.mdm.schema.*;

public class CheckRoyaltyLowRange implements Constraint
{
    public void setup(ConstraintContext aContext)
    {
    }

    public void checkOccurrence(Object aValue, ValueContextForValidation aValidationContext)
    {
        if (aValue == null)
            return;
        
        Integer lo_range = null;
        Integer hi_range = null;
        
        Object tmp = null;

        if ((tmp = aValidationContext.getValue(Path.parse("../lo_range"))) != null
        {
            lo_range = (Integer) tmp;    
        }
        if ((tmp = aValidationContext.getValue(Path.parse("../hi_range"))) != null
        {
            hi_range = (Integer) tmp;
        }
        
        if (hi_range != null && lo_range!=null)
        {
            int diff = hi_range.intValue() - lo_range.intValue();
            if (diff>1000
            {
                aValidationContext.addError("The interval between Min and Max must be lower than 1000");
                return;
            }
        }
    }

    public String toUserDocumentation(Locale arg0, ValueContext arg1) throws InvalidSchemaException
    {
        return "Programmatic constraint checking that the interval between Min and Max does 
not exceed 1000"
;
    }
}

As a result, we can see that an error message is raised when the constraint is breached:

As you probably noticed, the error messages are not localized in the class. We can easily implement it using the ResourceBundle class of the Java 2 Platform JDK (see http://java.sun.com/j2se/1.4.2/docs/api/java/util/ResourceBundle.html).

Parameterized contraints

In the previous example, the value of the allowable interval is hard coded in the Java code. We will now see how to implement the same constraint using a parameter.

The parameter is defined in the model as paramN where N is an integer.

<xs:element name="lo_rangetype="xs:intminOccurs="0">
    <xs:annotation>
        <xs:documentation xml:lang="fr-FR">
            <mdm:label>Min</mdm:label>
            <mdm:description>Borne inférieure</mdm:description>
        </xs:documentation>
        <xs:documentation xml:lang="en-US">
            <mdm:label>Min</mdm:label>
            <mdm:description>Lower range</mdm:description>
        </xs:documentation>
        <xs:appinfo>
            <mdm:otherFacets>
                <mdm:constraint class="com.softwareag.mdm.tutorial.constraints.CheckRoyaltyLowRange">
                    <
param1>1000</param1>
                </mdm:constraint
>
            </mdm:otherFacets>
        </xs:appinfo>
    </xs:annotation>
</xs:element>

You can define as many params as required in the schema.

The way you access these parameters is through a Java Bean: a specific String class field must be defined for each parameter described in the schema.
The corresponding Getters and Setters for those fields must also be defined in the class implementing the constraint.

Starting from our previous example:

  • we add a ‘param1’ parameter and access its value in the class through its getter. The setter is automatically called by webMethods MDM to pass the parameter value to the class,
  • we rewrite the setup method (called when validating the model) to check the presence and correctness of the parameter,
  • we rewrite the checkOccurence method to take this parameter into account.

/*
 * Copyright © Software AG 2000-2007. All rights reserved.
 */

package com.softwareag.mdm.tutorial.constraints;

import java.util.*;

import com.softwareag.mdm.instance.*;
import com.softwareag.mdm.schema.*;

public class CheckRoyaltyLowRange implements Constraint
{
    int interval;
    String param1;

    public String getParam1()
    {
        return this.param1;
    }

    public void setParam1(String param1)
    {
        this.param1 = param1;
    }
    
    public void setup(ConstraintContext aContext)
    {
        // check param is present
        if (this.getParam1() == null)
        {
            aContext.addError("param1 is not defined !");
            return;
        }

        // check param is an integer value
        try
        {
            this.interval = Integer.parseInt(this.getParam1());
        }
        catch (Exception e)
        {
            aContext.addError("param1 must be an integer !");
            return;
        }
    }

    public void checkOccurrence(Object aValue, ValueContextForValidation aValidationContext)
    {
        if (aValue == null)
            return;
        
        Integer lo_range = null;
        Integer hi_range = null;
        
        Object tmp = null;

        if ((tmp = aValidationContext.getValue(Path.parse("../lo_range"))) != null
        {
            lo_range = (Integer) tmp;    
        }
        if ((tmp = aValidationContext.getValue(Path.parse("../hi_range"))) != null
        {
            hi_range = (Integer) tmp;
        }
        
        if (hi_range != null && lo_range!=null)
        {
            int diff = hi_range.intValue() - lo_range.intValue();
            if (diff>this.interval) 
            {
                aValidationContext.addError("The interval between Min and Max must be lower than "
+this.interval);
                return;
            }
        }
    }

    public String toUserDocumentation(Locale arg0, ValueContext arg1) throws InvalidSchemaException
    {
        return "Programmatic constraint checking that the interval between Min and Max does not exceed "
+this.interval;
    }

We can now easily change the parameter value in the schema without recompiling the code and the control is correctly managed.

Computed values

Learn MoreThanks to the webMethods MDM programmatic extension, we can also implement a specific class to specify a default value for one of our model field.

Example: Populate by default the value of royalty as the result of a specific computing (hi_range – lo_range).*0.8

First, we declare the class implementing the default value computing in the lo_range element of the schema:

<xs:element  name="lo_rangetype="xs:intminOccurs="0" >
    <xs:annotation>
        <xs:appinfo>
            < mdm:function class="com.softwareag.mdm.tutorial.defaultValues.ComputeRoyaltyDefaultValue"/>
        </xs:appinfo>
    </xs:annotation >
</xs:element >

JavaDoc Next, we create the corresponding Java class. The class must implement the com.softwareag.mdm.schema.ValueFunction interface (methods getValue and setup).

/*
 * Copyright © Software AG 2000-2007. All rights reserved.
 */

package com.softwareag.mdm.tutorial.defaultValues;

import java.math.*;

import com.softwareag.mdm.adaptation.*;
import com.softwareag.mdm.schema.*;

public class ComputeRoyaltyDefaultValue implements ValueFunction
{
    public Object getValue(Adaptation adaptation)
    {
        int lo_range = adaptation.get_int(Path.parse("./lo_range"));
        int hi_range = adaptation.get_int(Path.parse("./hi_range"));
        
        return new BigDecimal((hi_range-lo_range)*0.8);
    }

    public void setup(ValueFunctionContext context)
    {
    }
}

As per the parameterized constraints, a default value may also depend on a parameter ‘paramN’, where N is an integer. The same Java Bean principle is applicable.

 

Next: Add UI Component & Filter >

 

Home > Tutorial