This part of the API Guide describes how to develop custom Java operators for StreamBase applications. A Java operator is a StreamBase component, inserted in the flow of a StreamBase application, that calls a custom Java method.
Java operators extend the following packages in the StreamBase Java Client library:
-
com.streambase.sb.operator
-
com.streambase.sb.operator.parameter
Designing, developing, and configuring Java operators in StreamBase Studio is similar to working with embedded adapters. Generally, you follow this process:
-
Understand the StreamBase operator life cycle.
-
Create the required Java class for your operator. We strongly recommend using the StreamBase Java Operator wizard to generate the base Java code, as described in the following topic.
-
Edit the Java source generated by the wizard to implement your specific functionality. The code includes // TODO markers, which indicate sections that need to be completed. The following topic contains information about writing Java operator code:
Creating Custom Java Operators
Pay special attention to the Methods for Studio Presentation section of that page.
-
If you are using third-party jars or native libraries, you may need to configure StreamBase Studio to correctly load the libraries:
-
Add the custom operator to a StreamBase application, as described in this Authoring Guide topic:
You can use the operator and test it in the StreamBase Studio environment without compiling or packaging it.
-
Make sure the operator's class files are on StreamBase Studio's classpath and on the StreamBase Server's runtime classpath. This will be automatic in StreamBase projects – the project's Build Path's Default Output Path is on the Studio and StreamBase Server's classpath by default. When running the application in a command line environment outside of StreamBase Studio, the operator's
.class
files must all be on the server's classpath explicitly. Use either thejar
ordir
elements of thejava-vm
element to extend the server's classpath.
This topic explains how to use the StreamBase Java Operator wizard to generate the base code for a custom Java operator. For additional details, refer to the StreamBase Help topics listed in Related Topics.
StreamBase provides a number of built-in operators, such as Filter, Java, Map,
Aggregate, and Union, to perform common processing on streaming data. StreamBase
also provides an operator API, com.streambase.sb.operator
, which you can extend to
build custom functionality.
The Java Operator wizard helps you get started with the operator API by stepping
you through the definition process. The Java source file that it generates has
commented // TODO
sections that you can later edit to add
the functionality you want.
After you replace these sections with your implementation code, you can use the operator immediately in your applications that you run locally in StreamBase Studio. If you are running your applications remotely, you may want to generate a JAR first.
To open the wizard, click
> > . Edit these fields in the wizard:- Source folder
-
The path to an existing folder within your project. By default, StreamBase projects contain a
src/main/java
subfolder, which you can use. - Package
-
While you could use the default package, it is recommended that you specify a different one, such as com.example.mysbapps.operators.
- Name
-
A name for your class, such as
MyJavaOperator
. - Display Name
-
The human readable name you want to show in the Palette view and in the blue text above instances of your operator in the EventFlow canvas.
- Number of Input Ports
-
Specify the number of input ports that the operator's UI will present to StreamBase Studio users. You can change this setting after the code is generated.
- Number of Output Ports
-
Specify the number of output ports that the operator's UI will present to StreamBase Studio users. You can change this setting after the code is generated.
For example:
When you are ready, click Next to proceed to the next page.
The wizard's second page is labeled Java Operator. Use the second page of the wizard to specify features you want generated as Java code, and to specify properties that can be configured in the generated operator at runtime.
An operator property is a Java property for this operator. For each property you specify, the wizard generates stub code that places a control in the Operator Properties tab of the Properties view for your operator. After you add implementation code to the generated stub code, the end-user of your operator can use these controls to modify the operation of your operator. See Java Operator Properties for additional details.
Edit the following fields in the wizard's Java Operator page:
- Operator Properties
-
Specify one or more properties that can be set or modified by the users of your operator to control its operation. For each property you specify, the wizard generates code to place a control in the Operator Properties tab (or a tab you specify) of the Properties view for your operator's icon.
Clicking the New Operator Property dialog, in which you specify the type, name, default value, and other aspects for the property you are adding, as shown below.
button opens theThe Operator Properties grid is used in the same way as the Adapter Properties grid in the New Adapter wizard. See Adding Adapter Properties for instructions on using the Operator Properties grid.
- Method to control enablement of UI widgets
-
The wizard always generates stub code for methods that include init(), shutdown(), typecheck(), and processTuple() in the class that implements your adapter. When you select this checkbox option, the wizard also generates stub code for each property you added in the Operator Properties section. These methods enable or disable each defined property depending on conditions you specify in code. Disabled properties are dimmed in the Operator Properties tab of the Properties view for your operator's icon. You might can use this feature to configure a set of related properties, for example, enabling one property only if another property in the group is enabled.
In a set of two properties, one property might provide a checkbox in which the operator's user specifies whether or not to filter a stream, while the second property provides a text box in which the user specifies the string to filter against. In this case, you can enable the text box property only if the check box property is currently enabled.
This control is enabled by default, but it is dimmed until you have added at least one property in the Operator Properties section of this dialog. When enabled, the wizard generates code stubs for getting and setting each defined property and for enabling/disabling its widget. If you disable the control, you will need to provide your own methods for these purposes.
After completing the second page of the New StreamBase Operator wizard, complete the process with these steps:
-
When you are done adding properties on the second page, click
.The wizard generates two Java files: one containing an operator class, the other, a beaninfo class. The class generated for the operator extends
com.streambase.sb.operator.Operator
. The beaninfo class file lets you customize your operator further, if necessary. -
The wizard opens the primary class file for editing, then prompts you to refresh the project's typecheck environment. The first time you run the wizard, it automatically refreshes the typecheck environment so that the new operator's icon will appear in the Palette view.
Tip
You must refresh the typecheck environment again every time you make changes to the operator's Java code. Do this by pressing Ctrl+F5 (or by right-clicking the project's name in the Project Explorer and selecting > from the context menu).
-
Next, provide Java code for all places marked
// TODO
in the generated operator class file to implement the class. -
A default icon for your new operator now appears in in the Project folder within the Insert an Operator or Adapter dialog. Invoke this dialog by dragging the Adapters, Java Operators icon from the Operators and Adapters drawer of the Palette view to the canvas. Add an instance of your operator to the canvas by selecting your operator's icon in the dialog and clicking .
Tip
You can provide your own 32x32 PALETTE_ICON_LARGE icon for the operator and register it using the API method
getIconResouce()
. See Methods for Studio Presentation.
-
For details about using the StreamBase API for Java operators, start in Creating Custom Java Operators in the StreamBase API Guide.
-
For the Java Client library Javadoc, see the API References topic of the StreamBase Reference Guide.
-
Using Java Operators in the Authoring Guide describes how to add your completed Java operator to an EventFlow application.
This topic explains how to use the StreamBase API to create your own custom Java operators for use in StreamBase applications.
Note
StreamBase Studio ships with new projects configured by default to build with Java 11, targeting Java 11 for client APIs.
This topic assumes that you used the StreamBase Java Operator wizard to generate the initial starter code for your operator, following the development process recommended in Developing Java Operators.
To understand how Java operators are used, we also recommend that you run the Java
Operator sample, view the source for StringCase.java
,
and see the sample's
documentation. Examples in this topic are based on the Java Operator sample. To
load this sample into StreamBase Studio, use > and select javaoperator
from the
[Extending StreamBase]
category.
The following sections describe the methods available in the Java Operator API, the steps for defining a custom operator, and walks through the creation of a sample Java operator. For additional details, refer to the Operator package's Javadoc and the description of the Java Operator's Properties view in the Authoring Guide.
Use the following methods of the Operator class to manage how an instance of your operator behaves on the EventFlow Editor canvas:
-
Call
Operator.setPortHints(int, int)
in your operator's constructor to set the initial number of ports when your operator is first placed on the canvas. -
Call
Operator.setDisplayName(String)
in your constructor to set a user-friendly name for your operator. This name is used in the Operator Name field in the Properties view, and as the details text in the Palette view's Details mode. -
Call
Operator.setShortDisplayName(String)
in your constructor to set a short name for your operator. This name is used as the operator's name in the Insert Java Operators dialog and shows above the operator on the EventFlow canvas. -
Override
Operator.getPortCounts()
if you change the number of ports based on end-user setting properties. -
Override
Operator.getIconResource(Operator.IconKind)
if you want your operator to appear on the canvas with a custom icon. -
During
Operator.typecheck()
, throwOperator.PropertyTypecheckException
instead ofTypecheckException
to allow Studio to decorate your operator icon with an overlay to indicate its warning or error state. See thePropertyTypecheckException
class and theOperator.getLocation()
method for details. -
See the
UIHints
class andParameterizable
interface for information on additional control over the display of properties in Studio's Properties view.
For the latest version of this list, see the Special Studio Considerations section of the Javadoc for the Operator class.
The StreamBase Java Client library for custom operators extends the following packages in the library:
-
com.streambase.sb.operator
-
com.streambase.sb.operator.parameter
Like any other StreamBase operator, Java Operators may have properties that you can customize in StreamBase Studio. You must modify the initial properties generated by the StreamBase Java Operator wizard.
Each Java Operator class has an Object that
implements the com.streambase.sb.operator.Parameterizable
interface. This
Parameterizable Object has getter/setter accessor
methods that are used in the StreamBase Studio Properties view. The Parameterizable object is actually a JavaBean as defined in the
java.beans package. StreamBase finds the Parameterizable Object by calling the Operator.getParameters
method on an instance of the Java
Operator class.
The Java Operator class can either implement the Parameterizable
interface directly, or delegate to another
object that implements the interface. The default Operator
constructor assumes that this is the case. Another
Operator
constructor that has a Parameterizable
argument also exists. There is also
an Operator.setParameters
method that can be used
to set the Operator's Parameterizable
Object. In any
case, all Java Operators must have a
public default constructor.
Properties are declared by implementing get and set accessor methods. Here is a
code fragment of an Operator
class with some
properties:
public class Example extends Operator implements Parameterizable { private int startCount = 1; private boolean clever = true; private String [] stockSymbols; private String name; public void setStartCount(int i) {startCount = i;} public int getStartCount() {return startCount;} public void setClever(boolean b) {clever = b;} public boolean isClever() {return clever;} public void setStockSymbols(String [] ss) {stockSymbols = ss;} public String [] getStockSymbols() {return stockSymbols;} public void setName(String s) {name=s;} public String getName() {return name;} public void typecheck() throws TypecheckException {} public void processTuple(int inputPort, Tuple t) throws StreamBaseException { } }
The example Operator
class above declares four
properties:
-
startCount
-
clever
-
stockSymbols
-
name
These properties will appear in StreamBase Studio's Properties view for an instance
of this operator. Notice that the reader accessor method for a boolean property can
be named either getPropertyName
, isPropertyName
, or hasPropertyName
.
StreamBase currently supports the following property types:
-
int
-
long
-
double
-
timestamp
-
boolean
-
String
-
String[]
-
Map <string><string>
-
enum
-
ResourceFile
-
Schema
The only way to create an Enum property is to
declare it as a String property in the Java
Operator class and define the enumeration values in a BeanInfo
class, as in the example below.
All but the last two are simple property types that StreamBase derives
automatically by looking at the signatures of the getter/setter methods in the
Parameterizable
class. These can be specified in
the BeanInfo
class with SBPropertyDescriptor
objects, as in the example above.
Enum properties are string properties that can only take on a specified set of values. ResourceFile properties are similar to Enum properties, but their value must be the name of a resource. In StreamBase Studio, this is enforced by displaying a drop-down list of files available from your project's folder.
Because both Enum and ResourceFile properties are implemented as Strings, their
getter and setter methods must return and expect objects of type String,
respectively. Thus, these property types cannot be automatically derived by
StreamBase. To use these properties, an adapter must have an accompanying
BeanInfo
class that returns the SBPropertyDescriptor
subclasses EnumPropertyDescriptor
or ResourceFilePropertyDescriptor
in its list of PropertyDescriptor
s.
The BeanInfo
class is described in the
java.beans.BeanInfo
API documentation. It can be
used by the Parameterizable
object to control
what properties are exposed; add additional metadata about properties, such as
which properties are optional; and access special types of properties that can
not be automatically derived via reflection. If a BeanInfo
class is present, only the properties explicitly
declared in this class will be exposed by StreamBase.
The easiest way to make a BeanInfo class is to create a class that you name by
appending BeanInfo
to the Parameterizable
class name. Thus if the Parameterizable class
is called OpParams
, the corresponding BeanInfo
would be OpParamsBeanInfo
(in the same package as OpParams) and
extending java.beans.SimpleBeanInfo
.
The following example BeanInfo
class changes the
Name property to an enum and makes the Clever
property optional:
public class ExampleBeanInfo extends SimpleBeanInfo { public PropertyDescriptor [] getPropertyDescriptors() { try { SBPropertyDescriptor [] p = { new SBPropertyDescriptor("StartCount", Example.class), new SBPropertyDescriptor("Clever", Example.class).optional(), new EnumPropertyDescriptor("Name", Example.class, new String [] { "Tom", "Dick", "Harry" }) }; return p; } catch(Exception e) { System.out.println("Exception: " + e); e.printStackTrace(); } return null; } }
Note that the optional()
method shown in this
example simply marks the descriptor as optional.
Java Operators can also change their number of input and output ports. If this is
done by setting property values, the property's setter method should call
setPortHints
with the new number of ports. Output
ports are automatically configured by calling setOutputSchema
. Operators may ensure the correct number of
input ports in their typecheck
method by calling
the requireInputPortCount
method.
Be sure to see the Special Studio Considerations section of the Javadoc for the Operator class in the StreamBase Java Client Library.
For example:
/** * This operator has two integer parameters, many input and many output ports */ public class RoundRobinOperator extends Operator implements Parameterizable { private int _numOutputPorts = 1; private int _nextOutputPort = 0; private int _numInputPorts = 1; public RoundRobinOperator() { setPortHints(_numInputPorts, _numOutputPorts); } public int getInputPortNumber() {return _numInputPorts;} public void setInputPortNumber(int i) { _numInputPorts = i; setPortHints(_numInputPorts, _numOutputPorts); }
public int getOutputPortNumber() {return _numOutputPorts;} public void setOutputPortNumber(int i) { _numOutputPorts = i; setPortHints(_numInputPorts, _numOutputPorts); } public void init() throws StreamBaseException { System.out.println("RoundRobinOperator.init"); } public PortCounts getPortCounts() { return new PortCounts(_numInputPorts,1); }
public void typecheck() throws TypecheckException { System.out.println("RoundRobinOperator.typecheck"); Schema s = null; StringBuffer errorMessage = new StringBuffer(); if(getInputPortCount() <= 0) { throw new TypecheckException("Invalid Number of Input Ports: " + getInputPortCount() + " must have at least 1"); } System.out.println("RoundRobinOperator.typecheck: requiring inputs: " + _numInputPorts); requireInputPortCount(_numInputPorts); for(int i = 0; i < getInputPortCount(); ++i) { Schema inputSchema = getInputSchema(i); if(s == null) { s = inputSchema; } else if(!s.sameFieldTypes(inputSchema)) { errorMessage.append("Invalid schema on port " + i + "\n"); } }
if(errorMessage.length() > 0) throw new TypecheckException(errorMessage.toString()); System.out.println("RoundRobinOperator.typecheck: input schemas ok"); System.out.println("input port num " + getInputPortNumber() + " output port num " + getOutputPortNumber()); s = getInputSchema(0); for(int i=0; i < getOutputPortNumber(); ++i) { setOutputSchema(i, s); } System.out.println("RoundRobinOperator.typecheck: done"); } public void processTuple(int inputPort, Tuple t) throws StreamBaseException { sendOutput(_nextOutputPort, t); _nextOutputPort = (_nextOutputPort + 1) % _numOutputPorts; } }
As mentioned in Methods for Studio Presentation, when
typechecking fails, your custom operator or adapter should throw Operator.PropertyTypecheckException
instead of TypecheckException
to allow Studio to decorate your operator
icon with an overlay to indicate its warning or error state.
More importantly, because typechecking is performed so frequently, it should be efficient. Each typecheck method you create should:
-
Execute quickly
-
Do the same thing every time it is called
That means your typecheck methods should not:
-
Perform extensive or large file I/O
-
Establish database connections
That is, the only side effect typechecking should have is to throw an exception.
Use init()
to open files and connect to databases.
However, do not perform typechecking from an init()
method, as it is executed by the server, and not within StreamBase Studio.
The Java Operator class has the following life cycle. Note that this section describes the life cycle within the StreamBase engine:
-
Constructor
All Java Operators must have a public default constructor. The
Constructor
is called when theOperator
instance is created, but before theOperator
is connected to the StreamBase application. We recommended that you set the default Input port and Output port count in theConstructor
with thesetPortHints(inPortCount, outPortCount)
method. The default is 1 input port, 0 output ports.In general, you can set any operator property (for example schemas) in a constructor. However, if you do not want StreamBase Studio to overwrite these properties, do not declare them when designing the component in the Java Operator Wizard.
-
typecheck
The
typecheck
method is called after theOperator
instance is connected in the StreamBase application, allowing theOperator
to validate its properties. TheOperator
class may change the number of input or output ports by calling therequireInputPortCount(portCount)
method or thesetOutputSchema(schema, portNum)
method. If theverifyInputPortCount
method is passed a different number of ports than the Operator currently has, aPortMismatchException
(subtype ofTypeCheckException
) is thrown.Call the
getResourceContents
method during typecheck, instead of waiting until start or run to call it. This is to ensure that StreamBase Studio can indicate to the user whether it was able to find the resource during authoring, and avoid waiting until streaming node fails silently.Recall that if your constructor sets adapter properties that Studio also manages (via a beaninfo class), those properties will be overwritten at typecheck time.
-
init
If
typecheck
succeeds, theinit
method is called before the StreamBase application is started. Note that your Operator class is not required to define theinit
method, unless (for example) you need to perform initialization of a resource such as a JDBC pool, if your operator is making JDBC calls. -
processTuple
The
processTuple
method is called when a tuple is available for processing. -
shutdown
The
shutdown
method is called when the StreamBase Server is in the process of shutting down.
A Java operator runs in the same process as the StreamBase application that contains it. One advantage of this is that when the StreamBase application starts or stops, any Java operators or embedded adapters in it start and stop along with it. More generally, the application and these components undergo life cycle changes in a synchronized fashion.
Java operators undergo life cycle changes in a prescribed order. Typically, when a StreamBase application is represented in StreamBase Studio, data flows through the application from left to right. Here, the order in which operators undergo life cycle events is described as being either “left to right”, or “right to left”, where “left to right” means in the same direction as data flows through the module. “Right to left”, on the other hand, means that Java operators will undergo some life cycle change in the opposite order as they will see data.
Life cycle changes that a StreamBase application undergoes include starting, pausing, resuming, and shutting down. During starting and resuming, operators are processed in right to left order. This means that operators start in an order that is opposite to that in which they will receive data. Conversely, operators are paused and stopped in left to right order, or in the same order as they will receive data.
Java operators start, pause, resume and shutdown along with the StreamBase application that contains them. It is also possible to suspend and resume Java operators independently of their StreamBase application.
This is accomplished with the same commands that are used to suspend and resume a StreamBase application as a whole. The command sbadmin suspend can be used to suspend an application; similarly, sbadmin resume is used to resume a StreamBase application.
To suspend or resume individual operators, you can append a list of Java operators to the sbadmin suspend or sbadmin resume command. If one or more strings are appended to sbadmin suspend, then the StreamBase application as a whole will not be suspended, rather the individual Java operators named by the appended strings will be suspended.
Note that an individual Java operator can be suspended or resumed only if the StreamBase application itself is running. An individual Java operator can be running only if the application that contains it is also running. Therefore, it is not meaningful to suspend or resume an operator that is not currently running if the application that contains it is not running.
The sbc status command returns status information about the StreamBase Server.
The sbc status --operators command returns the status of any Java operators contained by the server's application. Note that sbc status --operators and sbc status are disjoint commands: sbc status returns information about the server only, not about Java operators contained in the server. Similarly, sbc status --operators returns information about contained Java operators only, and not any information about the server itself.
In this context, the status of a Java operator consists only of its current
state. For example, if a Java operator has been started and is currently running,
its state will be STARTED
. If a Java operator has
yet to be started, its state will be NONE
. If a Java
operator has been suspended, its state will be either SUSPENDED_AND_DROPPING_TUPLES
or SUSPENDED_AND_PROCESSING_TUPLES
. Lastly, if an operator has been
shut down its state will be SHUTDOWN
.
By default, a Java operator starts along with the StreamBase application that
contains it. In Studio, in the General tab for Java operators, there is a
checkbox labeled Start with application. By
default, this box is selected, meaning that the Java operator will start with the
application. Clearing this checkbox causes the operator to be left in the
NONE
state when the application starts.
A Java operator that does not start with its application will stay in the
NONE
state until it is explicitly started with the
sbadmin resume operatorName
command. Such an
operator will not start even if the application as a whole is resumed. So for
example, the application as a whole may suspend and then resume. This will have
no effect on an operator that has not started with its application.
If a Java operator is suspended separately from the application that contains it, tuples might still arrive at the suspended operator. You can configure the Java operator to handle these tuples in two different ways:
-
A suspended Java operator can choose to drop tuples that are delivered to it.
-
The operator can choose to process these tuples.
These two possibilities are represented by static Strings on the class com.streambase.sb.operator.Operator
, SUSPENDED_AND_DROPPING_TUPLES
and SUSPENDED_AND_PROCESSING_TUPLES
, respectively. A Java operator
is configured to either drop or process tuples by calling the method setSuspendBehavior
on its instance. setSuspendBehavior
takes an int
argument, the value of which must be either
SUSPENDED_AND_DROPPING_TUPLES
or SUSPENDED_AND_PROCESSING_TUPLES
.
This section steps you through the creation of a sample Java Operator class,
StringCase.java. This example is kept deliberately simple, to allow you to focus on
the API without having to read other lines of code. The Java Operator is used in a
StringCase.sbapp
application to simply map string
input to lowercase or uppercase. The files that comprise the sample, including the
StringCase.java
file discussed here, are installed
with StreamBase in the sample/javaoperator
directory.
Before beginning this exercise, open StreamBase Studio and load the javaoperator
sample, as described in Custom Java Operator Sample. This creates the sample_javaoperator
project in your Project Explorer. In this
project, double-click StringCase.java
to open it in
the Java Editor.
In an editor, we started by adding these import statements in StringCase.java:
import com.streambase.sb.DataType; import com.streambase.sb.Schema; import com.streambase.sb.StreamBaseException; import com.streambase.sb.Tuple; import com.streambase.sb.operator.Operator; import com.streambase.sb.operator.Parameterizable; import com.streambase.sb.operator.TypecheckException; import java.util.Arrays;
Next, we declared the class by extending the StreamBase Operator class. For example:
public class StringCase extends Operator implements Parameterizable {
In the constructor, we defined two constants for an enum property, conversionType
. In this example, we defined the metadata for the
enum property in a Java bean, the StringCaseBeanInfo class. For example:
// // Constants for enum property conversionType // public static String UPPER = "Uppercase"; public static String LOWER = "Lowercase"; /** Enum property, metadata defined in StringCaseBeanInfo.java */ private String conversionType = LOWER;
Note
The source for StringCaseBeanInfo is Stepping through StringCase.java. You
can find it in the sample/javaoperator
directory
in the StreamBase installation.
Next we declare the Java Operator's input and output, and an array for fields in the schema. For example:
private Schema inSchema; // input to this operator private Schema outSchema; // output from this schema private Schema.Field[] fields; // individual fields in the schema
Then we use the setPortHints
method to specify a
fixed number of input and output ports:
public StringCase() { // this operator has one input and one output setPortHints(1, 1); }
Note
If the Java Operator will take a variable number of output ports, use the
Parameterizable
interface and the
typecheck
method. There must be a parameter for
the number of input and output ports. Within typecheck
, you must specify a setOutputSchema
for each port, so that StreamBase Studio
knows how many square black dots to draw for the output ports. If you do not
use setOutputSchema
for each port, the Java
Operator on the StreamBase Studio canvas will not display the correct number of
black dots.
Next, we set up the typecheck
method for the
class, added exception handling, and declared that the schema of the output is
the same as for the input:
public void typecheck() throws TypecheckException { // require exactly one input port requireInputPortCount(1); // the input must contain at least one string field inSchema = getInputSchema(0); fields = inSchema.getFields(); int stringCount = 0; for(int i=0; i < fields.length; ++i) { DataType dt = fields[i].getDataType(); if(DataType.STRING.equals(dt)) { ++stringCount; } } if (stringCount==0) throw new TypecheckException( "At least one string field is required"); // the output schema is the same as the input setOutputSchema(0, inSchema); outSchema = inSchema; }
Finally we defined the work that the custom Java operator will perform, by using
the processTuple
method. For example:
public void processTuple(int inputPort, Tuple t) throws StreamBaseException { Tuple out = outSchema.createTuple(); for(int i=0; i < fields.length; ++i) { Schema.Field f = fields[i]; DataType dt = f.getDataType(); String fname = f.getName(); if(DataType.STRING.equals(dt)) { String str = t.getString(f); if(LOWER.equals(conversionType)) { out.setString(fields[i], str.toLowerCase()); } else if(UPPER.equals(conversionType)) { out.setString(fields[i], str.toUpperCase()); } } else { out.setField(fields[i], t.getField(fields[i])); } } sendOutput(0, out); } public String getConversionType() {return conversionType;} public void setConversionType(String s) { conversionType = s; } }
StringCaseBeanInfo.java
is the BeanInfo
class for the StringCase operator. StringCaseBeanInfo
defines the metadata for the properties
that will appear in the StreamBase Studio Properties view for this Java operator.
The StringCase operator has only one property, conversionType, which is an enum whose values are defined in
the StringCase
class.
Now, open StringCaseBeanInfo.java
and examine it.
First we import these classes:
import java.beans.PropertyDescriptor; import java.beans.SimpleBeanInfo; import com.streambase.sb.operator.parameter.EnumPropertyDescriptor; import com.streambase.sb.operator.parameter.SBPropertyDescriptor;
And define the bean as follows:
public class StringCaseBeanInfo extends SimpleBeanInfo { public PropertyDescriptor [] getPropertyDescriptors() { try { SBPropertyDescriptor [] p = { new EnumPropertyDescriptor("ConversionType", StringCase.class, new String [] { StringCase.UPPER, StringCase.LOWER }) }; return p; } catch(Exception e) { System.out.println("Exception: " + e); e.printStackTrace(); } return null; // should never happen } }