Developers: Using Configuration to Add a Custom Function to a StreamBase Application

Home
Documentation
Library
Sample Code and Applications
FAQs
Articles
Community
Training
Download Center
Contact DevZone

Printer Friendly

Library Articles

Using Configuration to Add a Custom Function to a StreamBase Application

Authors: Natan Cliffer, Dr. John Lifter
StreamBase Systems

Date: 01-September-2007

    Introduction


    Prior to StreamBase 5.0, the callcpp and calljava functions were the only way to refer to a custom C++ or custom Java function in a StreamBase expression. Although this approach is still available in StreamBase 5.0, an alternative, configuration based approach may also be used. After the appropriate configuration entries have been made, a custom C++ or Java function may be invoked within a StreamBase expression through a simple name. Additionally, if a custom function is overloaded, or if you have multiple custom functions with the same name, the StreamBase runtime can use the configuration information and the argument list supplied to the method call to determine which version of the method to invoke.

    The <custom-functions> Configuration Element


    Within the StreamBase server configuration file, the <custom-functions> element may contain one or more <custom-function> child elements. Each <custom-function> element describes the API of a C++ or Java custom function. All C++ custom functions must be described in a <custom-function> element. Describing a Java custom function in a <custom-function> element is optional and is only used when you want to invoke custom Java functions without using the calljava function.

    The syntax of the <custom-function> element is as follows.

        <custom-function type='simple' | 'aggregate' 
           [name='methodName'] [language='cplusplus' | 'java']
           [alias='aliasedMethodName'] [class='package.className'] [args='auto'] >
             [
              <args>
                 <arg type="..." [length='...'] />
                 . . .
              </args>
              <return type="..." [length='...'] />
             ]
        </custom-function>
    

    This specification is not as difficult to understand as it first appears.

    • Each function must be identified as being either a simple or aggregate function, so the type attribute, with the value 'simple' or 'aggregate', is required.
    • If the custom function is a simple function, then the name attribute must be provided; its value is the name of the custom function. If the custom function is an aggregate function, the name attribute is not used as the StreamBase runtime will invoke the init, accumulate, and calculate methods as required.
    • The language attribute indicates whether the custom function has been written in C++ or Java. The default specifies C++, so you only need to use this attribute for Java custom functions.
    • The alias attribute is an alternative name that will be used to invoke this method in a StreamBase expression. Its value may be different from, or the same as, the value assigned to the name attribute. This attribute is only required if you want to avoid using the callcpp or calljava functions.
    • If the custom function is implemented in Java, the class attribute is used to specify the full package and class name of the Java class containing the function's implementation. This attribute is not used for C++ custom functions.
    • The args='auto' entry is only used when the custom function has been written in Java. The StreamBase runtime will use introspection and the argument list provided when the custom function is called to determine which custom function to invoke. When this entry is provided, it is not necessary to include the <args> and <return> child elements. If the custom function has been written in C++, the <args> and <return> child elements are required.

    A few examples will make this much clearer.

    Configuration Examples

    A simple, C++ custom function named myFunction would be defined as follows.

        <custom-function type='simple' name='myFunction' alias='myFunctionAlias' >
          <args>
             <arg type='...' [length='...'] />
             . . .
          </args>
          <return type='...' [length='...'] />
        </custom-function>
    

    Where one, or more, <arg> elements are used to define the function's argument list and the <return> element defines the function's return. If the type of an argument or return value is string, the length attribute is used to specify its size. Note that the alias name may either be the same or different than the actual function name.

    Since an alias name has been provided, a StreamBase expression may invoke this function by using the alias as a function name [for example, myFunctionAlias (arg, ...)], rather than through the callcpp function, which uses the function's actual name [that is, callcpp('myFunction', arg,..)].

    An aggregate, Java custom function named myFunction implemented in the class com.streambase.MyClass could be defined as follows.

        <custom-function type='aggregate' language='java'
           alias='myFunctionAlias' class='com.streambase.MyClass' args='auto' />
    

    Note that although a name attribute is not specified (this is an aggregate function), you can still provide an alias name. For a Java custom function, it only makes sense to create a <custom-function> configuration entry if you want to call the function directly rather than through the calljava function.

    Overloaded Functions


    Frequently you may want to use the same function name for functions with different argument lists and/or return values. In StreamBase 5.0, this can be accomplished through configuration and, if you assign the same alias name to the overloaded functions, the StreamBase runtime will use the argument list to select the appropriate function to invoke.

    For a group of overloaded Java custom functions, this process is extremely straight-forward. One <custom-function> configuration entry, with the args='auto' attribute and an alias name is all that is required, although the Java class that includes your custom code will need to include implementations for each of the overloaded functions. At runtime, simply use the alias name and provide an appropriate argument list, and the runtime will invoke the correct function.

    For a group of C++ overloaded functions, you will need to include a <custom-function> configuration entry for each of the function signatures, using the same alias name for each entry. At runtime, use the alias name and provide an appropriate argument list, and the runtime will invoke the correct function.

    An Application Example

    To illustrate how function overloading can be implemented through configuration, consider the following Java class, which implements simple Java custom functions.

        package com.training;
    
        public class MySimpleFunction {
    
          public static int myFunction(int arg0) {	
            return 1;
          }
    
          public static int myFunction(int arg0, int arg1) {
            return 2;
          }
    
          public static int myFunction(int arg0, int arg1, int arg2) {
            return 3;
          }
        }
    

    This class contains three identically named functions, each with a different argument list.  To use these functions in an EventFlow or StreamSQL application, add the following entry to the configuration file.

      <custom-functions>
        <custom-function name='myFunction' type='simple' language='java'
          alias='myFunctionAlias' class='com.training.MySimpleFunction' args='auto'/>
      </custom-functions>
    

    This entry associates the alias name myFunctionAlias with all of the overloaded functions sharing the name myFunction. The implementations for these functions is contained in the com.training.MySimpleFunction class, and the args='auto' attribute means that the StreamBase runtime will use introspection to determine which overloaded function to invoke. Consequently, the configuration file does not need a separate <custom-function> entry, with explicitly defined arguments and return value, for each of the functions.

    To use these overloaded functions, create the following StreamSQL application.

        CREATE INPUT STREAM InputStream1 (in int);
    
        CREATE OUTPUT STREAM OutputStream1 AS
          SELECT
            "You sent me " + myFunctionAlias(in) + " argument" AS field1,
            "You sent me " + myFunctionAlias(in, in) + " arguments" AS field2,
            "You sent me " + myFunctionAlias(in, in, in) + " arguments" AS field3
          FROM InputStream1;
    

    If you want to create an equivalent EventFlow application, define an input stream whose schema includes a single integer field named in, and then a map operator configured as follows will provide equivalent functionality.

    Note how in both the StreamSQL and EventFlow examples, the alias name with a different argument list is used to invoke one of the overloaded functions. Alternatively, you could use the calljava helper function to call each function explicitly. For example:

        calljava("com.training.MySimpleFunction","myFunction",in)
        calljava("com.training.MySimpleFunction","myFunction",in, in)
        calljava("com.training.MySimpleFunction","myFunction",in, in, in)
    

    In order to use the alias name to invoke a custom simple function, you must have a corresponding <custom-function> entry in the configuration file. You may use the calljava helper function with, or without, a <custom-function> entry.

    Related Topics


    Using the StreamBase Studio Java Operator Wizard