deepsecurity 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ # @author Udo Schneider <Udo.Schneider@homeaddress.de>
2
+
3
+ module SavonHelper
4
+
5
+ class SOAPInterface
6
+
7
+ def initialize(wsdl_url, logger = Logger.new(STDOUT), log_level = nil, options = {})
8
+ @client = Savon.client(options.merge({:wsdl => wsdl_url,
9
+ :logger => logger,
10
+ :log_level => log_level,
11
+ :log => (!log_level.nil?),
12
+ :ssl_verify_mode => :none}))
13
+ @logger = logger
14
+ end
15
+
16
+ def logger
17
+ @logger
18
+ end
19
+
20
+ # @!group Request Helper
21
+
22
+ # Send a Request to the SOAP API for method with arguments and unwrap the response
23
+ # @param method [Symbol] The SOAP method to call.
24
+ # @param arguments [Hash] The method arguments
25
+ # @return [Hash] The result hash.
26
+ def send_soap(method, arguments = {})
27
+ logger.debug { "#{self.class}\##{__method__}(#{method.inspect}, #{arguments.inspect})" }
28
+ retryable(:tries => 5, :on => Errno::ECONNRESET) do
29
+ response = @client.call method, :message => arguments
30
+ return response.to_hash[(method.to_s+"_response").to_sym][(method.to_s+"_return").to_sym]
31
+ end
32
+ end
33
+
34
+ # Helper Method deserializing the SOAP response into an object
35
+ # @param method_name [Symbol] The SOAP method to call.
36
+ # @param object_class [MappingObject] The class to typecast the result to.
37
+ # @param arguments [Hash] The method arguments
38
+ # @return [object_class] The object filled from the response.
39
+ def request_object(method_name, object_class, arguments={})
40
+ data = send_soap(method_name, arguments)
41
+ # ObjectMapping.to_native(object_class, data, self)
42
+ object_class.from_savon(data, self)
43
+ # raise "Halt"
44
+ end
45
+
46
+ # Helper Method deserializing the SOAP response into an array of objects.
47
+ # @param method_name [Symbol] The SOAP method to call.
48
+ # @param object_class [MappingObject] The element class to typecast the result elements to.
49
+ # @param collection_name [Symbol] The name of the reply parameter.
50
+ # @param arguments [Hash] The method arguments
51
+ # @return [Array<object_class>] The object filled from the response.
52
+ def request_array(method_name, object_class, collection_name = nil, arguments={})
53
+ data = send_soap(method_name, arguments)
54
+ data = data[collection_name] unless collection_name.blank?
55
+ ArrayMapping.to_native(ObjectMapping.new(object_class), data, self)
56
+ # SavonHelper::ArrayMapping.new(SavonHelper::ObjectMapping.new(object_class)).from_savon_data(data)
57
+ end
58
+
59
+ # @!endgroup
60
+
61
+ def retryable(options = {}, &block)
62
+ opts = {:tries => 1, :on => Exception}.merge(options)
63
+
64
+ retry_exception, retries = opts[:on], opts[:tries]
65
+
66
+ begin
67
+ return yield
68
+ rescue retry_exception
69
+ retry if (retries -= 1) > 0
70
+ end
71
+
72
+ yield
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -2,11 +2,11 @@
2
2
 
3
3
  module SavonHelper
4
4
 
5
- # A TypeMappng class is responsible for converting between Savon primitive types and compound Ruby Types
5
+ # A TypeMapping class is responsible for converting between Savon primitive types and Ruby Types
6
6
  class TypeMapping
7
7
 
8
8
  # A new instance of TypeMapping with description
9
- # @param [String] description
9
+ # @param description [String] A String describing the mapping.
10
10
  # @return [TypeMapping]
11
11
  def initialize(description='')
12
12
  @description = description
@@ -14,18 +14,18 @@ module SavonHelper
14
14
 
15
15
  # @!group Converting
16
16
 
17
- # Convert from Savon data to Ruby value
18
- # @param [Hash] data Savon data
17
+ # @abstract Convert from Savon data to Ruby value
18
+ # @param data [Hash, Object] Source Savon data
19
19
  # @return [Object]
20
- def from_savon_data(data)
21
- logger.error { "#{self.class}##{__method__}(#{data.inspect}) not implemented!" }
20
+ def to_native(data)
21
+ raise "#{self.class}##{__method__}(#{data.inspect}) not implemented!"
22
22
  end
23
23
 
24
- # Convert from Ruby value type to Savon data
25
- # @param [Object] value Ruby value
24
+ # @abstract Convert from Ruby value type to Savon data
25
+ # @param value [Object] Source Ruby value
26
26
  # @return [Object]
