Short description: Create Flink-ESB application offering 4 HTTP services to read / insert / update / delete customer data in the database.
Customer data is stored in the database in one table, called CUSTOMER.
In the fourth part of the tutorial we will:
create a route called "delete-customer" to delete data from the database >>
set up a Validate component within a route to check presence of numeric "id" message property >>
set up a Data writer component within a route to run DELETE SQL statement, injecting value of bind variable from message property "id" >>
set up a Transformer component within a route to output data in XML format >>
set up a Catch Exception and a Transformer components within a route to create an error handler outputting data in custom format >>
set up an Exclusive Gateway to check status of DB delete, and either send a message to "Transformer" (if data was deleted), or to "Throw Exception" component >>
set up a Throw Exception component within a route to raise an exception in case no data in DB is found >>
test a route in Flink-ESB Admin Console >>
create a route, handling HTTP DELETE request and calling another route, which deletes data from the database >>
set up a REST Receiver starting component within a route to start route on every incoming HTTP DELETE request >>
set up a Call Subflow component within a route to call "delete-customer" subflow >>
test HTTP DELETE service >>
add "Content-Type" HTTP header to HTTP DELETE response >>
Following Flink-ESB components are used in this part of tutorial:
First level components:
Route : represents a sequence of activities, performed upon the message. Route contains route node components connected with links. Route node activities and links define the functionality of the route. Route can either have a starting event (received HTTP request, timer etc.), or it can be called from other routes (in this case such route is called subflow).
Subflow : starting route node, used to mark beginning of the subflow. Subflow is kind of route, which does not have its own trigger (HTTP request, timer etc.). Every route, that does not have a specific starting event, must start with this component.
Validate : route node, used to validate a message. Can parse XML against schema file, and/or validate against one or multiple custom rules.
Transformer : used to transform a message in different format.
Data writer : used to run INSERT, UPDATE or DELETE SQL statements in the database. Must refer to "DB Connection Pool".
Throw Exception : used within a route to throw a custom exception. It is always the last route node component within a sequence flow. It does not have outgoing connection links.
Catch Exception : used within a route to create a separate processing flow, which is triggered in case exception is thrown.
REST Receiver : starting route node, used always at the begin of the route as starting event. Must refer to "HTTP Server". Triggers after receiving HTTP request with configured HTTP method + URI
Call Subflow : used to call a subflow (another route, which has a "Subflow" component as a starting event).
Go to Flink-ESB Editor. After finishing part 3 of the tutorial you should have an application looking similar to the one on picture below:
You should have a DB connection pool, HTTP server, HTTP connector and six routes with names "get-customer", "insert-customer", "update-customer", "http-get-customer", "http-insert-customer" and "http-update-customer".
Click on "ESB General" palette drawer to expand it, and place a new "Route" on editor canvas.
Give a route name "delete-customer":
Before adding components to the route, let us think about the functionality of this route. To delete a record in tha CUSTOMER table, all we need is CUSTID. Therefore input should be: message property "id", not XML. Then DELETE SQL statement should be executed trying to delete a record where CUSTID matches message property "id". If it will be deleted, an XML containing CUSTID and STATUS="OK" should be returned. If no data in DB found for a given CUSTID, a route should raise an exception "No customer found for id ...". Also there must be an error handler, catching all thrown exceptions, and transforming them to the output XML, containing CUSTID, STATUS and ERROR.
This functionality is very similar to the functionality of "update-customer" route. The only difference is: "update-customer" expects as input XML payload and message property "id". "delete-customer" expects as input message property "id".
So let us add the same components to "delete-customer" as we used for "update-customer". The route should like on the picture below:
Select "Validate" component in the Editor, and click on "Rules" tab in the properties window. Click "Add Rule" and type property['id']!=null in "Rule-Expression" field. Click "Add Rule" again and type the second expression: Integer.valueOf(property['id'])!=null. Click "Add Rule" again and provide the third expression: property['id']>0:
Press "Save Changes". Select "Data writer" and enter its properties as below: "DB-Connection-Ref" : db, "SQL" : 'delete from customer where custid=?':
Click "Save Changes", then click "Bind Variables" tab, press "Add Parameter" button and enter data: "Param-Type" : NUMERIC, "Param-Value" : property['id'].
Bind variable should look like on picture below:
Click "Save Changes". Now select a "Transformer" connected with an "Exclusive Gateway" and enter its properties like following: "Type" : custom, "Custom-Expression" :
'<DeleteCustomerResult> <custid>'+property['id']+'</custid> <status>OK</status> </DeleteCustomerResult>'
Press "Save Changes". Now select a "Transformer" component connected to "Catch Exception". Enter its properties like following: "Type" : custom, "Custom-Expression" :
'<DeleteCustomerResult> <custid>'+property['id']+'</custid> <status>ERROR</status> <error>'+escapeXml(error.getMessage())+'</error> </DeleteCustomerResult>'
Click "Save Changes". Select connection link between "Exclusive Gateway" and "Throw Exception", select "gateway Condition" tab in properties window, unselect "Default condition" checkbox, and type following into the textbox: property['db.update.count']==0
Press "Save changes". See, how the shape of connection link changes: a small diamond should appear, which means, there is a condition for passing this link.
Select "Throw Exception" component and type following expression in "Message" textbox: 'No customer found for id='+property['id']:
Press "Save Changes", save file and restart the application.
Go to browser any type following URL: http://localhost:4545/customer?id=5. You should get a response from "http-get-customer" route as on picture below:
No go to Flink-ESB Admin Console in the browser, use for this following URL: https://localhost:8443/console/start. Login to Flink-ESB Admin Console with default username/password: admin/admin. Click on "Application Overview" to expand it, then click on triangle on the left side of instance name. Now you should see an application with name "customer-api". Click on the small triangle to expand components of the project. Click on "Routes" to expand it. Now you should see a route with name "delete-customer". Click on it to see its details on the right side of Admin Console:
Click "Call Route" tab. Enter following expression in "Properties" textbox: [ 'id' : 5 ].
Press "Call" button. You should get response, as on picture below:
Now try again URL: http://localhost:4545/customer?id=5. This time you should get an error message:
Try calling "delete-customer" in Flink-ESB Admin Console again using the same properties expression: [ 'id' : 5 ]. Now response should be as on picture below:
Now try calling "delete-customer" providing invalid CUSTID (negative integer, not numeric value, zero). You should get a response XML with status ERROR and proper error message.
Go to Flink-ESB Editor and create another route. Call it "http-delete-customer".
Place "REST Receiver" from "HTTP Adapter" palette, and then "Call Subflow" from "ESB General" palette within a new route. Connect them as on picture below:
Select "REST Receiver" and enter its properties as on picture below: "HTTP-Server-Ref" : http-server, "Url" : /customer, "HTTP-Method" : DELETE:
Press "Save changes". Now select "Call Subflow" component and enter its properties as below: "Flow-Ref" : delete-customer:
Press "Save changes" and save the file
Restart the application in Flink-ESB Editor.
To test HTTP DELETE request we could use either some browser plugin, or SoapUI, or any other tool, which is able to call HTTP DELETE. I will use "curl" command.
To call HTTP DELETE service with "curl" use this command:
curl -k -i -X DELETE http://localhost:4545/customer?id=4
Calling this command you should get a valid XML response with status OK:
Repeat the same command (for the same id), and now you should get:
Now try running this command using invalid id, and check the result:
Since "http-delete-customer" always outputs XML, we should make sure to provide a proper "Content-Type" HTTP header with each response.
Go to Flink-ESB Editor and select "REST Receiver" within "http-delete-customer" route. Click "HTTP Headers" tab in properties window, and press "Add Header" button. Enter data as on the picture below: "Header-Name" : Content-Type, "Header-Value" : 'text/xml; charset=UTF-8':
Press "Save changes", save the file and restart the application.
Now call curl command again:
curl -k -i -X DELETE http://localhost:4545/customer?id=3
This time you should get a proper XML response, containing "Content-Type" HTTP Header:
So now we have all 4 working services to read customer data with HTTP GET, created in part 1 of the tutorial; to insert new customer data with HTTP POST, created in part 2 of the tutorial; to update existing customer data with HTTP PUT, created in part 3 of the tutorial; and to delete customer data with HTTP DELETE.
The application in Flink-ESB Editor should look now similar to the one on the picture below: