Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

723 lines (621 sloc) 27.572 kb
%%%-------------------------------------------------------------------
%%% Created : 29 Nov 2006 by Torbjorn Tornkvist <tobbe@tornkvist.org>
%%% Author : Willem de Jong (w.a.de.jong@gmail.com).
%%% Desc. : Common SOAP code.
%%%-------------------------------------------------------------------
%%% modified (WdJ, May 2007): deal with imports in the WSDL.
%%% modified (WdJ, August 2007): the WSDL can contain more than 1 schema
-module(yaws_soap_lib).
-export([initModel/1, initModel/2,
initModelFile/1,
config_file_xsd/0,
call/3, call/4, call/5, call/6,
call_attach/4, call_attach/5, call_attach/7,
write_hrl/2, write_hrl/3,
findHeader/2,
parseMessage/2,
makeFault/2,
is_wsdl/1, wsdl_model/1, wsdl_op_service/1,
wsdl_op_port/1, wsdl_op_operation/1,
wsdl_op_binding/1, wsdl_op_address/1,
wsdl_op_action/1, wsdl_operations/1,
get_operation/2
]).
%%% For testing...
-export([qtest/0]).
-include("../include/soap.hrl").
-define(HTTP_REQ_TIMEOUT, 20000).
%%-define(dbg(X,Y),
%% error_logger:info_msg("*dbg ~p(~p): " X,
%% [?MODULE, ?LINE | Y])).
-define(dbg(X,Y), true).
-record(yaws_soap_config, {atts, xsd_path, user_module, wsdl_file, add_files}).
-record(xsd_file, {atts, name, prefix, import_specs}).
-record(import_specs, {atts, namespace, prefix, location}).
-define(DefaultPrefix, "p").
%%%
%%% Writes the header file (record definitions) for a WSDL file
%%%
write_hrl(WsdlURL, Output) when is_list(WsdlURL) ->
write_hrl(initModel(WsdlURL), Output);
write_hrl(#wsdl{model = Model}, Output) when is_list(Output) ->
erlsom:write_hrl(Model, Output).
write_hrl(WsdlURL, Output, PrefixOrOptions)
when is_list(WsdlURL),is_list(PrefixOrOptions) ->
write_hrl(initModel(WsdlURL, PrefixOrOptions), Output).
%%% For testing only...
qtest() ->
call("http://www.webservicex.net/WeatherForecast.asmx?WSDL",
"GetWeatherByPlaceName",
["Boston"]).
%%% --------------------------------------------------------------------
%%% Access functions
%%% --------------------------------------------------------------------
is_wsdl(Wsdl) when is_record(Wsdl,wsdl) -> true;
is_wsdl(_) -> false.
wsdl_operations(#wsdl{operations = Ops}) -> Ops.
wsdl_model(#wsdl{model = Model}) -> Model.
wsdl_op_service(#operation{service = Service}) -> Service.
wsdl_op_port(#operation{port = Port}) -> Port.
wsdl_op_operation(#operation{operation = Op}) -> Op.
wsdl_op_binding(#operation{binding = Binding}) -> Binding.
wsdl_op_address(#operation{address = Address}) -> Address.
wsdl_op_action(#operation{action = Action}) -> Action.
%%% --------------------------------------------------------------------
%%% For Quick deployment
%%% --------------------------------------------------------------------
call(WsdlURL, Operation, ListOfData) when is_list(WsdlURL) ->
Wsdl = initModel(WsdlURL, ?DefaultPrefix),
call(Wsdl, Operation, ListOfData);
call(Wsdl, Operation, ListOfData) when is_record(Wsdl, wsdl) ->
case get_operation(Wsdl#wsdl.operations, Operation) of
{ok, Op} ->
Msg = mk_msg(?DefaultPrefix, Operation, ListOfData),
call(Wsdl, Operation, Op#operation.port,
Op#operation.service, [], Msg);
Else ->
Else
end.
%%% --------------------------------------------------------------------
%%% With additional specified prefix
%%% --------------------------------------------------------------------
call(WsdlURL, Operation, ListOfData, prefix, Prefix) when is_list(WsdlURL) ->
Wsdl = initModel(WsdlURL, Prefix),
call(Wsdl, Operation, ListOfData, prefix, Prefix );
call(Wsdl, Operation, ListOfData, prefix, Prefix) when is_record(Wsdl, wsdl) ->
case get_operation(Wsdl#wsdl.operations, Operation) of
{ok, Op} ->
Msg = mk_msg(Prefix, Operation, ListOfData),
call(Wsdl, Operation, Op#operation.port,
Op#operation.service, [], Msg);
Else ->
Else
end.
%%% --------------------------------------------------------------------
%%% Takes the actual records for the Header and Body message.
%%% --------------------------------------------------------------------
call(WsdlURL, Operation, Header, Msg) when is_list(WsdlURL) ->
Wsdl = initModel(WsdlURL, ?DefaultPrefix),
call(Wsdl, Operation, Header, Msg);
call(Wsdl, Operation, Header, Msg) when is_record(Wsdl, wsdl) ->
case get_operation(Wsdl#wsdl.operations, Operation) of
{ok, Op} ->
call(Wsdl, Operation, Op#operation.port, Op#operation.service,
Header, Msg);
Else ->
Else
end.
mk_msg(Prefix, Operation, ListOfData) ->
list_to_tuple([list_to_atom(Prefix++":"++Operation), % record name
[] % anyAttribs
| ListOfData]). % rest of record data
get_operation([#operation{operation = X} = Op|_], X) ->
{ok, Op};
get_operation([_|T], Op) ->
get_operation(T, Op);
get_operation([], _Op) ->
{error, "operation not found"}.
%%% --------------------------------------------------------------------
%%% Make a SOAP request (no attachments)
%%% --------------------------------------------------------------------
call(Wsdl, Operation, Port, Service, Headers, Message) ->
call_attach(Wsdl, Operation, Port, Service, Headers, Message, []).
%%% --------------------------------------------------------------------
%%% For Quick deployment (with attachments)
%%% --------------------------------------------------------------------
call_attach(WsdlURL, Operation, ListOfData, Attachments)
when is_list(WsdlURL) ->
Wsdl = initModel(WsdlURL, ?DefaultPrefix),
call_attach(Wsdl, Operation, ListOfData, Attachments);
call_attach(Wsdl, Operation, ListOfData, Attachments)
when is_record(Wsdl, wsdl) ->
case get_operation(Wsdl#wsdl.operations, Operation) of
{ok, Op} ->
Msg = mk_msg(?DefaultPrefix, Operation, ListOfData),
call_attach(Wsdl, Operation, Op#operation.port,
Op#operation.service, [], Msg, Attachments);
Else ->
Else
end.
%%% --------------------------------------------------------------------
%%% Takes the actual records for the Header and Body message
%%% (with attachments)
%%% --------------------------------------------------------------------
call_attach(WsdlURL, Operation, Header, Msg, Attachments)
when is_list(WsdlURL) ->
Wsdl = initModel(WsdlURL, ?DefaultPrefix),
call_attach(Wsdl, Operation, Header, Msg, Attachments);
call_attach(Wsdl, Operation, Header, Msg, Attachments)
when is_record(Wsdl, wsdl) ->
case get_operation(Wsdl#wsdl.operations, Operation) of
{ok, Op} ->
call_attach(Wsdl, Operation, Op#operation.port,
Op#operation.service,
Header, Msg, Attachments);
Else ->
Else
end.
%%% --------------------------------------------------------------------
%%% Make a SOAP request (with attachments)
%%% --------------------------------------------------------------------
call_attach(#wsdl{operations = Operations, model = Model},
Operation, Port, Service, Headers, Message, Attachments) ->
%% find the operation
case findOperation(Operation, Port, Service, Operations) of
#operation{address = URL, action = SoapAction} ->
%% Add the Soap envelope
Envelope = mk_envelope(Message, Headers),
%% Encode the message
case erlsom:write(Envelope, Model) of
{ok, XmlMessage} ->
{ContentType, Request} =
make_request_body(XmlMessage, Attachments),
HttpHeaders = [],
HttpClientOptions = [],
?dbg("+++ Request = ~p~n", [Request]),
HttpRes = http_request(URL, SoapAction, Request,
HttpClientOptions, HttpHeaders,
ContentType),
?dbg("+++ HttpRes = ~p~n", [HttpRes]),
case HttpRes of
{ok, _Code, _ReturnHeaders, Body} ->
parseMessage(Body, Model);
Error ->
%% in case of HTTP error: return
%% {error, description}
Error
end;
{error, EncodingError} ->
{error, {encoding_error, EncodingError}}
end;
false ->
{error, {unknown_operation, Operation}}
end.
%%%
%%% returns {ok, Header, Body} | {error, Error}
%%%
parseMessage(Message, #wsdl{model = Model}) ->
parseMessage(Message, Model);
%%
parseMessage(Message, Model) ->
case erlsom:scan(Message, Model) of
{ok, #'soap:Envelope'{'Body' = #'soap:Body'{choice = Body},
'Header' = undefined}, _} ->
{ok, undefined, Body};
{ok, #'soap:Envelope'{'Body' = #'soap:Body'{choice = Body},
'Header' = #'soap:Header'{choice = Header}}, _} ->
{ok, Header, Body};
{error, ErrorMessage} ->
{error, {decoding, ErrorMessage}}
end.
findOperation(_Operation, _Port, _Service, []) ->
false;
findOperation(Operation, Port, Service,
[Op = #operation{operation = Operation,
port = Port, service = Service} | _]) ->
Op;
findOperation(Operation, Port, Service, [#operation{} | Tail]) ->
findOperation(Operation, Port, Service, Tail).
mk_envelope(M, H) when is_tuple(M) -> mk_envelope([M], H);
mk_envelope(M, H) when is_tuple(H) -> mk_envelope(M, [H]);
%%
mk_envelope(Messages, []) when is_list(Messages) ->
#'soap:Envelope'{'Body' = #'soap:Body'{choice = Messages}};
mk_envelope(Messages, Headers) when is_list(Messages),is_list(Headers) ->
#'soap:Envelope'{'Body' = #'soap:Body'{choice = Messages},
'Header' = #'soap:Header'{choice = Headers}}.
%%% --------------------------------------------------------------------
%%% Parse a WSDL file and return a 'Model'
%%% --------------------------------------------------------------------
initModel(WsdlFile) ->
initModel(WsdlFile, ?DefaultPrefix).
%% PrefixOrOptions can be a property list that contains the options
%% for Erlsom, or a String. If it is a string, this is used as the
%% Erlsom 'prefix' option (and the other options are left unspecified).
initModel(WsdlFile, PrefixOrOptions) ->
Options = case is_string(PrefixOrOptions) of
no ->
%% It is an option list
%% Add the default prefix at the end - it will only be used
%% if no other prefix is specified
PrefixOrOptions ++ [{prefix, ?DefaultPrefix}];
_ ->
%% just the prefix
[{prefix, PrefixOrOptions}]
end,
PrivDir = priv_dir(),
initModel2(WsdlFile, Options, PrivDir, undefined, undefined).
initModelFile(ConfigFile) ->
{ok, ConfigSchema} = erlsom:compile_xsd(config_file_xsd()),
%% read (parse) the config file
{ok, Config, _} = erlsom:scan_file(ConfigFile, ConfigSchema),
#yaws_soap_config{xsd_path = XsdPath,
wsdl_file = Wsdl,
add_files = AddFiles} = Config,
#xsd_file{name = WsdlFile, prefix = Prefix, import_specs = Import} = Wsdl,
initModel2(WsdlFile, [{prefix, Prefix}], XsdPath, Import, AddFiles).
priv_dir() ->
case code:priv_dir(yaws) of
{error, bad_name} ->
filename:join([filename:dirname(code:which(yaws)),"..", "priv"]);
A ->
A
end.
initModel2(WsdlFile, ErlsomOptions, Path, Import, AddFiles) ->
WsdlName = filename:join([Path, "wsdl.xsd"]),
IncludeWsdl = {"http://schemas.xmlsoap.org/wsdl/", "wsdl", WsdlName},
{ok, WsdlModel} = erlsom:compile_xsd_file(
filename:join([Path, "soap.xsd"]),
[{prefix, "soap"},
{include_files, [IncludeWsdl]}]),
%% add the xsd model (since xsd is also used in the wsdl)
WsdlModel2 = erlsom:add_xsd_model(WsdlModel),
Options = ErlsomOptions ++ makeOptions(Import),
%% parse Wsdl
{Model, Operations} = parseWsdls([WsdlFile], WsdlModel2,
Options, {undefined, []}),
%% TODO: add files as required
%% now compile envelope.xsd, and add Model
{ok, EnvelopeModel} = erlsom:compile_xsd_file(
filename:join([Path, "envelope.xsd"]),
[{prefix, "soap"}]),
SoapModel = erlsom:add_model(EnvelopeModel, Model),
SoapModel2 = addModels(AddFiles, SoapModel),
#wsdl{operations = Operations, model = SoapModel2}.
%%% --------------------------------------------------------------------
%%% Parse a list of WSDLs and import (recursively)
%%% Returns {Model, Operations}
%%% --------------------------------------------------------------------
parseWsdls([], _WsdlModel, _Options, Acc) ->
Acc;
parseWsdls([WsdlFile | Tail], WsdlModel, Options, {AccModel, AccOperations}) ->
{ok, WsdlFileContent} = get_url_file(rmsp(WsdlFile)),
{ok, ParsedWsdl, _} = erlsom:scan(WsdlFileContent, WsdlModel),
%% get the xsd elements from this model, and hand it over to erlsom_compile.
Xsds = getXsdsFromWsdl(ParsedWsdl),
%% Now we need to build a list: [{Namespace, Xsd, Prefix}, ...] for
%% all the Xsds in the WSDL.
%% This list is used when a schema includes one of the other schemas.
%% The AXIS java2wsdl tool generates wsdls that depend on this feature.
ImportList = makeImportList(Xsds, []),
Model2 = addSchemas(Xsds, AccModel, Options, ImportList),
Ports = getPorts(ParsedWsdl),
Operations = getOperations(ParsedWsdl, Ports),
Imports = getImports(ParsedWsdl),
Acc2 = {Model2, Operations ++ AccOperations},
%% process imports (recursively, so that imports in the imported files are
%% processed as well).
%% For the moment, the namespace is ignored on operations etc.
%% this makes it a bit easier to deal with imported wsdl's.
Acc3 = parseWsdls(Imports, WsdlModel, Options, Acc2),
parseWsdls(Tail, WsdlModel, Options, Acc3).
%%% --------------------------------------------------------------------
%%% build a list: [{Namespace, Xsd}, ...] for all the Xsds in the WSDL.
%%% This list is used when a schema inlcudes one of the other schemas.
%%% The AXIS java2wsdl tool generates wsdls that depend on this feature.
makeImportList([], Acc) ->
Acc;
makeImportList([ Xsd | Tail], Acc) ->
makeImportList(Tail, [{erlsom_lib:getTargetNamespaceFromXsd(Xsd),
undefined, Xsd} | Acc]).
%%% --------------------------------------------------------------------
%%% compile each of the schemas, and add it to the model.
%%% Returns Model
%%% (TODO: using the same prefix for all XSDS makes no sense)
%%% --------------------------------------------------------------------
addSchemas([], AccModel, _Options, _ImportList) ->
AccModel;
addSchemas([Xsd| Tail], AccModel, Options, ImportList) ->
Model2 = case Xsd of
undefined ->
AccModel;
_ ->
{ok, Model} =
erlsom_compile:compile_parsed_xsd(
Xsd,
[{include_files, ImportList} |Options]),
case AccModel of
undefined -> Model;
_ -> erlsom:add_model(AccModel, Model)
end
end,
addSchemas(Tail, Model2, Options, ImportList).
%%% --------------------------------------------------------------------
%%% Get a file from an URL spec.
%%% --------------------------------------------------------------------
get_url_file("http://"++_ = URL) ->
case httpc:request(URL) of
{ok,{{_HTTP,200,_OK}, _Headers, Body}} ->
{ok, Body};
{ok,{{_HTTP,RC,Emsg}, _Headers, _Body}} ->
error_logger:error_msg("~p: http-request got: ~p~n",
[?MODULE, {RC, Emsg}]),
{error, "failed to retrieve: "++URL};
{error, Reason} ->
error_logger:error_msg("~p: http-request failed: ~p~n",
[?MODULE, Reason]),
{error, "failed to retrieve: "++URL}
end;
get_url_file("file://"++Fname) ->
{ok, Bin} = file:read_file(Fname),
{ok, binary_to_list(Bin)};
%% added this, since this is what is used in many WSDLs (i.e.: just a filename).
get_url_file(Fname) ->
{ok, Bin} = file:read_file(Fname),
{ok, binary_to_list(Bin)}.
%%% --------------------------------------------------------------------
%%% Make a HTTP Request
%%% --------------------------------------------------------------------
http_request(URL, SoapAction, Request, Options, Headers, ContentType) ->
case code:ensure_loaded(ibrowse) of
{module, ibrowse} ->
%% If ibrowse exist in the path then let's use it...
ibrowse_request(URL, SoapAction, Request, Options,
Headers, ContentType);
_ ->
%% ...otherwise, let's use the OTP http client.
inets_request(URL, SoapAction, Request, Options,
Headers, ContentType)
end.
inets_request(URL, SoapAction, Request, Options, Headers, ContentType) ->
NHeaders = [{"SOAPAction", SoapAction}|Headers],
NewHeaders = case proplists:get_value("Host", NHeaders) of
undefined ->
[{"Host", "localhost:8800"}|NHeaders];
_ ->
NHeaders
end,
NewOptions = [{cookies, enabled}|Options],
httpc:set_options(NewOptions),
case httpc:request(post,
{URL,NewHeaders,
ContentType,
Request},
[{timeout,?HTTP_REQ_TIMEOUT}],
[{sync, true}, {full_result, true},
{body_format, string}]) of
{ok,{{_HTTP,200,_OK},ResponseHeaders,ResponseBody}} ->
{ok, 200, ResponseHeaders, ResponseBody};
{ok,{{_HTTP,500,_Descr},ResponseHeaders,ResponseBody}} ->
{ok, 500, ResponseHeaders, ResponseBody};
{ok,{{_HTTP,ErrorCode,_Descr},ResponseHeaders,ResponseBody}} ->
{ok, ErrorCode, ResponseHeaders, ResponseBody};
Other ->
Other
end.
ibrowse_request(URL, SoapAction, Request, Options, Headers, ContentType) ->
case start_ibrowse() of
ok ->
NewHeaders = [{"Content-Type", ContentType},
{"SOAPAction", SoapAction} | Headers],
case ibrowse:send_req(URL, NewHeaders, post, Request, Options) of
{ok, Status, ResponseHeaders, ResponseBody} ->
{ok, list_to_integer(Status), ResponseHeaders, ResponseBody};
{error, Reason} ->
{error, Reason}
end;
error ->
{error, "could not start ibrowse"}
end.
start_ibrowse() ->
case ibrowse:start() of
{ok, _} -> ok;
{error, {already_started, _}} -> ok;
_ -> error
end.
rmsp(Str) -> string:strip(Str, left).
make_request_body(Content, []) ->
{"application/xml; charset=utf-8",
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"++ Content};
make_request_body(Content, AttachedFiles) ->
{"application/dime",
yaws_dime:encode("<?xml version=\"1.0\" encoding=\"utf-8\"?>" ++ Content,
AttachedFiles)}.
makeFault(FaultCode, FaultString) ->
try
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
"<SOAP-ENV:Body>"
"<SOAP-ENV:Fault>"
"<faultcode>SOAP-ENV:" ++ FaultCode ++ "</faultcode>" ++
"<faultstring>" ++ FaultString ++ "</faultstring>" ++
"</SOAP-ENV:Fault>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>"
catch
_:_ ->
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">"
"<SOAP-ENV:Body>"
"<SOAP-ENV:Fault>"
"<faultcode>SOAP-ENV:Server</faultcode>"
"<faultstring>Server error</faultstring>"
"</SOAP-ENV:Fault>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>"
end.
%% record http_header is not defined??
findHeader(Label, Headers) ->
findHeader0(yaws:to_lower(Label), Headers).
findHeader0(_Label, []) ->
undefined;
findHeader0(Label, [{_,_,Hdr,_,Val}|T]) ->
case {Label, yaws:to_lower(Hdr)} of
{X,X} -> Val;
_ -> findHeader0(Label, T)
end;
findHeader0(_Label, undefined) ->
undefined.
makeOptions(undefined) ->
[];
makeOptions(Import) ->
lists:map(fun makeOption/1, Import).
%% -record(import_specs, {atts, namespace, prefix, location}).
makeOption(#import_specs{namespace = Ns, prefix = Pf, location = Lc}) ->
{Ns, Pf, Lc}.
addModels(undefined, Model) ->
Model;
addModels(Import, Model) ->
lists:foldl(fun addModel/2, Model, Import).
%% -record(xsd_file, {atts, name, prefix, import_specs}).
addModel(undefined, Acc) ->
Acc;
addModel(#xsd_file{name = XsdFile, prefix = Prefix, import_specs = Import},
Acc) ->
Options = makeOptions(Import),
{ok, Model2} = erlsom:add_xsd_file(XsdFile, [{prefix, Prefix}|Options],Acc),
Model2.
%% returns [#port{}]
%% -record(port, {service, port, binding, address}).
getPorts(ParsedWsdl) ->
Services = getTopLevelElements(ParsedWsdl, 'wsdl:tService'),
getPortsFromServices(Services, []).
getPortsFromServices([], Acc) ->
Acc;
getPortsFromServices([Service|Tail], Acc) ->
getPortsFromServices(Tail, getPortsFromService(Service) ++ Acc).
getPortsFromService(#'wsdl:tService'{name = Name, port = Ports}) ->
getPortsInfo(Ports, Name, []).
getPortsInfo([], _Name, Acc) ->
Acc;
getPortsInfo([#'wsdl:tPort'{name = Name,
binding = Binding,
choice =
[#'soap:tAddress'{location = URL}]} | Tail],
ServiceName, Acc) ->
getPortsInfo(Tail, ServiceName, [#port{service = ServiceName,
port = Name,
binding = Binding,
address = URL}|Acc]);
%% non-soap bindings are ignored.
getPortsInfo([#'wsdl:tPort'{} | Tail], ServiceName, Acc) ->
getPortsInfo(Tail, ServiceName, Acc).
getTopLevelElements(#'wsdl:tDefinitions'{choice = TLElements}, Type) ->
getTopLevelElements(TLElements, Type, []).
getTopLevelElements([], _Type, Acc) ->
Acc;
getTopLevelElements([#'wsdl:anyTopLevelOptionalElement'{choice = Tuple}| Tail],
Type, Acc) ->
case element(1, Tuple) of
Type -> getTopLevelElements(Tail, Type, [Tuple|Acc]);
_ -> getTopLevelElements(Tail, Type, Acc)
end.
getImports(Definitions) ->
Imports = getTopLevelElements(Definitions, 'wsdl:tImport'),
lists:map(fun(Import) -> Import#'wsdl:tImport'.location end, Imports).
%% returns [#operation{}]
getOperations(ParsedWsdl, Ports) ->
Bindings = getTopLevelElements(ParsedWsdl, 'wsdl:tBinding'),
getOperationsFromBindings(Bindings, Ports, []).
getOperationsFromBindings([], _Ports, Acc) ->
Acc;
getOperationsFromBindings([Binding|Tail], Ports, Acc) ->
getOperationsFromBindings(Tail, Ports,
getOperationsFromBinding(Binding, Ports) ++ Acc).
getOperationsFromBinding(#'wsdl:tBinding'{name = BindingName,
type = BindingType,
choice = _Choice,
operation = Operations}, Ports) ->
%% TODO: get soap info from Choice
getOperationsFromOperations(Operations, BindingName, BindingType,
Operations, Ports, []).
getOperationsFromOperations([], _BindingName, _BindingType, _Operations, _Ports, Acc) ->
Acc;
getOperationsFromOperations([#'wsdl:tBindingOperation'{name = Name,
choice = Choice} | Tail],
BindingName, BindingType, Operations, Ports, Acc) ->
%% get SOAP action from Choice,
case Choice of
[#'soap:tOperation'{soapAction = Action}] ->
%% lookup Binding in Ports, and create a combined result
Ports2 = searchPorts(BindingName, Ports),
%% for each port, make an operation record
CombinedPorts = combinePorts(Ports2, Name, BindingName, Action),
getOperationsFromOperations(
Tail, BindingName, BindingType,
Operations, Ports, CombinedPorts ++ Acc);
_ ->
getOperationsFromOperations(Tail, BindingName, BindingType,
Operations, Ports, Acc)
end.
combinePorts(Ports, Name, BindingName, Action) ->
combinePorts(Ports, Name, BindingName, Action, []).
combinePorts([], _Name, _BindingName, _Action, Acc) ->
Acc;
combinePorts([#port{service = Service,
port = PortName,
address = Address} | Tail],
Name, BindingName, Action, Acc) ->
combinePorts(Tail, Name, BindingName, Action,
[#operation{service = Service,
port = PortName, operation = Name,
binding = BindingName,
address = Address, action = Action} | Acc]).
searchPorts(BindingName, Ports) ->
searchPorts(BindingName, Ports, []).
searchPorts(_BindingName, [], Acc) ->
Acc;
searchPorts(BindingName, [Port | Tail], Acc) ->
PortBinding = erlsom_lib:localName(Port#port.binding),
case PortBinding of
BindingName ->
searchPorts(BindingName, Tail, [Port | Acc]);
_ ->
searchPorts(BindingName, Tail, Acc)
end.
%% copied from yaws/json.erl
is_string([]) -> yes;
is_string(List) -> is_string(List, non_unicode).
is_string([C|Rest], non_unicode) when C >= 0, C =< 255 -> is_string(Rest, non_unicode);
is_string([C|Rest], _) when C =< 65000 -> is_string(Rest, unicode);
is_string([], non_unicode) -> yes;
is_string([], unicode) -> unicode;
is_string(_, _) -> no.
getXsdsFromWsdl(Definitions) ->
case getTopLevelElements(Definitions, 'wsdl:tTypes') of
[#'wsdl:tTypes'{choice = Xsds}] -> Xsds;
[] -> []
end.
config_file_xsd() ->
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
" <xs:element name=\"yaws_soap_config\">"
" <xs:complexType>"
" <xs:sequence>"
" <xs:element name=\"xsd_path\" type=\"xs:string\" minOccurs=\"0\"/>"
" <xs:element name=\"user_module\" type=\"xs:string\"/>"
" <xs:element name=\"wsdl_file\" type=\"xsd_file\"/>"
" <xs:element name=\"add_file\" type=\"xsd_file\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>"
" </xs:sequence>"
" </xs:complexType>"
" </xs:element>"
" <xs:complexType name=\"xsd_file\">"
" <xs:sequence>"
" <xs:element name=\"import_specs\" type=\"import_specs\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>"
" </xs:sequence>"
" <xs:attribute name=\"name\" type=\"string\" use=\"required\"/>"
" <xs:attribute name=\"prefix\" type=\"string\"/>"
" </xs:complexType>"
" <xs:complexType name=\"import_specs\">"
" <xs:attribute name=\"namespace\" type=\"string\" use=\"required\"/>"
" <xs:attribute name=\"prefix\" type=\"string\"/>"
" <xs:attribute name=\"location\" type=\"string\"/>"
" </xs:complexType>"
"</xs:schema>".
Jump to Line
Something went wrong with that request. Please try again.