27
- def to_savon_data(value)
28
- logger.error { "#{self.class}##{__method__}(#{value.inspect}) not implemented!" }
27
+ def to_savon(value)
28
+ raise "#{self.class}##{__method__}(#{value.inspect}) not implemented!"
29
29
  end
30
30
 
31
31
  # @!endgroup
@@ -36,278 +36,405 @@ module SavonHelper
36
36
  @description
37
37
  end
38
38
 
39
- # Return the class represented by the mapping.
39
+ # @abstract Return the class represented by the mapping.
40
40
  # @return [Class]
41
41
  def object_klass
42
- logger.error { "#{self.class}##{__method__}() not implemented!" }
42
+ raise "#{self.class}##{__method__}() not implemented!"
43
43
  end
44
44
 
45
- # Return the class description represented by the mapping.
45
+ # @abstract Return the class description represented by the mapping.
46
46
  # @return [String]
47
47
  def type_string
48
- logger.error { "#{self.class}##{__method__}() not implemented!" }
49
- end
50
-
51
- # The current logger
52
- # @return [Logger]
53
- def logger
54
- DeepSecurity::logger
48
+ raise "#{self.class}##{__method__}() not implemented!"
55
49
  end
56
50
 
57
51
  end
58
52
 
59
- # ArrayMapping maps Savon data to Ruby Arrays
60
- class ArrayMapping < TypeMapping
61
-
53
+ # BooleanMapping maps Savon data to Ruby Booleans.
54
+ class BooleanMapping < TypeMapping
62
55
 
63
- # Convert the given Savon data to an Array consisting of elements of class klass
64
- # @param [TypeMapping] element_mapping TypeMapping for elements
65
- # @param [Hash,Array] data Savon Data
66
- # @return [Array<Object>]
67
- def self.from_savon_data(element_mapping, data)
68
- return [] if data.blank?
69
- result = []
70
- if data.is_a?(Array)
71
- data.each do |element|
72
- result << element_mapping.from_savon_data(element)
73
- end
74
- elsif data.is_a?(Hash)
75
- item = data[:item]
76
- if item.nil?
77
- result << element_mapping.from_savon_data(data)
78
- else
79
- result = from_savon_data(element_mapping, item)
80
- end
81
- else
82
- raise "Unknown Array mapping"
83
- end
84
- result
85
- end
56
+ # @!group Converting
86
57
 
87
- # A new instance of TypeMapping with description
88
- # @param [TypeMapping] element_mapping A TypeMapping for elements
89
- # @param [String] description
90
- # @return [ArrayMapping]
91
- def initialize(element_mapping, description='')
92
- super(description)
93
- @element_mapping = element_mapping
58
+ # Convert from Savon data to Ruby Boolean
59
+ # @param data [Hash, Boolean, String] Source Savon data
60
+ # @return [Boolean]
61
+ def to_native(data, interface)
62
+ data.to_s == "true"
94
63
  end
95
64
 
96
- # @!group Converting
97
-
98
- # Convert from Savon data to Ruby value
99
- # @param [Hash] data Savon data
100
- # @return [Array]
101
- def from_savon_data(data)
102
- self.class.from_savon_data(@element_mapping, data)
65
+ # Convert from Ruby Boolean type to Savon data
66
+ # @param value [Boolean] Source Ruby data
67
+ # @return [String]
68
+ def to_savon(value)
69
+ value.to_s
103
70
  end
104
71
 
105
72
  # @!endgroup
106
73
 
74
+
107
75
  # Return the class represented by the mapping.
108
- # @return [Class]
76
+ # @return [TrueClass] Return TrueClass as Ruby as no common Boolan class
109
77
  def object_klass
110
- @element_mapping.object_klass
78
+ TrueClass
111
79
  end
112
80
 
113
81
  # Return the class description represented by the mapping.
114
82
  # @return [String]
115
83
  def type_string
116
- "Array<#{@element_mapping.type_string}>"
84
+ "bool"
117
85
  end
118
86
 
119
87
  end
120
88
 
121
- # BooleanMapping maps Savon data to Ruby Booleans.
122
- class BooleanMapping < TypeMapping
89
+ # IntegerMapping maps Savon data to Ruby integers.
90
+ class IntegerMapping < TypeMapping
123
91
 
124
92
  # @!group Converting
125
93
 
126
- # Convert from Savon data to Ruby Boolean
127
- # @param [Hash] data Savon data
128
- # @return [Boolean]
129
- def from_savon_data(data)
130
- data.to_s == "true"
94
+ # Convert from Savon data to Ruby integers
95
+ # @param data [Hash, String] Source Savon data
96
+ # @return [Integer]
97
+ def to_native(data, interface)
98
+ Integer(data.to_s)
131
99
  end
