deepsecurity 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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