source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/soap/rpc/proxy.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 14.7 KB
Line 
1# SOAP4R - RPC Proxy library.
2# Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi <[email protected]>.
3
4# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5# redistribute it and/or modify it under the same terms of Ruby's license;
6# either the dual license version in 2003, or any later version.
7
8
9require 'soap/soap'
10require 'soap/processor'
11require 'soap/mapping'
12require 'soap/rpc/rpc'
13require 'soap/rpc/element'
14require 'soap/streamHandler'
15require 'soap/mimemessage'
16
17
18module SOAP
19module RPC
20
21
22class Proxy
23 include SOAP
24
25public
26
27 attr_accessor :soapaction
28 attr_accessor :mandatorycharset
29 attr_accessor :allow_unqualified_element
30 attr_accessor :default_encodingstyle
31 attr_accessor :generate_explicit_type
32 attr_reader :headerhandler
33 attr_reader :streamhandler
34
35 attr_accessor :mapping_registry
36 attr_accessor :literal_mapping_registry
37
38 attr_reader :operation
39
40 def initialize(endpoint_url, soapaction, options)
41 @endpoint_url = endpoint_url
42 @soapaction = soapaction
43 @options = options
44 @streamhandler = HTTPStreamHandler.new(
45 @options["protocol.http"] ||= ::SOAP::Property.new)
46 @operation = {}
47 @mandatorycharset = nil
48 @allow_unqualified_element = true
49 @default_encodingstyle = nil
50 @generate_explicit_type = true
51 @headerhandler = Header::HandlerSet.new
52 @mapping_registry = nil
53 @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new
54 end
55
56 def inspect
57 "#<#{self.class}:#{@endpoint_url}>"
58 end
59
60 def endpoint_url
61 @endpoint_url
62 end
63
64 def endpoint_url=(endpoint_url)
65 @endpoint_url = endpoint_url
66 reset_stream
67 end
68
69 def reset_stream
70 @streamhandler.reset(@endpoint_url)
71 end
72
73 def set_wiredump_file_base(wiredump_file_base)
74 @streamhandler.wiredump_file_base = wiredump_file_base
75 end
76
77 def test_loopback_response
78 @streamhandler.test_loopback_response
79 end
80
81 def add_rpc_operation(qname, soapaction, name, param_def, opt = {})
82 opt[:request_qname] = qname
83 opt[:request_style] ||= :rpc
84 opt[:response_style] ||= :rpc
85 opt[:request_use] ||= :encoded
86 opt[:response_use] ||= :encoded
87 @operation[name] = Operation.new(soapaction, param_def, opt)
88 end
89
90 def add_document_operation(soapaction, name, param_def, opt = {})
91 opt[:request_style] ||= :document
92 opt[:response_style] ||= :document
93 opt[:request_use] ||= :literal
94 opt[:response_use] ||= :literal
95 # default values of these values are unqualified in XML Schema.
96 # set true for backward compatibility.
97 unless opt.key?(:elementformdefault)
98 opt[:elementformdefault] = true
99 end
100 unless opt.key?(:attributeformdefault)
101 opt[:attributeformdefault] = true
102 end
103 @operation[name] = Operation.new(soapaction, param_def, opt)
104 end
105
106 # add_method is for shortcut of typical rpc/encoded method definition.
107 alias add_method add_rpc_operation
108 alias add_rpc_method add_rpc_operation
109 alias add_document_method add_document_operation
110
111 def invoke(req_header, req_body, opt = nil)
112 opt ||= create_encoding_opt
113 route(req_header, req_body, opt, opt)
114 end
115
116 def call(name, *params)
117 unless op_info = @operation[name]
118 raise MethodDefinitionError, "method: #{name} not defined"
119 end
120 mapping_opt = create_mapping_opt
121 req_header = create_request_header
122 req_body = SOAPBody.new(
123 op_info.request_body(params, @mapping_registry,
124 @literal_mapping_registry, mapping_opt)
125 )
126 reqopt = create_encoding_opt(
127 :soapaction => op_info.soapaction || @soapaction,
128 :envelopenamespace => @options["soap.envelope.requestnamespace"],
129 :default_encodingstyle =>
130 @default_encodingstyle || op_info.request_default_encodingstyle,
131 :elementformdefault => op_info.elementformdefault,
132 :attributeformdefault => op_info.attributeformdefault
133 )
134 resopt = create_encoding_opt(
135 :envelopenamespace => @options["soap.envelope.responsenamespace"],
136 :default_encodingstyle =>
137 @default_encodingstyle || op_info.response_default_encodingstyle,
138 :elementformdefault => op_info.elementformdefault,
139 :attributeformdefault => op_info.attributeformdefault
140 )
141 env = route(req_header, req_body, reqopt, resopt)
142 raise EmptyResponseError unless env
143 receive_headers(env.header)
144 begin
145 check_fault(env.body)
146 rescue ::SOAP::FaultError => e
147 op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry)
148 end
149 op_info.response_obj(env.body, @mapping_registry,
150 @literal_mapping_registry, mapping_opt)
151 end
152
153 def route(req_header, req_body, reqopt, resopt)
154 req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body)
155 unless reqopt[:envelopenamespace].nil?
156 set_envelopenamespace(req_env, reqopt[:envelopenamespace])
157 end
158 reqopt[:external_content] = nil
159 conn_data = marshal(req_env, reqopt)
160 if ext = reqopt[:external_content]
161 mime = MIMEMessage.new
162 ext.each do |k, v|
163 mime.add_attachment(v.data)
164 end
165 mime.add_part(conn_data.send_string + "\r\n")
166 mime.close
167 conn_data.send_string = mime.content_str
168 conn_data.send_contenttype = mime.headers['content-type'].str
169 end
170 conn_data = @streamhandler.send(@endpoint_url, conn_data,
171 reqopt[:soapaction])
172 if conn_data.receive_string.empty?
173 return nil
174 end
175 unmarshal(conn_data, resopt)
176 end
177
178 def check_fault(body)
179 if body.fault
180 raise SOAP::FaultError.new(body.fault)
181 end
182 end
183
184private
185
186 def set_envelopenamespace(env, namespace)
187 env.elename = XSD::QName.new(namespace, env.elename.name)
188 if env.header
189 env.header.elename = XSD::QName.new(namespace, env.header.elename.name)
190 end
191 if env.body
192 env.body.elename = XSD::QName.new(namespace, env.body.elename.name)
193 end
194 end
195
196 def create_request_header
197 headers = @headerhandler.on_outbound
198 if headers.empty?
199 nil
200 else
201 h = ::SOAP::SOAPHeader.new
202 headers.each do |header|
203 h.add(header.elename.name, header)
204 end
205 h
206 end
207 end
208
209 def receive_headers(headers)
210 @headerhandler.on_inbound(headers) if headers
211 end
212
213 def marshal(env, opt)
214 send_string = Processor.marshal(env, opt)
215 StreamHandler::ConnectionData.new(send_string)
216 end
217
218 def unmarshal(conn_data, opt)
219 contenttype = conn_data.receive_contenttype
220 if /#{MIMEMessage::MultipartContentType}/i =~ contenttype
221 opt[:external_content] = {}
222 mime = MIMEMessage.parse("Content-Type: " + contenttype,
223 conn_data.receive_string)
224 mime.parts.each do |part|
225 value = Attachment.new(part.content)
226 value.contentid = part.contentid
227 obj = SOAPAttachment.new(value)
228 opt[:external_content][value.contentid] = obj if value.contentid
229 end
230 opt[:charset] = @mandatorycharset ||
231 StreamHandler.parse_media_type(mime.root.headers['content-type'].str)
232 env = Processor.unmarshal(mime.root.content, opt)
233 else
234 opt[:charset] = @mandatorycharset ||
235 ::SOAP::StreamHandler.parse_media_type(contenttype)
236 env = Processor.unmarshal(conn_data.receive_string, opt)
237 end
238 unless env.is_a?(::SOAP::SOAPEnvelope)
239 raise ResponseFormatError.new(
240 "response is not a SOAP envelope: #{conn_data.receive_string}")
241 end
242 env
243 end
244
245 def create_header(headers)
246 header = SOAPHeader.new()
247 headers.each do |content, mustunderstand, encodingstyle|
248 header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle))
249 end
250 header
251 end
252
253 def create_encoding_opt(hash = nil)
254 opt = {}
255 opt[:default_encodingstyle] = @default_encodingstyle
256 opt[:allow_unqualified_element] = @allow_unqualified_element
257 opt[:generate_explicit_type] = @generate_explicit_type
258 opt[:no_indent] = @options["soap.envelope.no_indent"]
259 opt[:use_numeric_character_reference] =
260 @options["soap.envelope.use_numeric_character_reference"]
261 opt.update(hash) if hash
262 opt
263 end
264
265 def create_mapping_opt(hash = nil)
266 opt = {
267 :external_ces => @options["soap.mapping.external_ces"]
268 }
269 opt.update(hash) if hash
270 opt
271 end
272
273 class Operation
274 attr_reader :soapaction
275 attr_reader :request_style
276 attr_reader :response_style
277 attr_reader :request_use
278 attr_reader :response_use
279 attr_reader :elementformdefault
280 attr_reader :attributeformdefault
281
282 def initialize(soapaction, param_def, opt)
283 @soapaction = soapaction
284 @request_style = opt[:request_style]
285 @response_style = opt[:response_style]
286 @request_use = opt[:request_use]
287 @response_use = opt[:response_use]
288 # set nil(unqualified) by default
289 @elementformdefault = opt[:elementformdefault]
290 @attributeformdefault = opt[:attributeformdefault]
291 check_style(@request_style)
292 check_style(@response_style)
293 check_use(@request_use)
294 check_use(@response_use)
295 if @request_style == :rpc
296 @rpc_request_qname = opt[:request_qname]
297 if @rpc_request_qname.nil?
298 raise MethodDefinitionError.new("rpc_request_qname must be given")
299 end
300 @rpc_method_factory =
301 RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction)
302 else
303 @doc_request_qnames = []
304 @doc_request_qualified = []
305 @doc_response_qnames = []
306 @doc_response_qualified = []
307 param_def.each do |inout, paramname, typeinfo, eleinfo|
308 klass_not_used, nsdef, namedef = typeinfo
309 qualified = eleinfo
310 if namedef.nil?
311 raise MethodDefinitionError.new("qname must be given")
312 end
313 case inout
314 when SOAPMethod::IN
315 @doc_request_qnames << XSD::QName.new(nsdef, namedef)
316 @doc_request_qualified << qualified
317 when SOAPMethod::OUT
318 @doc_response_qnames << XSD::QName.new(nsdef, namedef)
319 @doc_response_qualified << qualified
320 else
321 raise MethodDefinitionError.new(
322 "illegal inout definition for document style: #{inout}")
323 end
324 end
325 end
326 end
327
328 def request_default_encodingstyle
329 (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace
330 end
331
332 def response_default_encodingstyle
333 (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace
334 end
335
336 def request_body(values, mapping_registry, literal_mapping_registry, opt)
337 if @request_style == :rpc
338 request_rpc(values, mapping_registry, literal_mapping_registry, opt)
339 else
340 request_doc(values, mapping_registry, literal_mapping_registry, opt)
341 end
342 end
343
344 def response_obj(body, mapping_registry, literal_mapping_registry, opt)
345 if @response_style == :rpc
346 response_rpc(body, mapping_registry, literal_mapping_registry, opt)
347 else
348 response_doc(body, mapping_registry, literal_mapping_registry, opt)
349 end
350 end
351
352 def raise_fault(e, mapping_registry, literal_mapping_registry)
353 if @response_style == :rpc
354 Mapping.fault2exception(e, mapping_registry)
355 else
356 Mapping.fault2exception(e, literal_mapping_registry)
357 end
358 end
359
360 private
361
362 def check_style(style)
363 unless [:rpc, :document].include?(style)
364 raise MethodDefinitionError.new("unknown style: #{style}")
365 end
366 end
367
368 def check_use(use)
369 unless [:encoded, :literal].include?(use)
370 raise MethodDefinitionError.new("unknown use: #{use}")
371 end
372 end
373
374 def request_rpc(values, mapping_registry, literal_mapping_registry, opt)
375 if @request_use == :encoded
376 request_rpc_enc(values, mapping_registry, opt)
377 else
378 request_rpc_lit(values, literal_mapping_registry, opt)
379 end
380 end
381
382 def request_doc(values, mapping_registry, literal_mapping_registry, opt)
383 if @request_use == :encoded
384 request_doc_enc(values, mapping_registry, opt)
385 else
386 request_doc_lit(values, literal_mapping_registry, opt)
387 end
388 end
389
390 def request_rpc_enc(values, mapping_registry, opt)
391 method = @rpc_method_factory.dup
392 names = method.input_params
393 obj = create_request_obj(names, values)
394 soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname, opt)
395 method.set_param(soap)
396 method
397 end
398
399 def request_rpc_lit(values, mapping_registry, opt)
400 method = @rpc_method_factory.dup
401 params = {}
402 idx = 0
403 method.input_params.each do |name|
404 params[name] = Mapping.obj2soap(values[idx], mapping_registry,
405 XSD::QName.new(nil, name), opt)
406 idx += 1
407 end
408 method.set_param(params)
409 method
410 end
411
412 def request_doc_enc(values, mapping_registry, opt)
413 (0...values.size).collect { |idx|
414 ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt)
415 ele.elename = @doc_request_qnames[idx]
416 ele
417 }
418 end
419
420 def request_doc_lit(values, mapping_registry, opt)
421 (0...values.size).collect { |idx|
422 ele = Mapping.obj2soap(values[idx], mapping_registry,
423 @doc_request_qnames[idx], opt)
424 ele.encodingstyle = LiteralNamespace
425 if ele.respond_to?(:qualified)
426 ele.qualified = @doc_request_qualified[idx]
427 end
428 ele
429 }
430 end
431
432 def response_rpc(body, mapping_registry, literal_mapping_registry, opt)
433 if @response_use == :encoded
434 response_rpc_enc(body, mapping_registry, opt)
435 else
436 response_rpc_lit(body, literal_mapping_registry, opt)
437 end
438 end
439
440 def response_doc(body, mapping_registry, literal_mapping_registry, opt)
441 if @response_use == :encoded
442 return *response_doc_enc(body, mapping_registry, opt)
443 else
444 return *response_doc_lit(body, literal_mapping_registry, opt)
445 end
446 end
447
448 def response_rpc_enc(body, mapping_registry, opt)
449 ret = nil
450 if body.response
451 ret = Mapping.soap2obj(body.response, mapping_registry,
452 @rpc_method_factory.retval_class_name, opt)
453 end
454 if body.outparams
455 outparams = body.outparams.collect { |outparam|
456 Mapping.soap2obj(outparam, mapping_registry, nil, opt)
457 }
458 [ret].concat(outparams)
459 else
460 ret
461 end
462 end
463
464 def response_rpc_lit(body, mapping_registry, opt)
465 body.root_node.collect { |key, value|
466 Mapping.soap2obj(value, mapping_registry,
467 @rpc_method_factory.retval_class_name, opt)
468 }
469 end
470
471 def response_doc_enc(body, mapping_registry, opt)
472 body.collect { |key, value|
473 Mapping.soap2obj(value, mapping_registry, nil, opt)
474 }
475 end
476
477 def response_doc_lit(body, mapping_registry, opt)
478 body.collect { |key, value|
479 Mapping.soap2obj(value, mapping_registry)
480 }
481 end
482
483 def create_request_obj(names, params)
484 o = Object.new
485 idx = 0
486 while idx < params.length
487 o.instance_variable_set('@' + names[idx], params[idx])
488 idx += 1
489 end
490 o
491 end
492 end
493end
494
495
496end
497end
Note: See TracBrowser for help on using the repository browser.