132
100
 
133
- # Convert from Ruby Boolean type to Savon data
134
- # @param [Object] value Boolean
135
- # @return [Hash]
136
- def to_savon_data(value)
101
+ # Convert from Ruby float type to Savon data
102
+ # @param value [Integer] Source Ruby data
103
+ # @return [String]
104
+ def to_savon(value)
137
105
  value.to_s
138
106
  end
139
107
 
140
108
  # @!endgroup
141
109
 
110
+ # Return the class represented by the mapping.
111
+ # @return [Integer]
112
+ def object_klass
113
+ Integer
114
+ end
115
+
142
116
  # Return the class description represented by the mapping.
143
117
  # @return [String]
144
118
  def type_string
145
- "bool"
119
+ "int"
146
120
  end
147
-
148
121
  end
149
122
 
150
- class DatetimeMapping < TypeMapping
123
+ # FloatMapping maps Savon data to Ruby floats.
124
+ class FloatMapping < TypeMapping
151
125
 
152
- def from_savon_data(data)
153
- DateTime.parse(data.to_s)
126
+ # @!group Converting
127
+
128
+ # Convert from Savon data to Ruby floats
129
+ # @param data [Hash, String] Source Savon data
130
+ # @return [Float]
131
+ def to_native(data)
132
+ data.to_f
154
133
  end
155
134
 
156
- def to_savon_data(value)
157
- value.to_datetime.to_s
135
+ # Convert from Ruby float type to Savon data
136
+ # @param value [Float] Source Ruby data
137
+ # @return [String]
138
+ def to_savon(value)
139
+ value.to_s
140
+ end
141
+
142
+ # @!endgroup
143
+
144
+ # Return the class represented by the mapping.
145
+ # @return [Float]
146
+ def object_klass
147
+ Float
158
148
  end
159
149
 
150
+ # Return the class description represented by the mapping.
151
+ # @return [String]
160
152
  def type_string
161
- "datetime"
153
+ "float"
162
154
  end
163
155
 
164
156
  end
165
157
 
166
- class EnumMapping < TypeMapping
158
+ # StringMapping maps Savon data to Ruby strings.
159
+ class StringMapping < TypeMapping
167
160
 
168
- def initialize(enum, description='')
169
- super(description)
170
- @enum = enum
161
+ # @!group Converting
162
+
163
+ # Convert from Savon data to Ruby strings
164
+ # @param data [Hash, String] Source Savon data
165
+ # @return [String]
166
+ def to_native(data, interface)
167
+ data.to_s
171
168
  end
172
169
 
173
- def from_savon_data(data)
174
- @enum[data]
170
+ # Convert from Ruby string type to Savon data
171
+ # @param value [String] Source Ruby data
172
+ # @return [String]
173
+ def to_savon(value)
174
+ value.to_s
175
175
  end
176
176
 
177
- def to_savon_data(value)
178
- @enum.key(value)
177
+ # @!endgroup
178
+
179
+ # @abstract Return the class represented by the mapping.
180
+ # @todo Is this really neccessary?
181
+ # @return [Class]
182
+ def object_klass
183
+ String
179
184
  end
180
185
 
186
+ # Return the class description represented by the mapping.
187
+ # @return [String]
181
188
  def type_string
182
- "enum<#{@enum.values.join(', ')}>"
189
+ "String"
183
190
  end
184
191
 
185
192
  end
186
193
 
187
- class FloatMapping < TypeMapping
188
-
189
- def from_savon_data(data)
190
- data.to_f
191
- end
192
-
193
- def to_savon_data(value)
194
- value.to_s
195
- end
194
+ # IPAddressMapping maps Savon data to Ruby IP Address String.
195
+ # @note Currently IPAddressMapping only does a from/to String mapping. The IP Address is not parsed in any way!
196
+ class IPAddressMapping < StringMapping
196
197
 
198
+ # Return the class description represented by the mapping.
199
+ # @return [String]
197
200
  def type_string
198
- "float"
201
+ "IPAddress"
199
202
  end
200
203
 
201
204
  end
202
205
 
203
- class IntegerMapping < TypeMapping
206
+ # DatetimeMapping maps Savon data to Ruby DateTimes.
207
+ class DatetimeMapping < TypeMapping
204
208
 
205
- def from_savon_data(data)
206
- Integer(data.to_s)
209
+ # @!group Converting
210
+
211
+ # Convert from Savon data to Ruby datetime
212
+ # @param data [Hash, String] Source Savon data
213
+ # @return [DateTime]
214
+ def to_native(data, interface)
215
+ DateTime.parse(data.to_s)
207
216
  end
