This example is the simplest that we can create because this example don't create any component and don't configure anything, just execute Tubo with default configuration.
Tubo by default create a echo service used to ping the instance. To make this appends by default there are some components preconfigured and a echo flow supporting service.
This service is a socket service listen on a port, when a client connect to this a welcome message is sended to client, and each line than is readed from client is sended back to him. If the line "bye" is readed, a goodbye message is sended to client and the connection is closed.
To support this service two components are created:
Consume phase strategy is based on a consumer component ServerSocketLineReaderConsumer which use a ServerSocket listen on a port. When a new connection arrives the component generate a event and begin to read the input stream line by line. Each line generate a new event and when the line readed match with the goodbye word then the goodbye event is generated.
Each event is processed by the consumer life cycle activating an executing a determinated Flow. Event consept is used to show a determinated activity or "event" has happened on some component, in this case on Consumer. To share data the event originator or any component can use Item properties.
Don't forget than Tubo is based on Pipeline Arquitecture. On this Arquitecture a set of nodes (aka Components) are conecteds one to anothers making a king of pipeline or node flow. Each conection between nodes is made of data (aka Item), and each node transform this data. Each Node have an Input and a Output (in a traditional point of view).
This component fire tree kinds of events and use two properties, one to send readed input line to flow, and one to write the output message generated on flow.
NEW_CONNECTION_EVENT | This event is fired when a new connection is created, given the posibility of write a welcome message. Properties: SSLINEREADER_INPUT: This property is setted null by Consumer before fire the event. SSLINEREADER_OUTPUT: This property is used by components on flow to store the output message. |
READ_LINE_EVENT | This event is fired when a new line is readed. Properties: SSLINEREADER_INPUT: This property is setted with the line readed. SSLINEREADER_OUTPUT: This property is used by components on flow to store the output message. |
GOODBYE_EVENT | This event is fired when a goodbye word is readed. After this event is processed the connection will be closed. Properties: SSLINEREADER_INPUT: This property is setted with the line readed. SSLINEREADER_OUTPUT: This property is used by components on flow to store the output message. |
This consumer create a socket with client, and consume input line by line. Because the socket between client and consumer is a statefull condition, the consumer assigned will be free when the conection is closed (is implemented in this way, not is the only way!) componentClassname="org.tubo.resource.component.transform.SimpleTransformComponent" type="singleton"
Will see than this consumer is listening at port 6666 with a concurrency of 3 (three client connections can be procesed at time), if the three consumers are busy (because are three connections open) then the next clients they will be able to create connections but will be blocked waiting for next free consumer.
The process cut condition is configured on goodbye-words property. In this case, the connection will finish if client send "bye" or "." words.
<consumer id="tubo-echo-consumer" consumerClassname="org.tubo.resource.consumer.serversocketlinereader.ServerSocketLineReaderConsumer" type="pooled" maxCapacity="3" > <property> <prop-name>ports</prop-name> <prop-value>6666</prop-value> </property> <property> <prop-name>goodbye-words</prop-name> <prop-value>bye,.</prop-value> </property> </consumer>
This component is really simple, have three executional methods than can be mapped to listeners and two properties, one for input and one for output.
sayHelo | This method is used by the listener of the NEW_CONNECTION_EVENT event. Properties: ECHO_OUTPUT: In this property put the Hello Message |
execute | This is the default executional method for components, when a component don't listen a particular event this method is executed. This echo component use this method for copy input on output. Properties: ECHO_INPUT: Input ECHO_OUTPUT: Output |
sayGoodbye | This event is fired when a goodbye word is readed. After this event is processed the connection will be closed. Properties: ECHO_INPUT: Input ECHO_OUTPUT: Goodbye message. |
This is the code of Echo component.
public class EchoComponent extends BaseComponentImpl { public static final String RCS_ID = "$Id: EchoComponent.java 54 2006-11-08 14:02:18Z maldito_orco $"; private static Log log = LogFactory.getLog(EchoComponent.class); public static final String ECHO_INPUT_PROPERTY = "ECHO_INPUT"; public static final String ECHO_OUTPUT_PROPERTY = "ECHO_OUTPUT"; public void sayHelo(FlowContext flowContext) throws TuboException { flowContext.getItem().setProperty(ECHO_OUTPUT_PROPERTY,"helo"); } public void sayGoodbye(FlowContext flowContext) throws TuboException { flowContext.getItem().setProperty(ECHO_OUTPUT_PROPERTY,"goodbye"); } public void execute(FlowContext flowContext) throws TuboException { // // get item Item item = flowContext.getItem(); // // get input String input = (String)item.getProperty(ECHO_INPUT_PROPERTY); // // put input in output item.setProperty(ECHO_OUTPUT_PROPERTY,input); } }
This is the definition of Echo Component
<component id="tubo-echo-component" componentClassname="org.tubo.resource.component.echo.EchoComponent" > </component>
Because the Consumer output property name and Echo input property name don't match we need a simple transformation to make input available to Echo and output availavble to Consumer.
This is the code of Echo component.
public class SimpleTransformComponent extends BaseComponentImpl { public static final String RCS_ID = "$Id: SimpleTransformComponent.java 78 2006-12-15 21:37:36Z maldito_orco $"; private static Log log = LogFactory.getLog(SimpleTransformComponent.class); public void execute(FlowContext flowContext) throws TuboException { // // get item Item item = flowContext.getItem(); // // int i=0; String transform = null; do { // // get i-esima transformation String ti = "t"+i; transform = (String)item.getProperty(ti); // // if i-esima transformation is null then is cut condition if (transform!=null) { // // parse transformation int inx = transform.indexOf("->"); String from = transform.substring(0,inx).trim(); String to = transform.substring(inx+"->".length(),transform.length()).trim(); // // transform Object value = item.getProperties().remove(from); item.setProperty(to,value); // // increment i i++; } // // check cut condition } while (transform!=null); } }
This is the definition of Transformation
<component id="simple-transform" componentClassname="org.tubo.resource.component.transform.SimpleTransformComponent" type="singleton" > </component>
A Flow is a pipeline of components with zero, one or more Consumers on beginning and zero, one or more Nodes to execute.
A Node in a flow can be a Component or a Flow.
<flow id="tubo-echo-flow"> <consume> <from refId="tubo-echo-consumer" /> </consume> <node-list> <!-- transform input ss to input echo--> <component-node refId="simple-transform"> <property> <prop-name>t0</prop-name> <prop-value>SSLINEREADER_INPUT->ECHO_INPUT</prop-value> </property> </component-node> <!-- execute echo --> <component-node refId="tubo-echo-component"> <listen> <event> <action>NEW_CONNECTION_EVENT</action> <execute>sayHelo</execute> </event> <event> <action>GOODBYE_EVENT</action> <execute>sayGoodbye</execute> </event> <!-- by default if not defined listens or not matched events, method 'execute' is invoked --> </listen> </component-node> <!-- transform output echo to output ss--> <component-node refId="simple-transform"> <property> <prop-name>t0</prop-name> <prop-value>ECHO_OUTPUT->SSLINEREADER_OUTPUT</prop-value> </property> </component-node> </node-list> </flow>