Class: Marshaling::Marshaler

Inherits:
Object
  • Object
show all
Defined in:
lib/rbc/bsi.rb

Overview

Exception dispatcher based on error logged by BSI

Constant Summary collapse

SSL_RETRY_LIMIT =
5

Instance Method Summary collapse

Constructor Details

#initialize(url, options = {:verify=>true}) ⇒ Marshaler

Returns a new instance of Marshaler.



48
49
50
51
52
53
# File 'lib/rbc/bsi.rb', line 48

def initialize(url, options={:verify=>true})
  @target_url = url
  @debug      = options[:debug]
  @stealth    = options[:stealth]
  @verify_ssl = options[:verify]
end

Instance Method Details

#array_to_xml(noko, array) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/rbc/bsi.rb', line 160

def array_to_xml(noko, array)
    noko.value{
      noko.array{
        noko.data{
          array.each do |e|
            send("#{e.class.to_s.downcase}_to_xml".to_sym, noko, e)
          end
        }
      }
    }
end

#build_call(method_name, *arguments) ⇒ Object

Build xml for submission



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rbc/bsi.rb', line 56

def build_call(method_name, *arguments)

  builder = Nokogiri::XML::Builder.new do |xml|
    xml.methodCall{
      xml.methodName_ method_name.gsub(/_/, '.')
      xml.params{
        arguments.each do |a|
          xml.param{
            unless a.nil?
              type = a.class.to_s.downcase
              send("#{type}_to_xml", xml, a)
            else
              raise "Nil is not an acceptable argument for method: #{method_name}#{arguments.to_s.gsub(/\]/, ')').gsub(/\[/, '(')}"
            end
          }
        end
      }
    }
  end

  # Submit xml to them
  send_xml( builder.to_xml )
end

#convert_array(xml) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/rbc/bsi.rb', line 208

def convert_array(xml)
  array = Array.new
  unless xml['data'].nil?
    case xml['data']['value'].class.to_s.downcase
    when 'array'
      xml['data']['value'].each do |e|
        member_type  = e.keys.first
        member_value = e[member_type]
        array << send( "convert_#{member_type}".to_sym, member_value )
      end
    when 'hash'
      member_type  = xml['data']['value'].keys.first
      member_value = xml['data']['value'][member_type]
      array << send( "convert_#{member_type.gsub(/\./, '_')}".to_sym, member_value )
    end
  else
    array = nil
  end
  array
end

#convert_boolean(xml) ⇒ Object



234
235
236
# File 'lib/rbc/bsi.rb', line 234

def convert_boolean(xml)
  xml
end

#convert_dateTime_iso8601(xml) ⇒ Object



246
247
248
# File 'lib/rbc/bsi.rb', line 246

def convert_dateTime_iso8601(xml)
  DateTime.parse(xml)
end

#convert_int(xml) ⇒ Object

Methods to convert XML BSI sends back to us into ruby



230
231
232
# File 'lib/rbc/bsi.rb', line 230

def convert_int(xml)
  xml.to_i
end

#convert_nil(xml) ⇒ Object



238
239
240
# File 'lib/rbc/bsi.rb', line 238

def convert_nil(xml)
  nil
end

#convert_string(xml) ⇒ Object



242
243
244
# File 'lib/rbc/bsi.rb', line 242

def convert_string(xml)
  xml
end

#convert_struct(xml) ⇒ Object



197
198
199
200
201
202
203
204
205
206
# File 'lib/rbc/bsi.rb', line 197

def convert_struct(xml)
  hash = Hash.new
  xml['member'].each do |e|
    member_name  = e['name']
    member_value_type = e['value'].keys.first
    member_value = send("convert_#{ member_value_type.gsub(/\./, '_') }".to_sym, e['value'][member_value_type] )
    hash.store( member_name, member_value )
  end
  hash
end

#enumerator_to_xml(noko, enumerator) ⇒ Object



150
151
152
153
154
155
156
157
158
# File 'lib/rbc/bsi.rb', line 150

def enumerator_to_xml(noko, enumerator)
  # this should only be exercised when trying to pass a byte array
  # this should be sent enclosed in <base64> and encoded as such

  noko.value{
    noko.base64_ Base64.encode64(enumerator.to_a.pack('c*'))
  }

end

#fixnum_to_xml(noko, int) ⇒ Object



191
192
193
194
195
# File 'lib/rbc/bsi.rb', line 191

def fixnum_to_xml(noko, int)
  noko.value{
    noko.int_ int
  }
end

#float_to_xml(noko, float) ⇒ Object

Methods to convert ruby structures into XML in the format BSI expects



144
145
146
147
148
# File 'lib/rbc/bsi.rb', line 144

def float_to_xml(noko, float)
  noko.value{
    noko.float_ float
  }
end

#generate_exception(code, message) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rbc/bsi.rb', line 35

def generate_exception(code, message)
  case code
  when 9000
    # 9000 level
    case message
    when 'Logon failed: Broken pipe'
      raise Error.new(code, message, 'retry')
    end
  else
    raise Error.new(code, message)
  end
end

#hash_to_xml(noko, hash) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/rbc/bsi.rb', line 172

def hash_to_xml(noko, hash)
    noko.value{
      noko.struct{
        hash.each do |k,v|
          noko.member{
            noko.name_ k.to_s
            send("#{v.class.to_s.downcase}_to_xml".to_sym, noko, v) unless v.nil?
          }
        end
      }
    }
end

#parse(xml) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rbc/bsi.rb', line 80

def parse(xml)

  # Handle Errors appropriately
  unless xml['methodResponse'].keys.include?('fault')
    type = xml['methodResponse']['params']['param']['value'].keys.pop
    # Handle happy path, no errors
    send("convert_#{type}".to_sym, xml['methodResponse']['params']['param']['value'][type])
  else
    # Error occurred, extract it, notify
    code = xml['methodResponse']['fault']['value']['struct']['member'][0]['value']['int'].to_i
    message = xml['methodResponse']['fault']['value']['struct']['member'][1]['value']['string']
    # How we should generate exceptions
    generate_exception(code, message)
  end
end

#send_xml(xml) ⇒ Object



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
131
132
133
134
135
136
# File 'lib/rbc/bsi.rb', line 96

def send_xml( xml)

  options = {:body => xml}
  if @target_url.match(/https/)
    options.merge!(:ssl_version=>:SSLv3)
    options.merge!(:verify => @verify_ssl)
  end
  if @debug
    puts "Sending:"
    puts xml
    puts ""
  end

  try_num = 0
  unless @stealth
    begin
      response =  HTTParty.post(@target_url, options)
    rescue OpenSSL::SSL::SSLError => e
      if try_num < SSL_RETRY_LIMIT
        try_num = try_num + 1
        puts "SSL error.  Retry #{try_num}"
        retry
      else
        raise e
      end
    rescue Error => e
      puts 'Broken Pipe error, retrying'
      retry if e.action == 'retry'
    end
  end

  unless @stealth
    if @debug
      puts "Recieved:"
      puts Nokogiri::XML(response.body, &:noblanks)
    end

    parse(response)
  end

end

#string_to_xml(noko, string) ⇒ Object



185
186
187
188
189
# File 'lib/rbc/bsi.rb', line 185

def string_to_xml(noko, string)
  noko.value{
    noko.string_ string
  }
end

#test_send_xml(xml) ⇒ Object



138
139
140
# File 'lib/rbc/bsi.rb', line 138

def test_send_xml(xml)
  puts xml
end