208
217
 
209
- def to_savon_data(value)
210
- value.to_s
218
+ # Convert from Ruby DateTime type to Savon data
219
+ # @param value [DateTime] Source Ruby data
220
+ # @return [String]
221
+ def to_savon(value)
222
+ value.to_datetime.to_s
211
223
  end
212
224
 
225
+ # @!endgroup
226
+
227
+ # Return the class represented by the mapping.
228
+ # @return [DateTime]
229
+ def object_klass
230
+ DateTime
231
+ end
232
+
233
+ # Return the class description represented by the mapping.
234
+ # @return [String]
213
235
  def type_string
214
- "int"
236
+ "datetime"
215
237
  end
238
+
216
239
  end
217
240
 
218
- class IPAddressMapping < TypeMapping
241
+ # EnumMapping maps Savon integers to Ruby symbols.
242
+ class EnumMapping < TypeMapping
219
243
 
220
- def from_savon_data(data)
221
- data.to_s
244
+ # A new instance of EnumMapping with description and enum hash enum.
245
+ # @param enum [Hash{String => Symbol}] Mapping between Savon Strings and Ruby Symbols.
246
+ # @param description [String]
247
+ # @return [ArrayMapping]
248
+ def initialize(enum, description='')
249
+ super(description)
250
+ @enum = enum
222
251
  end
223
252
 
224
- def to_savon_data(value)
225
- value.to_s
253
+ # @!group Converting
254
+
255
+ # Convert from Savon enum-String to Ruby Symbol
256
+ # @param data [String] Source Savon data
257
+ # @return [Symbol, nil]
258
+ def to_native(data, interface)
259
+ @enum[data]
226
260
  end
227
261
 
262
+ # Convert from Ruby DateTime Symbol to Savon enum-String
263
+ # @param value [Symbol] Source Ruby data
264
+ # @return [String]
265
+ def to_savon(value)
266
+ @enum.key(value)
267
+ end
268
+
269
+ # @!endgroup
270
+
271
+ # Return the class description represented by the mapping.
272
+ # @return [String]
228
273
  def type_string
229
- "IPAddress"
274
+ "enum<#{@enum.values.join(', ')}>"
230
275
  end
231
276
 
232
277
  end
233
278
 
234
- class ObjectMapping < TypeMapping
279
+ # HintMapping maps Savon data to Ruby objects of type klass (r/o).
280
+ class HintMapping < TypeMapping
235
281
 
282
+ # A new instance of ObjectMapping with description for class klass.
283
+ # @param klass [Class] A class returned by the hint accessor
284
+ # @param description [String]
285
+ # @return [HintMapping]
236
286
  def initialize(klass, description='')
237
287
  super(description)
238
288
  @klass = klass
239
289
  end
240
290
 
241
- def from_savon_data(data)
242
- @klass.from_savon_data(data)
243
- end
291
+ # @!endgroup
244
292
 
293
+ # @abstract Return the class represented by the mapping.
294
+ # @return [Class]
245
295
  def object_klass
246
296
  @klass
247
297
  end
248
298
 
299
+ # Return the class description represented by the mapping.
300
+ # @return [String]
249
301
  def type_string
250
- "#{@klass}"
302
+ "HINT<#{@klass.name_without_namespace}>"
251
303
  end
252
304
 
253
305
  end
254
306
 
255
- class StringMapping < TypeMapping
307
+ # ObjectMapping maps Savon data to Ruby Objects.
308
+ class ObjectMapping < HintMapping
256
309
 
257
- def from_savon_data(data)
258
- data.to_s
310
+ # Convert from Savon data to Ruby Object.
311
+ # @param data [Hash, String] Source Savon data
312
+ # @param klass [Class, #to_native] A class which can create instances from Savon data and provide Savon data for export.
313
+ # @return [SavonHelper::MappingObject, #to_native]
314
+ def self.to_native(klass, data, interface)
315
+ klass.from_savon(data, interface)
259
316
  end
260
317
 
261
- def to_savon_data(value)
262
- value.to_s
318
+ # A new instance of ObjectMapping with description for class klass.
319
+ # @param klass [Class, #to_native] A class which can create instances from Savon data and provide Savon data for export.
320
+ # @param description [String]
321
+ # @return [ObjectMapping]
322
+ def initialize(klass, description='')
323
+ super(klass, description)
263
324
  end
264
325
 
265
- def object_klass
266
- String
267
- end
326
+ # @!group Converting
268
327
 
