aboutsummaryrefslogtreecommitdiffstats
path: root/actionservice/lib/action_service/protocol/abstract.rb
blob: bd02b6e829a65c37858feab264a4fd3757ba0a66 (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
module ActionService # :nodoc:
  module Protocol # :nodoc:
    CheckedMessage = :checked
    UncheckedMessage = :unchecked

    class ProtocolError < ActionService::ActionServiceError # :nodoc:
    end

    class AbstractProtocol # :nodoc:
      attr :container_class

      def initialize(container_class)
        @container_class = container_class
      end

      def unmarshal_request(protocol_request)
        raise NotImplementedError
      end

      def marshal_response(protocol_request, return_value)
        raise NotImplementedError
      end

      def marshal_exception(exception)
        raise NotImplementedError
      end

      def self.create_protocol_request(container_class, action_pack_request)
        nil
      end

      def self.create_protocol_client(api, protocol_name, endpoint_uri, options)
        nil
      end
    end

    class AbstractProtocolMessage # :nodoc:
      attr_accessor :signature
      attr_accessor :return_signature
      attr_accessor :type
      attr :options

      def initialize(options={})
        @signature = @return_signature = nil
        @options = options
        @type = @options[:type] || CheckedMessage
      end

      def signature=(value)
        return if value.nil?
        @signature = []
        value.each do |klass|
          if klass.is_a?(Hash)
            @signature << klass.values.shift
          else
            @signature << klass
          end
        end
        @signature
      end

      def checked?
        @type == CheckedMessage
      end

      def check_parameter_types(values, signature)
        return unless checked? && signature
        unless signature.length == values.length
          raise(ProtocolError, "Signature and parameter lengths mismatch")
        end
        (1..signature.length).each do |i|
          check_compatibility(signature[i-1], values[i-1].class)
        end
      end

      def check_compatibility(expected_class, received_class)
        return if \
            (expected_class == TrueClass or expected_class == FalseClass) and \
            (received_class == TrueClass or received_class == FalseClass)
        unless received_class.ancestors.include?(expected_class) or \
               expected_class.ancestors.include?(received_class)
          raise(ProtocolError, "value of type #{received_class.name} is not " +
                               "compatible with expected type #{expected_class.name}")
        end
      end
    end

    class ProtocolRequest < AbstractProtocolMessage # :nodoc:
      attr :protocol
      attr :raw_body

      attr_accessor :web_service_name
      attr_accessor :public_method_name
      attr_accessor :content_type

      def initialize(protocol, raw_body, web_service_name, public_method_name, content_type, options={})
        super(options)
        @protocol = protocol
        @raw_body = raw_body
        @web_service_name = web_service_name
        @public_method_name = public_method_name
        @content_type = content_type
      end

      def unmarshal
        @protocol.unmarshal_request(self)
      end

      def marshal(return_value)
        @protocol.marshal_response(self, return_value)
      end
    end

    class ProtocolResponse < AbstractProtocolMessage # :nodoc:
      attr :protocol
      attr :raw_body

      attr_accessor :content_type

      def initialize(protocol, raw_body, content_type, options={})
        super(options)
        @protocol = protocol
        @raw_body = raw_body
        @content_type = content_type
      end
    end
  end
end