diff options
Diffstat (limited to 'lib/soap/rpc/soaplet.rb')
-rw-r--r-- | lib/soap/rpc/soaplet.rb | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/soap/rpc/soaplet.rb b/lib/soap/rpc/soaplet.rb new file mode 100644 index 0000000000..1a4ef99b76 --- /dev/null +++ b/lib/soap/rpc/soaplet.rb @@ -0,0 +1,167 @@ +=begin +SOAP4R - SOAP handler servlet for WEBrick +Copyright (C) 2001, 2002, 2003 NAKAMURA, Hiroshi. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PRATICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 675 Mass +Ave, Cambridge, MA 02139, USA. +=end + + +require 'webrick/httpservlet/abstract' +require 'webrick/httpstatus' +require 'soap/rpc/router' +require 'soap/streamHandler' + +module SOAP +module RPC + + +class SOAPlet < WEBrick::HTTPServlet::AbstractServlet +public + attr_reader :app_scope_router + + def initialize + @router_map = {} + @app_scope_router = ::SOAP::RPC::Router.new(self.class.name) + end + + # Add servant klass whose object has request scope. A servant object is + # instanciated for each request. + # + # Bare in mind that servant klasses are distinguished by HTTP SOAPAction + # header in request. Client which calls request-scoped servant must have a + # SOAPAction header which is a namespace of the servant klass. + # I mean, use Driver#add_method_with_soapaction instead of Driver#add_method + # at client side. + # + def add_rpc_request_servant(klass, namespace, mapping_registry = nil) + router = RequestRouter.new(klass, namespace, mapping_registry) + add_router(namespace, router) + end + + # Add servant object which has application scope. + def add_rpc_servant(obj, namespace) + router = @app_scope_router + SOAPlet.add_servant_to_router(router, obj, namespace) + add_router(namespace, router) + end + alias add_servant add_rpc_servant + + + ### + ## Servlet interfaces for WEBrick. + # + def get_instance(config, *options) + @config = config + self + end + + def require_path_info? + false + end + + def do_GET(req, res) + res.header['Allow'] = 'POST' + raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed." + end + + def do_POST(req, res) + namespace = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) + router = lookup_router(namespace) + + is_fault = false + + charset = ::SOAP::StreamHandler.parse_media_type(req['content-type']) + begin + response_stream, is_fault = router.route(req.body, charset) + rescue Exception => e + response_stream = router.create_fault_response(e) + is_fault = true + end + + res.body = response_stream + res['content-type'] = "text/xml; charset=\"#{charset}\"" + if response_stream.is_a?(IO) + res.chunked = true + end + + if is_fault + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR + end + end + +private + + class RequestRouter < ::SOAP::RPC::Router + def initialize(klass, namespace, mapping_registry = nil) + super(namespace) + if mapping_registry + self.mapping_registry = mapping_registry + end + @klass = klass + @namespace = namespace + end + + def route(soap_string) + obj = @klass.new + namespace = self.actor + router = ::SOAP::RPC::Router.new(@namespace) + SOAPlet.add_servant_to_router(router, obj, namespace) + router.route(soap_string) + end + end + + def add_router(namespace, router) + @router_map[namespace] = router + end + + def parse_soapaction(soapaction) + if /^"(.*)"$/ =~ soapaction + soapaction = $1 + end + if soapaction.empty? + return nil + end + soapaction + end + + def lookup_router(namespace) + if namespace + @router_map[namespace] || @app_scope_router + else + @app_scope_router + end + end + + class << self + public + def add_servant_to_router(router, obj, namespace) + ::SOAP::RPC.defined_methods(obj).each do |name| + add_servant_method_to_router(router, obj, namespace, name) + end + end + + def add_servant_method_to_router(router, obj, namespace, name) + qname = XSD::QName.new(namespace, name) + soapaction = nil + method = obj.method(name) + param_def = ::SOAP::RPC::SOAPMethod.create_param_def( + (1..method.arity.abs).collect { |i| "p#{ i }" }) + router.add_method(obj, qname, soapaction, name, param_def) + end + end +end + + +end +end |