Because our company uses a variety of programming languages for development, I looked for a mechanism for integrating WEE into these other environments. My goal was to end up with something as shown below.
My investigation discovered that there were several good alternatives, but the Apache Thrift seemed best because of its broad programming language support and general features. Documentation for Thrift is very spotty and inconsistent and it was a struggle to get all the pieces and parts working together. I strongly recommend the online document Thrift: The Missing Guide for anyone else attempting to do this. Apache Thrift is actually quite simple to use and I realize now that I was making things much harder than they needed to be.
The first step in using Thrift is to develop a specification of what the remote service and data structures will look like. In the example shown below, a structure named Rule is defined with three elements named filename, contextList, and rules. The remote application will provide one service named run with the Rule structure as the payload.
/*
This file contains the definition of an Apache Thrift service for executing rules using the
Workflow Execution Engine (WEE).
Version 1.0 - June 2012
*/
struct Rule {
1: optional string filename; // name of a file containing rules to run
2: optional string contextList; // array of variable names and values in Erlang list format
This file contains the definition of an Apache Thrift service for executing rules using the
Workflow Execution Engine (WEE).
Version 1.0 - June 2012
*/
struct Rule {
1: optional string filename; // name of a file containing rules to run
2: optional string contextList; // array of variable names and values in Erlang list format
3: optional string rules; // Instead of embedding rules in a file, specify the rules to run here
}
service Wee {
string run(1:Rule rule);
}
}
service Wee {
string run(1:Rule rule);
}
The next step is to compile this specification using the Thrift Compiler into the various programming languages that will act as clients or servers. Three examples are shown below for generating Erlang, PHP, and Java code bindings respectively.
thrift-0.8.0.exe -r --gen erl wee.thrift
thrift-0.8.0.exe -r --gen php wee.thrift
thrift-0.8.0.exe -r --gen java wee.thrift
The client-side code is relatively simple as shown by the following example using Erlang. First, a connection is made to the server-side code. Next, a data structure is created and populated with the appropriate values. After that, the client invokes the run service passing the data that was defined in the previous step. Finally, the connection is closed.
start(Args) ->
#options{port = Port, client_opts = ClientOpts} = parse_args(Args),
% Connect to server
{ok, Client0} = thrift_client_util:new("127.0.0.1", Port, wee_thrift, ClientOpts),
% Create data structure
RuleStruct = #rule {
filename = "c:/temp/wee_rules.txt"
},
% Call remote server
{Client01, R} = thrift_client:call(Client0, run, [RuleStruct]),
% Display results
io:format("Result ~p~n", [R]),
% Close connection
thrift_client:close(Client01).
#options{port = Port, client_opts = ClientOpts} = parse_args(Args),
% Connect to server
{ok, Client0} = thrift_client_util:new("127.0.0.1", Port, wee_thrift, ClientOpts),
% Create data structure
RuleStruct = #rule {
filename = "c:/temp/wee_rules.txt"
},
% Call remote server
{Client01, R} = thrift_client:call(Client0, run, [RuleStruct]),
% Display results
io:format("Result ~p~n", [R]),
% Close connection
thrift_client:close(Client01).
The server-side code is also simple. An example in Erlang is shown below.
handle_function(run, {Rule})
when is_record(Rule, rule) ->
when is_record(Rule, rule) ->
% extract data components
Filename = Rule#rule.filename,
ContextList = Rule#rule.contextList,
Rules = Rule#rule.rules,
Filename = Rule#rule.filename,
ContextList = Rule#rule.contextList,
Rules = Rule#rule.rules,
% do some processing here
% send reply back to client
{reply, Result}.
Note that the code shown above is the only custom-code that I needed to write. However, there is some additional boiler-plate code that is required to setup and tear down the connection, but this boiler-plate code is provided in the Apache Thrift distribution.
No comments:
Post a Comment