The monitor programming model receives data coming from external events, extracts these data, and maps them to metrics that may trigger other operations to occur. Expressions play an important role; they produce the values used in the monitor model and dictate the overall flow of the monitor model logic. You can define what values are eventually stored, how and when certain operations or events can take place, what events to process, and what monitor context instances to operate on—all by using XPath expressions.
Previously, expressions were built mainly from event data, previously computed expressions, and built-in XPath functions. WebSphere Business Monitor V6.1 has introduced the notion of a user-defined XPath function (UDXF). With UDXF, you can:
- Create functions that are not currently available.
- Pull information and event data from other sources, such as Web services, spreadsheets, and third-party databases.
- Customize functions that vary depending on conditions, such as your current locale, time, and so forth.
- Implement complicated rules that can affect the logic of your monitor model (for example, calendaring functions).
In this article, learn step by step how to add new functions to your monitor model using UDXF. A very simple example is used first. Then you'll follow a more complicated example with the mortgage lending business scenario.
You can download the examples used in this article.
The first step is to write the Java function that you plan to use as an additional XPath function in your XPath expressions, as follows:
- Switch to the Java perspective and create a new Java project with the name
MyUDF. - Add the monitor run time library to this Java project by right-clicking on the
project and selecting Build Path -> Add Libraries.
Figure 1. Setting the build path
Select Monitor Runtime Library, click Next, then click Finish.
Figure 2. Selecting the monitor run time library
- Create a new class in this project to hold the function implementations. This
class must exist in a nondefault package.
UDXF classes in the default package will cause errors, because they cannot be referenced later in the generated code of other projects.
You may also wish to create a messages.properties file for localization. Listings 1 and 2 show examples.
Listing 1. com/foo/bar/Truth.javapackage com.foo.bar; import static com.ibm.wbimonitor.xml.expression.udf. XPathFunction.CallingConvention.JAXB; import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Indicator.One; import com.ibm.wbimonitor.xml.expression.udf.XPathFunction; import com.ibm.wbimonitor.xml.expression.udf.XPathType; public class Truth { private static final String NAMESPACE_NAME = "http://www.foo.com/truth"; @XPathFunction( namespaceName = NAMESPACE_NAME, localName = "true", description = "Returns true.", descriptionKey = "com.foo.bar.messages/Truth_trueDescription", callingConvention = JAXB, isDeterministic = true, isSelfContained = true ) public static @XPathType(occurrenceIndicator = One) Boolean logicalTrue() { return Boolean.TRUE; } }
Listing 2. com/foo/bar/messages.propertiesTruth_trueDescription=Returns true.
At this point your project should look like Figure 3.
Figure 3. Example Java project
- Export the project as a JAR by right-clicking on the project, selecting
Export..., Java -> JAR file. This JAR file will be
imported for use in the monitoring model in the next section.
Though the JAR file can be saved anywhere in your file system, it is recommended you save it within a project in your work space.
For this tutorial, save the JAR file into the directory containing the MyUDF project.
Now that the function has been written, you want to be able to use it in your expressions.
- Switch to the business monitoring perspective, create a new business monitoring project, then a new monitor model within it.
- Add the UDXF created above to the business monitoring project by
right-clicking on the project and selecting External Function
Libraries....
Figure 4. Selecting external function libraries
Click Add JARs..., and select the JAR created above.
Figure 5. Selecting the JAR file
Figure 6. Successful selection
- To add the UDXF to the monitor model, open the
monitor model source file to edit and select the monitor details model tab.
Click Edit... in the user-defined XPath functions section of the edit
window, select the namespace, assign a prefix to it, and click Finish.
Figure 7. Adding UDXF to monitor model
Figure 8. Successful UDXF addition
- To use the new function, create a
booleanmetric and entertruth:true()as the default value.The new function and its description are available through content assist, as shown in Figure 9.
Figure 9. Using the new function
So far you have learned how to create a UDXF and how to include and use it within a monitor model. This section further examines the different elements used when writing a UDXF.
Listing 3 shows four import statements that must be
included when writing a UDXF. The first two
import static statements allow you the convenience of
using "JAXB" and "One" in the code directly, instead of using their very long full
names (XPathFunction.CallingConvention.JAXB and XPathType.Indicator.One,
respectively). The second two import statements are
for the two UDXF annotations that you use to declare a method to be a UDXF.
Listing 3. com/foo/bar/Truth.java, imports.
import static com.ibm.wbimonitor.xml.expression.udf.XPathFunction.CallingConvention.JAXB; import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Indicator.One; import com.ibm.wbimonitor.xml.expression.udf.XPathFunction; import com.ibm.wbimonitor.xml.expression.udf.XPathType; |
While not required, it's a good idea to place your namespace name (the namespace in which your functions will be found) in a constant. If you have multiple UDXFs defined in one class, it is easy to put them all in the same namespace, as shown in Listing 4.
Listing 4. com/foo/bar/Truth.java, namespace name
private static final String NAMESPACE_NAME = "http://www.foo.com/truth"; |
Listing 5 shows an example of using the XPathFunction
annotation, which contains the information necessary to mark a method as a UDXF.
Listing 5. com/foo/bar/Truth.java, XPathFunction annotation
@XPathFunction(
namespaceName = NAMESPACE_NAME,
localName = "true",
description = "Returns true.",
descriptionKey = "com.foo.bar.messages/Truth_trueDescription",
callingConvention = JAXB,
isDeterministic = true,
isSelfContained = true
) |
The XPathFunction annotation has several elements, as follows.
namespaceName- (required, String) The namespace in which the function will be found. It
must parse to a valid uniform resource identifier (URI).
This namespace will be assigned a prefix in the function prefix library area when adding the functions of this namespace to a monitor model.
localName- (required, String) The XPath name of the function. It does not have to be
the same or in any way related to the name of the Java method implementing
this function.
This should be a valid NCName. Although everything will work when using an invalid NCName, it will not be possible to call the function from within an expression.
description- (optional, String default "") The default description of this method. Description may be displayed by content assist.
descriptionKey- (optional, String default "") Used to find a localized description of this
method. The format of this String is "bundle.name/key_name".
The bundle will be searched for with the standard Java bundle resolution mechanism within the JAR in which this method is found, given the current locale settings. If the bundle or key cannot be found, the
descriptionwill be used. This description may be displayed by content assist. callingConvention- (optional, XPathFunction.CallingConvention default JAXB) Currently, only the
built-in JAXB bindings are supported.
An internal binding exists but is not supported. Use it at your own risk.
isDeterministic- (required, boolean) Set to true if the output of this function only depends
on its parameters. For example, you would expect
add(1, 2)to always return3soisDeterministicwould be true.On the other hand,
random()will return a different value for every call, soisDeterministicwould be false. Functions marked withisDeterministicas true may be used to produce constant expressions, allowing for additional validation. isSelfContained- (required, boolean) Set to true if the function does not use any external
resources that exist only in the target environment. Functions marked with
isSelfContainedas true will be called during validation if the parameters can be determined, allowing for additional validation.If you have a function that makes external connections to a database or server, it should have
isSelfContainedset to false so that it is not called during monitor model development.
Java types for method and parameters
For the method and parameters, only certain types are allowed. The types are
based on the default JAXB bindings when the
callingConvention of the XPathFunction annotation is
JAXB. Listing 6 shows an example.
Listing 6. com/foo/bar/Truth.java, Java types for method and parameters
public static @XPathType(occurrenceIndicator = One) Boolean logicalTrue() {
|
Table 1 lists the Java types allowed and the corresponding XML datatype. Those XML datatypes listed in bold are defaults. To select an XML datatype other than the default, you must use the XPathType annotation.
Table 1. Method return types
| Java return type | XML datatype |
|---|---|
| java.lang.String | xs:string |
| java.math.BigInteger | xs:integer, xs:decimal |
| java.math.BigDecimal | xs:decimal |
| java.lang.Boolean | xs:boolean |
| javax.xml.datatype.XMLGregorianCalendar | xs:date, xs:time, xs:dateTime |
| javax.xml.datatype.Duration | xs:duration, xs:dayTimeDuration, xs:yearMonthDuration |
| java.util.Calendar | xs:dateTime |
| java.net.URI | xs:string |
| java.util.UUID | xs:string |
Table 2 shows the parameter types. XML dataypes in bold are defaults.
Table 2. Parameter types
| Java parameter type | XML datatype |
|---|---|
| java.lang.String | xs:string |
| java.math.BigInteger | xs:integer |
| java.math.BigDecimal | xs:decimal, xs:integer |
| java.lang.Boolean | xs:boolean |
| javax.xml.datatype.XMLGregorianCalendar | xs:date, xs:time, xs:dateTime |
| javax.xml.datatype.Duration | xs:duration, xs:dayTimeDuration, xs:yearMonthDuration |
The XPathType annotation may be used on the method itself to clarify the return value of the method. It can also be used on parameters of a method to clarify the type of the parameter, as shown below.
Listing 7. com/foo/bar/Truth.java, XPathType annotation
public static @XPathType(occurrenceIndicator = One) Boolean logicalTrue() {
|
The XPathType annotation has three elements:
name- (optional, String default "") May be used to give a name to a parameter as a
form of documentation.
If the XPathType annotation is used on a method, this element is ignored.
itemType- (optional, XPathType.Type default infer) Clarifies the type of return value
or parameter. When this is set to Infer, the defaults listed in the table
above apply.
The XMLGregorianCalendar has no default type associated with it. The XPathType annotation must always be used with XMLGregorianCalendar, and it must specify the
itemType. occurrenceIndicator- (optional, XPathType.Indicator default ZeroOrOne) Further clarifies the type
of return value or parameter. For a full understanding of occurrence
indicators, you need to understand the XPath type system. For this
application, however, all you really need to know is that if this is set to
One on a return value, it means that you are promising to never return null.
If you set this to One on a parameter, you expect that the argument should
never be null. A setting of ZeroOrOne allows nulls for these values at run
time, and the type will be marked with a '?' in the UI to indicate that the
value may be null.
If you want to be able to use a function to assign a value to a metric marked as value is required, you will need to mark the method (the return value) with the XPathType annotation element
occurrenceIndicatorset to One, as metrics marked as value is required should not be assigned null.
The Java method that implements the function must be
public static, as shown in Listing 8. The name of the
method does not need to be related to the name of the function as specified in the
XPathFunction.name annotation element.
Listing 8. com/foo/bar/Truth.java, the Java method
public static @XPathType(occurrenceIndicator = One) Boolean logicalTrue(){ |
There can be as many XPathFunction annotated methods in a class as desired. If there is more than one method, these methods do not need to share the same namespace, though it is recommended that they do for ease of maintenance.
Using XMLGregorianCalendar and Duration
When writing a UDXF that uses or returns a time, date, dateTime, duration,
dayTimeDuration, or yearMonthDuration, the associated Java type is
XMLGregorianCalendar (for time, date, dateTime) or
Duration (for duration, dayTimeDuration, or
yearMonthDuration). While not difficult, using these types could be confusing
without an example of how to create and use them. See the snippet shown in Listing
9.
Listing 9. com/foo/bar/Sale.java
package com.foo.bar;
import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Indicator.One;
import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Type.Date;
import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Type.DayTimeDuration;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import com.ibm.wbimonitor.xml.expression.udf.XPathFunction;
import com.ibm.wbimonitor.xml.expression.udf.XPathType;
public class Sale {
private static final String NAMESPACE_NAME = "http://www.foo.com/sale";
private static final DatatypeFactory XDF;
static {
try {
XDF = DatatypeFactory.newInstance();
} catch (final DatatypeConfigurationException e) {
throw new IllegalStateException(e);
}
}
@XPathFunction(
namespaceName = NAMESPACE_NAME,
localName = "duration-of-sale",
isDeterministic = false,
isSelfContained = true
)
public static
@XPathType(itemType = DayTimeDuration, occurrenceIndicator = One) Duration
lengthOfSale() {
return XDF.newDurationDayTime("P4D");
}
@XPathFunction(
namespaceName = NAMESPACE_NAME,
localName = "date-of-sale",
isDeterministic = false,
isSelfContained = true
)
public static
@XPathType(itemType = Date, occurrenceIndicator = One) XMLGregorianCalendar
dateOfSale() {
return XDF.newXMLGregorianCalendar("2007-12-05Z");
}
} |
Once a DatatypeFactory is created, use its
newXXX methods to create XMLGregorianCalendars
and Durations. There are several newXXX methods;
the correct one should be used for best results. All XMLGregorianCalendars that
are returned from a method should have a time zone set. (This limitation may be
lifted in the future.) Be sure to read the documentation for
DatatypeFactory,
XMLGregorianCalendar, and
Duration if you are planning to use them.
Beware of a few kinds of errors using UDXFs.
Loading errors occur when you add a UDXF JAR to a business monitoring project
using the external function libraries dialog box. The errors occur when there is
an issue with a method marked with the XPathFunction annotation. There are many
reasons this can happen, but typically they are type errors. For example,
specifying a parameter of type XMLGregorianCalendar
without an XPathType annotation will cause an error, as there is no default XML
data type associated with XMLGregorianCalendar.
Loading errors are reported on the .monitor.classpath file in the business monitoring project. When a loading error exists in a JAR, none of the functions in that JAR will be available.
Run time errors occur when a UDXF is invoked. To help discover run time errors,
the Validator will invoke the method if it is marked as
isSelfContained and all the parameters are known. It is
also possible to test UDXFs using the visual model editor (but how to do this is
outside the scope of this article).
If an error is detected when the method is invoked, an error will be displayed
in the problems view. These errors are normally either exceptions thrown by the
method, or they are type errors when an
XMLGregorianCalendar is stated to be a date or time but
the fields are not set correctly.
Sometimes there are complex business rules for simple things. In such cases, it can be useful to wrap the rules inside a UDXF. The following example demonstrates a UDXF to be used with the mortgage lending example previously used in this series.
The problem: Application to Funded Duration Days needs to be changed to reflect not the number of days or duration of time elapsed, but the number of business days between the start and finish times. The concept of "business day" varies greatly, and perhaps even independently of the model itself. The example in Listing 10 implements one set of rules about what makes a business day.
Listing 10. com/mortgage/lending/UDF.java
package com.mortgage.lending;
import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Indicator.One;
import static com.ibm.wbimonitor.xml.expression.udf.XPathType.Type.DateTime;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.xml.datatype.XMLGregorianCalendar;
import com.ibm.wbimonitor.xml.expression.udf.XPathFunction;
import com.ibm.wbimonitor.xml.expression.udf.XPathType;
public class UDF {
private static final String NAMESPACE_NAME
= "http://www.mortgage.com/lending";
private static final long MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
private static final int END_HOUR_OF_DAY = 17; //5:00PM
@XPathFunction(
namespaceName = NAMESPACE_NAME,
localName = "business-days-between",
description = "(start, end) Computes the number of end-of-business
days between start and end. When there are more than 100 days,
the result is an estimate.",
isDeterministic = true,
isSelfContained = true
)
public static @XPathType(occurrenceIndicator = One) BigInteger businessDaysBetween(
final @XPathType(itemType = DateTime, occurrenceIndicator = One)
XMLGregorianCalendar day1
, final @XPathType(itemType = DateTime, occurrenceIndicator = One)
XMLGregorianCalendar day2
) {
final GregorianCalendar current;
final GregorianCalendar end;
{
final GregorianCalendar day1g = day1.toGregorianCalendar();
final GregorianCalendar day2g = day2.toGregorianCalendar();
final int cmp = day1g.compareTo(day2g);
if (cmp == 0) {
return BigInteger.ZERO;
} else if (cmp > 0) {
end = day1g;
current = day2g;
} else { //cmp < 0
end = day2g;
current = day1g;
}
}
//greater than 100 days, estimate
final long days = (end.getTimeInMillis() - current.getTimeInMillis())
/ MILLIS_PER_DAY;
if (days > 100) {
//the simple estimate is that five of every seven days are a business day.
return BigInteger.valueOf((days * 5) / 7);
}
//After 5PM, advance to next day
if (current.get(Calendar.HOUR_OF_DAY) >= END_HOUR_OF_DAY) {
current.add(Calendar.DATE, 1);
}
//Start at the beginning of the day
current.set(Calendar.HOUR_OF_DAY, 0);
current.set(Calendar.MINUTE, 0);
current.set(Calendar.SECOND, 0);
current.set(Calendar.MILLISECOND, 0);
//advance to the first business day
while (end.compareTo(current) > 0) {
if (isBusinessDay(current)) break;
current.add(Calendar.DATE, 1);
}
//advance past the first partial day
current.add(Calendar.DATE, 1);
//count the business days until we pass the end day
long businessDays = 0;
while (end.compareTo(current) > 0) {
if (isBusinessDay(current)) ++businessDays;
current.add(Calendar.DATE, 1);
}
return BigInteger.valueOf(businessDays);
}
/**
* Checks to see if a given day is a business day.
* @param day the day to check.
* @return true is the day is a business day, false if not.
*/
private static boolean isBusinessDay(final GregorianCalendar day) {
//Business rule: everyone is off on Programmer's Day
final int dayOfYear = day.get(Calendar.DAY_OF_YEAR);
if (dayOfYear == 256) return false;
//Business rule: no one works on Talk Like a Pirate Day
final int month = day.get(Calendar.MONTH);
final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
if (month == Calendar.SEPTEMBER && dayOfMonth == 19) return false;
//Business rule: Sunday and Saturday are not business days
final int dayOfWeek = day.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) return false;
//Otherwise: back to work!
return true;
}
} |
To use this in the model, follow the steps listed above to create the JAR and add it to the business monitoring project. Then change the metric value expression of Application to Funded Duration Days to:
Listing 11. MortgageLendingBAM/Mortgage_Lending_BAM_MC/Application_to_Funded_Duration_Days
time:business-days-between(aux_Application_Start_Time
, Funding_Complete/fundingCompletePart/mor:dateCompleted)
|
In this article, you learned how to write and use a user-defined XPath function in a monitor model. UDXF is new in IBM WebSphere Business Monitor V6.1 and is one of the most useful additions to the monitor programming model. You are no longer limited to the built-in XPath functions. With the ability to write and implement an XPath function using Java, there are endless possibilities for what you can accomplish, whether it's getting the current stock quote of IBM or getting the status of an order from a spreadsheet.
| Description | Name | Size | Download method |
|---|---|---|---|
| The simple examples used in this article. | example.zip | 8KB | HTTP |
| The MortgageLending example used in this article. | mortgage.zip | 41KB | HTTP |
Information about download methods
Learn
- Check out the other parts of this series:
- Part 1, "What's new in WebSphere Business Monitor 6.1" (developerWorks, Dec 2007)
- Part 2, "WebSphere Business Monitor 6.1 installation improvements" (developerWorks, Jan 2008)
- Part 3, "Improved Unit Test Environment in IBM WebSphere Business Monitor Development Toolkit V6.1" (developerWorks, Feb 2008)
- Part 4, "Use the Integrated Test Client to improve iterative development with WebSphere Business Monitor V6.1" (developerWorks, March 2008)
- Part 5, "Managing failed and unrecoverable events In IBM WebSphere Business Monitor V6.1" (developerWorks, April 2008)
- Part 6, "Combine high-level monitor models from IBM WebSphere Business Modeler with low-level monitor models from IBM WebSphere Integration Developer" (developerWorks, April 2008)
- Get the Javadoc for
DatatypeFactory,
XMLGregorianCalendar,
and
Duration.
- Authoring XPath functions
has more information and examples.
- Browse the
IBM WebSphere Business Monitor documentation
for more details and reference material.
- Learn about
WebSphere Business Monitor
features and benefits, system requirements, library, services, news items and
more.
- Read about
WebSphere business process management
on developerWorks.
- Refer to
developerWorks
for more information on WebSphere business process management.
- Browse the
Jump-start business activity monitoring (BAM) series
for a wealth of WebSphere Business Monitor how-to information and samples.
- Browse the
technology bookstore
for books on these and other technical topics.
- Get an
RSS
feed
for the series Put new capabilities of business activity monitoring (BAM) to
work.
Get products and technologies
- Download
IBM product evaluation versions
and get your hands on application development tools and middleware products from
DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Participate in the discussion forum.
- Check out
developerWorks blogs and
get involved in the
developerWorks community.
Comments (Undergoing maintenance)