269
- def type_string
270
- "String"
328
+ # Convert from Savon data to Ruby Object.
329
+ # @param data [Hash, String] Source Savon data
330
+ # @return [SavonHelper::MappingObject, #to_native]
331
+ def to_native(data, interface)
332
+ self.class.to_native(@klass, data, interface)
271
333
  end
272
334
 
335
+ # @!endgroup
336
+
273
337
  end
274
338
 
275
- class MissingMapping < TypeMapping
339
+ # ArrayMapping maps Savon data to Ruby Arrays
340
+ class ArrayMapping < TypeMapping
276
341
 
277
- def from_savon_data(data)
278
- data
342
+ # Convert the given Savon data to an Array consisting of elements described by element_mapping
343
+ # @param element_mapping [TypeMapping] TypeMapping for elements
344
+ # @param data [Hash,Array] Source Savon Data
345
+ # @return [Array<element_mapping>]
346
+ def self.to_native(element_mapping, data, interface)
347
+ return [] if data.blank?
348
+ result = []
349
+ if data.is_a?(Array)
350
+ data.each do |element|
351
+ result << element_mapping.to_native(element, interface)
352
+ end
353
+ elsif data.is_a?(Hash)
354
+ item = data[:item]
355
+ if item.nil?
356
+ result << element_mapping.to_native(data, interface)
357
+ else
358
+ result = to_native(element_mapping, item, interface)
359
+ end
360
+ else
361
+ raise "Unknown Array mapping"
362
+ end
363
+ result
279
364
  end
280
365
 
281
- def to_savon_data(value)
282
- value
366
+ # A new instance of TypeMapping with description
367
+ # @param element_mapping [TypeMapping] A TypeMapping for elements
368
+ # @param description [String]
369
+ # @return [ArrayMapping]
370
+ def initialize(element_mapping, description='')
371
+ super(description)
372
+ @element_mapping = element_mapping
373
+ end
374
+
375
+ # @!group Converting
376
+
377
+ # Convert from Savon data to Ruby value
378
+ # @param data [Hash, Hash] Source Savon data
379
+ # @return [Array<@element_mapping>]
380
+ def to_native(data, interface)
381
+ self.class.to_native(@element_mapping, data, interface)
283
382
  end
284
383
 
384
+ # @!endgroup
385
+
386
+ # Return the class represented by the mapping.
387
+ # @return [Class]
388
+ def object_klass
389
+ @element_mapping.object_klass
390
+ end
391
+
392
+ # Return the class description represented by the mapping.
393
+ # @return [String]
285
394
  def type_string
286
- "MISSING"
395
+ "Array<#{@element_mapping.type_string}>"
287
396
  end
288
397
 
289
398
  end
290
399
 
291
- class HintMapping < TypeMapping
400
+ # MissingMapping maps Savon data to itself (no conversion).
401
+ class MissingMapping < TypeMapping
292
402
 
293
- def initialize(klass, description='')
294
- super(description)
295
- @klass = klass
403
+ # @!group Converting
404
+
405
+ # Convert from Savon data to itself.
406
+ # @param data [Object] Source Savon data
407
+ # @return [Object]
408
+ def to_native(data, interface)
409
+ data
296
410
  end
297
411
 
298
- def object_klass
299
- @klass
412
+ # Convert from itself (no conversion) to Savon data.
413
+ # @param value [Object] Source Ruby data
414
+ # @return [Object]
415
+ def to_savon(value)
416
+ value
300
417
  end
301
418
 
419
+ # @!endgroup
420
+
421
+ # Return the class description represented by the mapping.
422
+ # @return [String]
302
423
  def type_string
303
- "HINT"
424
+ "UNDEFINED"
304
425
  end
305
426
 
306
427
  end
307
428
 
308
- def self.define_missing_type_mapping(klass, ivar_name, value, mappings)
429
+ # Define a MissingMapping for the given options
430
+ # @todo Check if mappings can be derived from klass
431
+ # @param klass [Class] The class to define the mapping for.
432
+ # @param ivar_name [Symbol] The name of the ivar/accessor to hold/access the value
433
+ # @param value [Object] The value to set the ivar to.
434
+ # @param mappings [Hash{Symbol=>TypeMapping}] The mappings hash to add the HintMapping to.
435
+ def self.define_missing_type_mapping(klass, ivar_name, value, mappings, interface)
309
436
  message = "No type mapping for #{klass}@#{ivar_name} = #{value}!"
310
- DeepSecurity::Manager.current.logger.warn(message)
437
+ interface.logger.warn(message)
311
438
  mappings[ivar_name] = MissingMapping.new(message)
312
439
  end
313
440