Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 394 lines (326 sloc) 16.005 kB
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
1
2 <erl>
3
4
5 box(Str) ->
6 {'div',[{class,"box"}],
7 {pre,[], yaws_api:htmlize(Str)}}.
8
9 tbox(T) ->
10 box(lists:flatten(io_lib:format("~p",[T]))).
11
12
13 ssi(File) ->
14 {'div',[{class,"box"}],
15 {pre,[],
16 {ssi, File,[],[]}}}.
17
18 ss(A, File) ->
19 {ok, B} = file:read_file(
0be3c7e @klacke untabified all of yaws
authored
20 filename:join([A#arg.docroot, File])),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
21 box(binary_to_list(B)).
22
23
24
25 out(A) ->
26 [{ssi, "TAB.inc", "%%",[{"soap_intro", "choosen"}]},
27 {ehtml,
28 {'div', [{id, "entry"}],
29
30 [{h1, [], "SOAP with Yaws"},
31
32 {p, [],
0be3c7e @klacke untabified all of yaws
authored
33 ["SOAP is an XML-based protocol for communication over a network "
34 "connection. The main focus of SOAP is remote procedure calls (RPCs) "
35 "transported via HTTP. "
36 "SOAP is similar to XML-RPC but makes use of XML Schema to define "
37 "the data types it is making use of. "
38 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
39
40 {h2, [], "Preparations"},
41
42 {p, [],
0be3c7e @klacke untabified all of yaws
authored
43 ["Yaws is making use of the 'erlsom' XML Schema "
44 "parser and some SOAP specific library code. "
45 "Thus, to be able to use SOAP with Yaws you need to have "
46 "'erlsom' installed. Currently, the easiest way of installing "
47 "'erlsom' is to check out the library from Sourceforge and "
48 "install it from there (you can also download a released version "
49 "of erlsom and install it)."]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
50
51 {p,[],"To install 'erlsom' do:"},
52
53 box("cvs -d:pserver:anonymous@erlsom.cvs.sourceforge.net:/cvsroot/erlsom login\n"
0be3c7e @klacke untabified all of yaws
authored
54 " cvs -z3 -d:pserver:anonymous@erlsom.cvs.sourceforge.net:/cvsroot/erlsom co -P erlsom\n"
55 "cd erlsom; ./configure; make\n"
56 "sudo make install # iff you want to install as root\n"
57 ),
58
59 {p, [],
60 "<b>Important:</b> The SOAP specific code that makes use of erlsom has some limitations "
61 "that it is important to be aware of. Only the Soap <i>'document'</i> binding "
62 "style is supported. There is no support for non-soap bindings, nor for the "
63 "RPC binding style. Also, only the <i>'literal'</i> encoding is supported "
64 "There is no support for <i>'soap-encoding'</i>. For an explanation of the differences "
65 "between these concepts, see this "
66 "<a href=\"http://www-128.ibm.com/developerworks/webservices/library/ws-whichwsdl/\">description</a>."},
67
68
69 {h2, [], "The SOAP client side"},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
70
71 {p, [],
0be3c7e @klacke untabified all of yaws
authored
72 ["The SOAP interface is defined by a WSDL specification, which "
73 "simply is a (rather verbose) piece of XML document that specifies "
74 "the public interface for a web service. As a client, "
75 "we don't need to understand everything in the WSDL specification "
76 "The parts that are most interesting is the name of the operation "
77 "we want to perform (i.e the function we want to call) and what "
78 "input data it expects."
79 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
80
81 {p,[],
0be3c7e @klacke untabified all of yaws
authored
82 ["As an example, lets have a look at a public SOAP service that "
83 "returns some weather data for the location we send to it. "
84 "The WSDL specification can be found here: ",
85 {a, [{href, "http://www.webservicex.net/WeatherForecast.asmx?WSDL"}],
86 "http://www.webservicex.net/WeatherForecast.asmx?WSDL "}
87 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
88
89 {p,[],
0be3c7e @klacke untabified all of yaws
authored
90 ["We start by finding the operation named: ",
91 {i, [], "GetWeatherByPlaceName, "},
92 "which is the operation we want to invoke. As can be seen, we have "
93 "one input message and one output message defined. The input message is "
94 "the one we (as a client) will send to the server. "
95 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
96
97 box("<wsdl:operation name=\"GetWeatherByPlaceName\">\n"
0be3c7e @klacke untabified all of yaws
authored
98 " <documentation>\n"
99 " Get one week weather forecast for a place name(USA)\n"
100 " </documentation>\n"
101 " <wsdl:input message=\"tns:GetWeatherByPlaceNameSoapIn\"/>\n"
102 " <wsdl:output message=\"tns:GetWeatherByPlaceNameSoapOut\"/>\n"
103 "</wsdl:operation>\n"),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
104
105 {p,[],
0be3c7e @klacke untabified all of yaws
authored
106 ["Now, follow the reference to the message: ",
107 {i, [], "tns:GetWeatherByPlaceNameSoapIn, "},
108 "to where it is defined: "
109 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
110
111 box("<wsdl:message name=\"GetWeatherByPlaceNameSoapIn\">\n"
0be3c7e @klacke untabified all of yaws
authored
112 "<wsdl:part name=\"parameters\" element=\"tns:GetWeatherByPlaceName\"/>\n"
113 "</wsdl:message>\n"),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
114
115 {p,[],
0be3c7e @klacke untabified all of yaws
authored
116 ["Continue by following the reference to: ",
117 {i, [], "tns:GetWeatherByPlaceName, "},
118 "and you will end up with an XML Schema type definition: "
119 ]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
120
121 box("<s:element name=\"GetWeatherByPlaceName\">\n"
0be3c7e @klacke untabified all of yaws
authored
122 "<s:complexType>\n"
123 "<s:sequence>\n"
124 "<s:element minOccurs=\"0\" maxOccurs=\"1\" name=\"PlaceName\" type=\"s:string\"/>\n"
125 "</s:complexType>\n"
126 "</s:sequence>\n"
127 "</s:element>\n"),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
128
129 {p,[],
0be3c7e @klacke untabified all of yaws
authored
130 "This tells us that the function we want to call takes one argument "
131 "of a string type (which apparently denotes a Name of a place in the US). "
132 "Left for us is just to call the function from an Erlang shell which has "
133 "got the Yaws ebin directory in the path:"
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
134 },
135
136 box("1> yaws_soap_lib:call(\n"
0be3c7e @klacke untabified all of yaws
authored
137 " \"http://www.webservicex.net/WeatherForecast.asmx?WSDL\"\n"
138 " \"GetWeatherByPlaceName\"\n"
139 " [\"Boston\"]).\n"
140 "{ok,undefined,\n"
141 " [{'p:GetWeatherByPlaceNameResponse',\n"
142 " [],\n"
143 " {'p:WeatherForecasts',[],\n"
144 " \"40.3044128\",\n"
145 " \"79.81284\",\n"
146 " \"0.000453\",\n"
147 " \"42\",\n"
148 " \"BOSTON\",\n"
149 " \"PA\",\n"
150 " undefined,\n"
151 " {'p:ArrayOfWeatherData',\n"
152 " [],\n"
153 " [{'p:WeatherData',\n"
154 " [],\n"
155 " \"Friday, December 08, 2006\"|...},\n"
156 " .....\n"),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
157
158 {p,[],
0be3c7e @klacke untabified all of yaws
authored
159 "So what happend here? We specified the URL to the WSDL file. "
160 "The yaws_soap_lib:call/3 function then went to retrieve the file, parsed it, "
161 "created a proper message, sent off the message, waited for the "
162 "reply and finally returned a parsed reply as Erlang records. "
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
163 },
164
165 {p,[],
0be3c7e @klacke untabified all of yaws
authored
166 "Eventhough this was very convenient, we probably want do more thnn just one call "
167 "to the web service. So to avoid retrieving and parsing the WSDL file for every "
168 "call. We can do it in two steps: "
169 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
170
171 box("1> Wsdl = yaws_soap_lib:initModel(\n"
0be3c7e @klacke untabified all of yaws
authored
172 " \"http://www.webservicex.net/WeatherForecast.asmx?WSDL\").\n"
173 "...\n"
174 "2> yaws_soap_lib:call(\n"
175 " Wsdl,\n"
176 " \"GetWeatherByPlaceName\"\n"
177 " [\"Boston\"]).\n"
178 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
179
180 {p,[],
0be3c7e @klacke untabified all of yaws
authored
181 "To be able to work with the records that we get in the response, "
182 "we can create a header file that we can include in our source code. In our example "
183 "the generated '.hrl' file will look like this: "
184 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
185
186 box("3> yaws_soap_lib:write_hrl(Wsdl, \"/tmp/wfc.hrl\").\n"
0be3c7e @klacke untabified all of yaws
authored
187 "...\n"
188 "4> {ok,Bin}=file:read_file(\"/tmp/wfc.hrl\"),io:fwrite(binary_to_list(Bin)).\n"
189 "-record('soap:detail', {anyAttribs, choice}).\n"
190 "-record('soap:Fault', {anyAttribs, 'faultcode', 'faultstring', 'faultactor', 'detail'}).\n"
191 "-record('soap:Body', {anyAttribs, choice}).\n"
192 "-record('soap:Header', {anyAttribs, choice}).\n"
193 "-record('soap:Envelope', {anyAttribs, 'Header', 'Body', choice}).\n"
194 "-record('p:GetWeatherByPlaceNameResponse', {anyAttribs, 'GetWeatherByPlaceNameResult'}).\n"
195 "-record('p:GetWeatherByPlaceName', {anyAttribs, 'PlaceName'}).\n"
196 "-record('p:WeatherData', {anyAttribs, 'Day', 'WeatherImage', 'MaxTemperatureF', \n"
197 " 'MinTemperatureF', 'MaxTemperatureC', 'MinTemperatureC'}).\n"
198 "-record('p:ArrayOfWeatherData', {anyAttribs, 'WeatherData'}).\n"
199 "-record('p:WeatherForecasts', {anyAttribs, 'Latitude', 'Longitude', 'AllocationFactor', \n"
200 " 'FipsCode', 'PlaceName', 'StateCode', 'Status', 'Details'}).\n"
201 "-record('p:GetWeatherByZipCodeResponse', {anyAttribs, 'GetWeatherByZipCodeResult'}).\n"
202 "-record('p:GetWeatherByZipCode', {anyAttribs, 'ZipCode'}).\n"
203 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
204
205 {p,[],
0be3c7e @klacke untabified all of yaws
authored
206 "As you can see, every record in our header has an XML namespace prefix prepended "
207 "in the name of the record. The prefix 'p' as shown above is the default prefix you'll "
208 "get if you don't specify a prefix yourself. This is probably good enough, but if you "
209 "want to set it to something else, you can do it as shown below:"
210 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
211
212 box("5> yaws_soap_lib:initModel(... , \"foo\"). % foo is my prefix\n"
0be3c7e @klacke untabified all of yaws
authored
213 "6> yaws_soap_lib:write_hrl(... , ... , \"foo\").\n"
214 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
215
216 {p,[],
0be3c7e @klacke untabified all of yaws
authored
217 ["Some final notes:",
218 {ul, [],
219 [{li, [],
220 "The \"http://...\" URL given as the first argument to the "
221 "functions above may as well be a local file, and thus written as \"file://....\". "},
222 {li, [],
223 "When we retrieve a HTTP located file, we will use 'ibrowse' if it exist "
224 "in the code path. Otherwise we will use the OTP 'http' client."}
225 ]}]},
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
226
227 {h2, [], "The SOAP server side"},
228
229 {p,[],
0be3c7e @klacke untabified all of yaws
authored
230 "If we want to run our own weather service we need to take the WSDL "
231 "and add our own location to it. Either we can just study the WSDL file to "
232 "see which URL we need to change in the 'service' part of the document, or "
233 "we can make use of some nice access functions, that work on the "
234 "#wsdl{} record that yaws_soap_lib:initModel/2 returned, as shown below: "
235 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
236
237 box("7> Ops = yaws_soap_lib:wsdl_operations(Wsdl).\n"
0be3c7e @klacke untabified all of yaws
authored
238 "8> {ok,Op} = yaws_soap_lib:get_operation(Ops, \"GetWeatherByPlaceName\").\n"
239 "9> yaws_soap_lib:wsdl_op_address(Op).\n"
240 "\"http://www.webservicex.net/WeatherForecast.asmx\"\n"
241 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
242
243 {p,[],
0be3c7e @klacke untabified all of yaws
authored
244 "Now, edit the WSDL file and change the above URL to something like this:"
245 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
246
247 box("<wsdl:service name=\"WeatherForecast\">\n"
0be3c7e @klacke untabified all of yaws
authored
248 " <documentation xmlns=......\n"
249 " <wsdl:port name=\"WeatherForecastSoap\".....\n"
250 " <soap:address location=\"http://localhost:8181/WeatherForecast.yaws\" />\n"
251 " </wsdl:port>\n"
252 ".....\n"
253 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
254
255
256 {p,[],
0be3c7e @klacke untabified all of yaws
authored
257 "Next, start an Erlang shell and start Yaws with SOAP enabled. We need to write "
258 "the code that returns the weather info. This is done in a callback module that "
259 "the Yaws SOAP code will call with the incoming message. The message will be an "
260 "Erlang record and what we return must also be an Erlang record. So we will need "
261 "to create a .hrl containing the record definitions that we can include: "
262 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
263
264 box("1> Docroot = \"/tmp\".\n"
0be3c7e @klacke untabified all of yaws
authored
265 "\n"
266 "2> GL = [{enable_soap,true}, % <== THIS WILL ENABLE SOAP IN A YAWS SERVER!!\n"
267 " {trace, false},\n"
268 " {tmpdir,\"/tmp\"},{logdir,\"/tmp\"},\n"
269 " {flags,[{auth_log,false},{tty_trace, false},{copy_errlog, true}]}].\n"
270 "\n"
271 "3> SL = [{port,8181},{servername,\"localhost\"},{dir_listings, true},\n"
272 " {listen,{127,0,0,1}},{flags,[{access_log,false}]}].\n"
273 "\n"
274 "% BELOW, WE CREATE THE .hrl FILE!!\n"
275 "4> yaws_soap_lib:write_hrl(\"file:///tmp/MyWeatherService.wsdl\", \"/tmp/my_soap.hrl\").\n"
276 "\n"
277 "% WE MUST ADD A PATH TO OUR CALLBACK CODE!!\n"
278 "5> code:add_path(\"/tmp\").\n"
279 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
280
281 {p,[],
0be3c7e @klacke untabified all of yaws
authored
282 "We continue by writing our weather forecast callback module:"
283 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
284
285 box("# cat /tmp/my_soap.erl\n"
0be3c7e @klacke untabified all of yaws
authored
286 "-module(my_soap).\n"
287 "-export([handler/4]).\n"
288 "-include(\"my_soap.hrl\"). % .hrl file generated by erlsom\n"
289 "\n"
290 "handler(_Header,\n"
291 " [#'p:GetWeatherByPlaceName'{'PlaceName' = Place}],\n"
292 " _Action, \n"
293 " _SessionValue) ->\n"
294 " {ok, undefined, get_weather_info(Place)}.\n"
295 "\n"
296 "get_weather_info(Place) ->\n"
297 " WeatherData =\n"
298 " #'p:WeatherData'{anyAttribs = [],\n"
299 " 'Day' = \"Sunday, December 10, 2006\",\n"
300 " 'WeatherImage' = \"http://www.nws.noaa.gov/weather/images/fcicons/nfew.jpg\",\n"
301 " 'MaxTemperatureF' = \"51\",\n"
302 " 'MinTemperatureF' = \"28\",\n"
303 " 'MaxTemperatureC' = \"11\",\n"
304 " 'MinTemperatureC' = \"-2\"\n"
305 " },\n"
306 "\n"
307 " ArrayOfWeatherData =\n"
308 " #'p:ArrayOfWeatherData'{anyAttribs = [],\n"
309 " 'WeatherData' = [WeatherData]\n"
310 " },\n"
311 "\n"
312 " Forecast =\n"
313 " #'p:WeatherForecasts'{anyAttribs = [],\n"
314 " 'Latitude' = \"40.3044128\",\n"
315 " 'Longitude' = \"79.81284\",\n"
316 " 'AllocationFactor' = \"0.000453\",\n"
317 " 'FipsCode' = \"42\",\n"
318 " 'PlaceName' = Place,\n"
319 " 'StateCode' = \"PA\",\n"
320 " 'Status' = undefined,\n"
321 " 'Details' = ArrayOfWeatherData\n"
322 " },\n"
323 "\n"
324 " Response =\n"
325 " #'p:GetWeatherByPlaceNameResponse'{anyAttribs = [],\n"
326 " 'GetWeatherByPlaceNameResult' = Forecast\n"
327 " },\n"
328 "\n"
329 " [Response]. \n"
330 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
331
332 {p,[],
0be3c7e @klacke untabified all of yaws
authored
333 "The final piece on the server side is the '.yaws' file that invokes the "
334 "Yaws SOAP server (note that we are using the same way of hooking in our "
335 "callback module as for Json and HaXe):"
336 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
337
338 box("# cat /tmp/WeatherForecast.yaws\n"
0be3c7e @klacke untabified all of yaws
authored
339 "<erl>\n"
340 "out(A) ->\n"
341 " yaws_rpc:handler_session(A, {my_soap, handler}).\n"
342 "</erl>\n"
343 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
344
345 {p,[],
0be3c7e @klacke untabified all of yaws
authored
346 "Now, in your Yaws shell, setup the Soap server as shown below:"
347 },
7795c70 Adding missing description on call to: yaws_soap_srv:setup/2.
Tobbe Tornquist authored
348
349 box("6> yaws_soap_srv:setup({my_soap, handler}, \"file:///tmp/MyWeatherService.wsdl\").\n"
0be3c7e @klacke untabified all of yaws
authored
350 ),
7795c70 Adding missing description on call to: yaws_soap_srv:setup/2.
Tobbe Tornquist authored
351
352 {p,[],
0be3c7e @klacke untabified all of yaws
authored
353 "We are now ready to try it out. Start another Erlang shell and call it: "
354 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
355
356 box("1> yaws_soap_lib:call(\"file:///tmp/MyWeatherService.wsdl\",\n"
0be3c7e @klacke untabified all of yaws
authored
357 " \"GetWeatherByPlaceName\",\n"
358 " [\"Stockholm\"]).\n"
359 "{ok,undefined,\n"
360 " [{'p:GetWeatherByPlaceNameResponse', [],\n"
361 " {'p:WeatherForecasts',[],\n"
362 " \"40.3044128\",\n"
363 " \"79.81284\",\n"
364 " \"0.000453\",\n"
365 " \"42\",\n"
366 " \"Stockholm\", % <=== Yippie, it works !!\n"
367 " \"PA\",\n"
368 " undefined,\n"
369 " {'p:ArrayOfWeatherData', [],\n"
370 " [{'p:WeatherData', [],\n"
371 " \"Sunday, December 10, 2006\"|...}]}}}]}\n"
372 "\n"
373 ),
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
374
375 {p,[],
0be3c7e @klacke untabified all of yaws
authored
376 "There you have it! "
377 },
c332fc2 Adding SOAP processing capabilities to Yaws.
Tobbe Tornquist authored
378
379
380 {ssi, "END2",[],[]}
381 ]}}].
382
383
384
385
386 </erl>
387
388
389
390
391
392
393
Something went wrong with that request. Please try again.