From: Fergus H. <fj...@cs...> - 2001-02-22 01:15:16
|
On 19-Feb-2001, Ina Cheng <in...@st...> wrote: > > +++ client_demo.m Sun Feb 18 16:23:17 2001 ... > +main --> > + io__command_line_arguments(Args0), > + { OptionOpts = option_ops(short_option, long_option, option_defaults)}, > + { getopt__process_options(OptionOpts, Args0, _Args, OptionsResult) }, > + ( > + { OptionsResult = ok(OptTable) }, > + { getopt__lookup_bool_option(OptTable, help, Help) }, > + ( > + { Help = yes }, > + options_help > + ; > + { Help = no }, > + { getopt__lookup_string_option(OptTable, host, Host) }, > + { getopt__lookup_int_option(OptTable, port, Port) }, > + { getopt__lookup_string_option(OptTable, method, Method) }, > + { getopt__lookup_string_option(OptTable, uri, URI) }, > + { getopt__lookup_string_option(OptTable, xml, XML) }, > + ( > + { XML = "" } > + -> > + ( > + { Method = "GetStockPrice" } > + -> > + { getopt__lookup_int_option(OptTable, int, Int) }, > + ( > + { Int = -1 } > + -> > + io__write_string("Parameter not supplied.\n"), > + io__write_string("Program terminated.\n") > + ; > + soap_call_mercury_type(Host, Port, Method, > + URI, [univ(Int)], Responses), > + display_mercury_response("Stockprice = ", > + Responses) > + ) > + ; > + { Method = "Hello" } > + -> > + soap_call_mercury_type(Host, Port, Method, > + URI, [], Responses), > + display_mercury_response("", Responses) > + ; > + { Method = "Add3Ints" } > + -> > + { getopt__lookup_int_option(OptTable, add1, X) }, > + { getopt__lookup_int_option(OptTable, add2, Y) }, > + { getopt__lookup_int_option(OptTable, add3, Z) }, > + ( > + % If some of the arguments are not supplied, > + % they are treated as 0. Only when all > + % arguments are not supplied, the program > + % terminates. > + { X = 0 }, { Y = 0 }, { Z = 0 } > + -> > + io__write_string("Parameter not supplied.\n"), > + io__write_string("Program terminated.\n") > + ; > + soap_call_mercury_type(Host, Port, Method, > + URI, [univ(X), univ(Y), univ(Z)], > + Responses), > + display_mercury_response("Add3Ints = ", > + Responses) > + ) > + ; > + { Method = "PurchaseBook" } > + -> > + { getopt__lookup_string_option(OptTable, title, T) }, > + { getopt__lookup_string_option(OptTable, author, A)}, > + soap_call_mercury_type(Host, Port, Method, URI, > + [univ(T), univ(A)], Responses), > + display_mercury_response("", Responses) > + ; > + io__write_string("Method not supported.\n"), > + io__write_string("Program terminated.\n") > + ) > + ; > + soap_call_xml_type(Host, Port, Method, URI, XML, > + Responses), > + io__write_string(Responses) > + ) > + ) > + ; > + { OptionsResult = error(OptionErrorString) }, > + io__write_string(OptionErrorString), > + io__nl, > + options_help > + ). That predicate is very very long. It would be much nicer to split the code for handling each different method name into a separate predicate. And rather than hard-coding the if-then-else on the message names here, you could use a table, e.g. :- type method_handler == pred(option_table, ...). :- inst method_handler == pred(in, ...) is det. :- func get_method_handler(string, method_handler). :- mode get_method_handler(in, out(method_handler)) is semidet. method_handler("PurchaseBook") = handle_purchase_book. method_handler("...") = ... soap_interface.m: > +soap_call_mercury_type(Host, Port, Method, SOAPuri, Parameters, > + Responses) --> > + ( > + { Method = "GetStockPrice" } > + -> > + { generate_SP_request(Host, Method, SOAPuri, > + Parameters, Request) } > + ; > + { Method = "Hello" } > + -> > + { generate_Hello_request(Host, Method, SOAPuri, > + Parameters, Request) } > + ; > + { Method = "Add3Ints" } > + -> > + { generate_AddInt_request(Host, Method, SOAPuri, > + Parameters, Request) } > + ; > + { Method = "PurchaseBook" } > + -> > + { generate_PB_request(Host, Method, SOAPuri, > + Parameters, Request) } > + ; > + { error("Encode: Method not supported") } > + ), It would be nice to use a table here too. I.e. soap_call_mercury_type(Host, Port, Method, SOAPuri, Parameters, Responses) --> { generate_request(Method) = Generator -> call(Generator, Host, Method, SOAPuri, Parameters, Request) ; error("Encode: Method not supported") }. :- func generate_request(string) = pred(host, port, method, uri, list(univ), list(univ)). :- mode generate_request(in) = out(pred(in, in, in, in, in, out) is det. generate_request("GetStockPrice") = generate_SP_request. generate_request("Add3Ints") = generate_Add3Int_request. ... > + % Translates XML response to Mercury types. > +:- pred decode_response(string::in, string::in, list(univ)::out) is det. > + > +decode_response(Method, XMLResponse, Responses) :- > + ( > + Method = "GetStockPrice" > + -> > + decode_SP_response(XMLResponse, Responses) > + ; > + Method = "Hello" > + -> > + decode_Hello_response(XMLResponse, Responses) > + ; > + Method = "Add3Ints" > + -> > + decode_AddInt_response(XMLResponse, Responses) > + ; > + Method = "PurchaseBook" > + -> > + decode_PB_response(XMLResponse, Responses) > + ; > + error("Decode: Method not supported") > + ). Likewise here. soap_call_mercury_type(Host, Method, SOAPuri, Parameters, Responses) --> { decode_response(Method) = Generator -> call(Generator, Host, Method, SOAPuri, Parameters, Responses) ; error("Encode: Method not supported") }. :- func decode_response(string) = pred(host, port, method, uri, list(univ), list(univ)). :- mode decode_response(in) = out(pred(in, in, in, in, in, out) is det. decode_response("GetStockPrice") = decode_SP_Response. decode_response("Add3Ints") = decode_Add3Int_Response. ... > +%-------------------------------------------------------------------------% > +% Hello > +%-------------------------------------------------------------------------% > + > + % Generates HTTP header information and SOAP message in the body. > +:- pred generate_Hello_request(host, method, uri, list(univ), string). > +:- mode generate_Hello_request(in, in, in, in, out) is det. > + > +generate_Hello_request(Host, Method, SOAPuri, Parameters, Request) :- > + generate_Hello_body(Method, Parameters, Body), > + string__length(Body, Length), > + generate_header(Host, Length, SOAPuri, Header), > + Request = insert_cr(Header) ++ Body. ... > +:- pred generate_AddInt_request(host, method, uri, list(univ), string). > +:- mode generate_AddInt_request(in, in, in, in, out) is det. > + > +generate_AddInt_request(Host, Method, SOAPuri, Parameters, Request) :- > + generate_AddInt_body(Method, Parameters, Body), > + string__length(Body, Length), > + generate_header(Host, Length, SOAPuri, Header), > + Request = insert_cr(Header) ++ Body. ... > + % Generates HTTP header information and SOAP message in the body. > +:- pred generate_SP_request(host, method, uri, list(univ), string). > +:- mode generate_SP_request(in, in, in, in, out) is det. > + > +generate_SP_request(Host, Method, SOAPuri, Parameters, Request) :- > + generate_SP_body(Method, Parameters, Body), > + string__length(Body, Length), > + generate_header(Host, Length, SOAPuri, Header), > + Request = insert_cr(Header) ++ Body. Can't that code be abstracted out? It looks like it is the same in all cases. > + % Generates SOAP message. > + % Hello pred has no input. > +:- pred generate_Hello_body(string, list(univ), string). > +:- mode generate_Hello_body(in, in, out). > + > +generate_Hello_body(MethodName, _Parameters, Body) :- > + Body = "<Envelope><Body><" ++ MethodName ++ ">" ++ > + "</" ++ MethodName ++ "></Body></Envelope>". > + > +:- pred generate_AddInt_body(method::in, list(univ)::in, string::out) > + is det. > + > +generate_AddInt_body(Method, Parameters, Body) :- > + list__map(create_xml_parameter, Parameters, XMLList), > + string__append_list(XMLList, XMLString), > + Body = "<Envelope><Body><" ++ Method ++ ">" ++ XMLString ++ > + "</" ++ Method ++ "></Body></Envelope>". Likewise for these ones. (The code for Hello is simplified, because it assumes that Parameters = [], but you could use the same code as for AddInt.) Otherwise that looks fine. -- Fergus Henderson <fj...@cs...> | "I have always known that the pursuit | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp. |