aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/test_invoke.rb
blob: 44601c1c1141c5e958eb120475f28bd791911bd9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'test/unit'

module Test
  module Unit
    class TestCase # :nodoc:
      private
        # invoke the specified API method
        def invoke_direct(method_name, *args)
          prepare_request('api', 'api', method_name, *args)
          @controller.process(@request, @response)
          decode_rpc_response
        end
        alias_method :invoke, :invoke_direct

        # invoke the specified API method on the specified service
        def invoke_delegated(service_name, method_name, *args)
          prepare_request(service_name.to_s, service_name, method_name, *args)
          @controller.process(@request, @response)
          decode_rpc_response
        end

        # invoke the specified layered API method on the correct service
        def invoke_layered(service_name, method_name, *args)
          if protocol == :soap
            raise "SOAP protocol support for :layered dispatching mode is not available"
          end
          prepare_request('api', service_name, method_name, *args)
          @controller.process(@request, @response)
          decode_rpc_response
        end

        # ---------------------- internal ---------------------------

        def prepare_request(action, service_name, api_method_name, *args)
          @request.request_parameters['action'] = action
          @request.env['REQUEST_METHOD'] = 'POST'
          @request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
          @request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
          case protocol
          when :soap
            soap_action = "/#{@controller.controller_name}/#{service_name}/#{public_method_name(service_name, api_method_name)}" 
            @request.env['HTTP_SOAPACTION'] = soap_action
          when :xmlrpc
            @request.env.delete('HTTP_SOAPACTION')
          end
        end

        def encode_rpc_call(service_name, api_method_name, *args)
          case @controller.web_service_dispatching_mode
          when :direct
            api = @controller.class.web_service_api
          when :delegated, :layered
            api = @controller.web_service_object(service_name.to_sym).class.web_service_api
          end
          info = api.api_methods[api_method_name.to_sym]
          ((info[:expects] || []) + (info[:returns] || [])).each do |spec|
            marshaler.register_type spec
          end
          expects = info[:expects]
          args = args.dup
          (0..(args.length-1)).each do |i|
            type_binding = marshaler.register_type(expects ? expects[i] : args[i].class)
            info = WS::ParamInfo.create(expects ? expects[i] : args[i].class, type_binding, i)
            args[i] = marshaler.marshal(WS::Param.new(args[i], info))
          end
          encoder.encode_rpc_call(public_method_name(service_name, api_method_name), args)
        end

        def decode_rpc_response
          public_method_name, return_value = encoder.decode_rpc_response(@response.body)
          result = marshaler.unmarshal(return_value).value
          unless @return_exceptions
            exception = is_exception?(result)
            raise exception if exception
          end
          result
        end

        def public_method_name(service_name, api_method_name)
          public_name = service_api(service_name).public_api_method_name(api_method_name)
          if @controller.web_service_dispatching_mode == :layered
            '%s.%s' % [service_name.to_s, public_name]
          else
            public_name
          end
        end

        def service_api(service_name)
          case @controller.web_service_dispatching_mode
          when :direct
            @controller.class.web_service_api
          when :delegated, :layered
            @controller.web_service_object(service_name.to_sym).class.web_service_api
          end
        end

        def protocol
          @protocol ||= :soap
        end

        def marshaler
          case protocol
          when :soap
            @soap_marshaler ||= WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
          when :xmlrpc
            @xmlrpc_marshaler ||= WS::Marshaling::XmlRpcMarshaler.new
          end
        end

        def encoder
          case protocol
          when :soap
            @soap_encoder ||= WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
          when :xmlrpc
            @xmlrpc_encoder ||= WS::Encoding::XmlRpcEncoding.new
          end
        end

        def is_exception?(obj)
          case protocol
          when :soap
            (obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
            obj.detail.cause.is_a?(Exception)) ? obj.detail.cause : nil
          when :xmlrpc
            obj.is_a?(XMLRPC::FaultException) ? obj : nil
          end
        end
    end
  end
end