summaryrefslogtreecommitdiff
path: root/lib/soap/rpc/soaplet.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/soap/rpc/soaplet.rb')
-rw-r--r--lib/soap/rpc/soaplet.rb167
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