hoodoo 1.0.2

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.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hoodoo +5 -0
  3. data/lib/hoodoo.rb +27 -0
  4. data/lib/hoodoo/active.rb +32 -0
  5. data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
  6. data/lib/hoodoo/active/active_record/base.rb +81 -0
  7. data/lib/hoodoo/active/active_record/creator.rb +134 -0
  8. data/lib/hoodoo/active/active_record/dated.rb +343 -0
  9. data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
  10. data/lib/hoodoo/active/active_record/finder.rb +606 -0
  11. data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
  12. data/lib/hoodoo/active/active_record/secure.rb +431 -0
  13. data/lib/hoodoo/active/active_record/support.rb +106 -0
  14. data/lib/hoodoo/active/active_record/translated.rb +87 -0
  15. data/lib/hoodoo/active/active_record/uuid.rb +80 -0
  16. data/lib/hoodoo/active/active_record/writer.rb +321 -0
  17. data/lib/hoodoo/client.rb +23 -0
  18. data/lib/hoodoo/client/augmented_array.rb +29 -0
  19. data/lib/hoodoo/client/augmented_base.rb +168 -0
  20. data/lib/hoodoo/client/augmented_hash.rb +23 -0
  21. data/lib/hoodoo/client/client.rb +354 -0
  22. data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
  23. data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
  24. data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
  25. data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
  26. data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
  27. data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
  28. data/lib/hoodoo/client/headers.rb +269 -0
  29. data/lib/hoodoo/communicators.rb +23 -0
  30. data/lib/hoodoo/communicators/fast.rb +44 -0
  31. data/lib/hoodoo/communicators/pool.rb +601 -0
  32. data/lib/hoodoo/communicators/slow.rb +84 -0
  33. data/lib/hoodoo/data.rb +51 -0
  34. data/lib/hoodoo/data/resources/caller.rb +39 -0
  35. data/lib/hoodoo/data/resources/errors.rb +28 -0
  36. data/lib/hoodoo/data/resources/log.rb +31 -0
  37. data/lib/hoodoo/data/resources/session.rb +26 -0
  38. data/lib/hoodoo/data/types/error_primitive.rb +27 -0
  39. data/lib/hoodoo/data/types/permissions.rb +40 -0
  40. data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
  41. data/lib/hoodoo/data/types/permissions_full.rb +28 -0
  42. data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
  43. data/lib/hoodoo/discovery.rb +20 -0
  44. data/lib/hoodoo/errors.rb +19 -0
  45. data/lib/hoodoo/errors/error_descriptions.rb +229 -0
  46. data/lib/hoodoo/errors/errors.rb +322 -0
  47. data/lib/hoodoo/generator.rb +139 -0
  48. data/lib/hoodoo/logger.rb +23 -0
  49. data/lib/hoodoo/logger/fast_writer.rb +27 -0
  50. data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
  51. data/lib/hoodoo/logger/logger.rb +387 -0
  52. data/lib/hoodoo/logger/slow_writer.rb +49 -0
  53. data/lib/hoodoo/logger/writer_mixin.rb +52 -0
  54. data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
  55. data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
  56. data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
  57. data/lib/hoodoo/middleware.rb +33 -0
  58. data/lib/hoodoo/presenters.rb +45 -0
  59. data/lib/hoodoo/presenters/base.rb +281 -0
  60. data/lib/hoodoo/presenters/base_dsl.rb +519 -0
  61. data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
  62. data/lib/hoodoo/presenters/embedding.rb +232 -0
  63. data/lib/hoodoo/presenters/types/array.rb +118 -0
  64. data/lib/hoodoo/presenters/types/boolean.rb +26 -0
  65. data/lib/hoodoo/presenters/types/date.rb +26 -0
  66. data/lib/hoodoo/presenters/types/date_time.rb +26 -0
  67. data/lib/hoodoo/presenters/types/decimal.rb +47 -0
  68. data/lib/hoodoo/presenters/types/enum.rb +55 -0
  69. data/lib/hoodoo/presenters/types/field.rb +158 -0
  70. data/lib/hoodoo/presenters/types/float.rb +26 -0
  71. data/lib/hoodoo/presenters/types/hash.rb +361 -0
  72. data/lib/hoodoo/presenters/types/integer.rb +26 -0
  73. data/lib/hoodoo/presenters/types/object.rb +117 -0
  74. data/lib/hoodoo/presenters/types/string.rb +53 -0
  75. data/lib/hoodoo/presenters/types/tags.rb +24 -0
  76. data/lib/hoodoo/presenters/types/text.rb +26 -0
  77. data/lib/hoodoo/presenters/types/uuid.rb +54 -0
  78. data/lib/hoodoo/services.rb +34 -0
  79. data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
  80. data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
  81. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
  82. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
  83. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
  84. data/lib/hoodoo/services/discovery/discovery.rb +186 -0
  85. data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
  86. data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
  87. data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
  88. data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
  89. data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
  90. data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
  91. data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
  92. data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
  93. data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
  94. data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
  95. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
  96. data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
  97. data/lib/hoodoo/services/middleware/interaction.rb +127 -0
  98. data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
  99. data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
  100. data/lib/hoodoo/services/services/context.rb +153 -0
  101. data/lib/hoodoo/services/services/implementation.rb +132 -0
  102. data/lib/hoodoo/services/services/interface.rb +934 -0
  103. data/lib/hoodoo/services/services/permissions.rb +250 -0
  104. data/lib/hoodoo/services/services/request.rb +189 -0
  105. data/lib/hoodoo/services/services/response.rb +316 -0
  106. data/lib/hoodoo/services/services/service.rb +141 -0
  107. data/lib/hoodoo/services/services/session.rb +729 -0
  108. data/lib/hoodoo/utilities.rb +12 -0
  109. data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
  110. data/lib/hoodoo/utilities/utilities.rb +380 -0
  111. data/lib/hoodoo/utilities/uuid.rb +44 -0
  112. data/lib/hoodoo/version.rb +17 -0
  113. data/spec/active/active_record/base_spec.rb +57 -0
  114. data/spec/active/active_record/creator_spec.rb +88 -0
  115. data/spec/active/active_record/dated_spec.rb +248 -0
  116. data/spec/active/active_record/error_mapping_spec.rb +360 -0
  117. data/spec/active/active_record/finder_spec.rb +744 -0
  118. data/spec/active/active_record/search_helper_spec.rb +384 -0
  119. data/spec/active/active_record/secure_spec.rb +435 -0
  120. data/spec/active/active_record/support_spec.rb +225 -0
  121. data/spec/active/active_record/translated_spec.rb +19 -0
  122. data/spec/active/active_record/uuid_spec.rb +72 -0
  123. data/spec/active/active_record/writer_spec.rb +272 -0
  124. data/spec/alchemy/alchemy-amq.rb +33 -0
  125. data/spec/client/augmented_array_spec.rb +15 -0
  126. data/spec/client/augmented_base_spec.rb +50 -0
  127. data/spec/client/augmented_hash_spec.rb +15 -0
  128. data/spec/client/client_spec.rb +955 -0
  129. data/spec/client/endpoint/endpoint_spec.rb +70 -0
  130. data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
  131. data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
  132. data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
  133. data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
  134. data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
  135. data/spec/client/headers_spec.rb +172 -0
  136. data/spec/communicators/fast_spec.rb +9 -0
  137. data/spec/communicators/pool_spec.rb +339 -0
  138. data/spec/communicators/slow_spec.rb +15 -0
  139. data/spec/data/resources/caller_spec.rb +156 -0
  140. data/spec/data/resources/errors_spec.rb +22 -0
  141. data/spec/data/resources/log_spec.rb +20 -0
  142. data/spec/data/resources/session_spec.rb +15 -0
  143. data/spec/data/types/error_primitive_spec.rb +15 -0
  144. data/spec/data/types/permissions_defaults_spec.rb +25 -0
  145. data/spec/data/types/permissions_full_spec.rb +44 -0
  146. data/spec/data/types/permissions_resources_spec.rb +34 -0
  147. data/spec/data/types/permissions_spec.rb +37 -0
  148. data/spec/errors/error_descriptions_spec.rb +98 -0
  149. data/spec/errors/errors_spec.rb +346 -0
  150. data/spec/integration/service_actions_spec.rb +112 -0
  151. data/spec/logger/fast_writer_spec.rb +18 -0
  152. data/spec/logger/logger_spec.rb +259 -0
  153. data/spec/logger/slow_writer_spec.rb +144 -0
  154. data/spec/logger/writers/file_writer_spec.rb +37 -0
  155. data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
  156. data/spec/logger/writers/stream_writer_spec.rb +38 -0
  157. data/spec/presenters/base_dsl_spec.rb +111 -0
  158. data/spec/presenters/base_spec.rb +871 -0
  159. data/spec/presenters/common_resource_fields_spec.rb +30 -0
  160. data/spec/presenters/embedding_spec.rb +87 -0
  161. data/spec/presenters/types/array_spec.rb +249 -0
  162. data/spec/presenters/types/boolean_spec.rb +51 -0
  163. data/spec/presenters/types/date_spec.rb +57 -0
  164. data/spec/presenters/types/date_time_spec.rb +59 -0
  165. data/spec/presenters/types/decimal_spec.rb +58 -0
  166. data/spec/presenters/types/enum_spec.rb +71 -0
  167. data/spec/presenters/types/field_spec.rb +77 -0
  168. data/spec/presenters/types/float_spec.rb +50 -0
  169. data/spec/presenters/types/hash_spec.rb +1069 -0
  170. data/spec/presenters/types/integer_spec.rb +50 -0
  171. data/spec/presenters/types/object_spec.rb +177 -0
  172. data/spec/presenters/types/string_spec.rb +65 -0
  173. data/spec/presenters/types/tags_spec.rb +56 -0
  174. data/spec/presenters/types/text_spec.rb +50 -0
  175. data/spec/presenters/types/uuid_spec.rb +46 -0
  176. data/spec/presenters/walk_spec.rb +198 -0
  177. data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
  178. data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
  179. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
  180. data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
  181. data/spec/services/discovery/discovery_spec.rb +73 -0
  182. data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
  183. data/spec/services/discovery/results/for_http_spec.rb +37 -0
  184. data/spec/services/discovery/results/for_local_spec.rb +21 -0
  185. data/spec/services/discovery/results/for_remote_spec.rb +15 -0
  186. data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
  187. data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
  188. data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
  189. data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
  190. data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
  191. data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
  192. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
  193. data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
  194. data/spec/services/middleware/middleware_cors_spec.rb +93 -0
  195. data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
  196. data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
  197. data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
  198. data/spec/services/middleware/middleware_logging_spec.rb +356 -0
  199. data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
  200. data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
  201. data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
  202. data/spec/services/middleware/middleware_public_spec.rb +238 -0
  203. data/spec/services/middleware/middleware_spec.rb +1569 -0
  204. data/spec/services/middleware/string_inquirer_spec.rb +30 -0
  205. data/spec/services/services/application_spec.rb +74 -0
  206. data/spec/services/services/context_spec.rb +48 -0
  207. data/spec/services/services/implementation_spec.rb +45 -0
  208. data/spec/services/services/interface_spec.rb +262 -0
  209. data/spec/services/services/permissions_spec.rb +249 -0
  210. data/spec/services/services/request_spec.rb +95 -0
  211. data/spec/services/services/response_spec.rb +250 -0
  212. data/spec/services/services/session_spec.rb +432 -0
  213. data/spec/spec_helper.rb +298 -0
  214. data/spec/utilities/utilities_spec.rb +537 -0
  215. data/spec/utilities/uuid_spec.rb +20 -0
  216. metadata +615 -0
@@ -0,0 +1,427 @@
1
+ ########################################################################
2
+ # File:: endpoint.rb
3
+ # (C):: Loyalty New Zealand 2015
4
+ #
5
+ # Purpose:: Resource endpoint definition.
6
+ # ----------------------------------------------------------------------
7
+ # 05-Mar-2015 (ADH): Created.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+ class Client # Just used as a namespace here
12
+
13
+ # Base class for endpoint code.
14
+ #
15
+ # This base class defines the API to which subclasses must adhere,
16
+ # so that endpoint users don't need to care how the endpoint
17
+ # actually communicates with a target resource.
18
+ #
19
+ # ENDPOINTS ARE NOT INTENDED TO BE THREAD SAFE. Whenever you want to
20
+ # use one from a particular thread, instantiate an endpoint for use by
21
+ # just that thread. Don't share instances between threads via e.g.
22
+ # controlling class instance variables recording a reference to a
23
+ # single endpoint object.
24
+ #
25
+ class Endpoint
26
+
27
+ # Endpoint factory - instantiates and endpoint for the given resource
28
+ # and implemented API version, using the given discoverer.
29
+ #
30
+ # +resource+:: Resource name the endpoint targets, e.g. +:Purchase+.
31
+ # String or symbol.
32
+ #
33
+ # +version+:: Optional required interface (API) version for that
34
+ # endpoint. Integer. Default is 1.
35
+ #
36
+ # +options+:: Options Hash. Options are described below. Note that
37
+ # this Hash may be modified during processing.
38
+ #
39
+ # Items in the options hash are required, unless explicitly listed
40
+ # as optional. They are:
41
+ #
42
+ # +discoverer+:: A Hoodoo::Services::Discovery "By..." family
43
+ # member instance, e.g. a
44
+ # Hoodoo::Services::Discovery::ByDRb instance.
45
+ # This is used to look up a service instance. The
46
+ # returned discovery data type is used to determine
47
+ # the required endpoint type; for example, a
48
+ # Hoodoo::Services::Discovery::ForHTTP result yields
49
+ # a Hoodoo::Client::Endpoint::HTTP instance.
50
+ #
51
+ # +session_id+:: A session UUID, for the X-Session-ID HTTP header
52
+ # or an equivalent. Optional, but if omitted, only
53
+ # public resource actions will be accessible.
54
+ #
55
+ # +interaction+:: Optional Hoodoo::Services::Middleware::Interaction
56
+ # instance which describes a *source* interaction at
57
+ # hand. This is a middleware concept and most of the
58
+ # time, only the middleware would use this; the
59
+ # middleware is handling some API call which the
60
+ # source interaction data describes but the resource
61
+ # which is handling the call needs to make an
62
+ # inter-resource call, which is why an Endpoint is
63
+ # being created.
64
+ #
65
+ # +locale+:: Locale string for request/response, e.g. "en-gb".
66
+ # Optional. If omitted, defaults to "en-nz".
67
+ #
68
+ # OTHERS:: See Hoodoo::Client::Headers' +HEADER_TO_PROPERTY+.
69
+ # All such option keys _MUST_ be Symbols.
70
+ #
71
+ # Returns a Hoodoo::Services::Discovery "For..." family member
72
+ # instance (e.g. Hoodoo::Services::Discovery::ForHTTP) which can be
73
+ # used to talk to the resource in question. Getting an instance does
74
+ # not mean the resource endpoint is found - you will not know that
75
+ # until you try to talk to it and get a 404 expressed as a platform
76
+ # error in the response data. See Hoodoo::Client::AugmentedHash and
77
+ # Hoodoo::Client::AugmentedArray.
78
+ #
79
+ # Callers dealing with inter-resource call code may want to consult
80
+ # their discoverer to see if the resource is locally available
81
+ # before bothering to instantiate an endpoint.
82
+ #
83
+ # If the +deja_vu+ option is set, then a confirmed case of deja vu
84
+ # results in an empty Hash being returned, with no platform errors
85
+ # associated. This is the high-level transport neutral equivalent of
86
+ # (say) a 204 HTTP response with no body.
87
+ #
88
+ def self.endpoint_for( resource, version, options )
89
+ discoverer = options.delete( :discoverer )
90
+ discovery_result = discoverer.discover( resource.to_sym, version.to_i )
91
+
92
+ klass = if discovery_result.is_a?( Hoodoo::Services::Discovery::ForHTTP )
93
+ Hoodoo::Client::Endpoint::HTTP
94
+ elsif discovery_result.is_a?( Hoodoo::Services::Discovery::ForAMQP )
95
+ Hoodoo::Client::Endpoint::AMQP
96
+ elsif discovery_result.nil?
97
+ Hoodoo::Client::Endpoint::NotFound
98
+ else
99
+ nil
100
+ end
101
+
102
+ options[ :discovery_result ] = discovery_result
103
+
104
+ if klass.nil?
105
+ raise "Hoodoo::Client::Endpoint::endpoint_for: Unrecognised discoverer result class of '#{ discovery_result.class.name }'"
106
+ else
107
+ return klass.new( resource, version, options )
108
+ end
109
+ end
110
+
111
+ # Define read/write accessors for properties related to "X-Foo"
112
+ # headers. See the Middleware for details.
113
+ #
114
+ Hoodoo::Client::Headers.define_accessors_for_header_equivalents( self )
115
+
116
+ # The resource name passed to the constructor, as a String.
117
+ #
118
+ attr_reader :resource
119
+
120
+ # The version number passed to the constructor, as an Integer.
121
+ #
122
+ attr_reader :version
123
+
124
+ # The value of the +interaction+ option key passed to the
125
+ # constructor. See the constructor and #endpoint_for for more.
126
+ #
127
+ attr_reader :interaction
128
+
129
+ # The session UUID passed to the constructor or some value provided
130
+ # later; used for the calls to the target resource via the X-Session-ID
131
+ # HTTP header or an equivalent. If +nil+, only public actions in the
132
+ # target resource will be accessible.
133
+ #
134
+ attr_accessor :session_id
135
+
136
+ # The locale passed to the constructor or some value provided later; a
137
+ # String, e.g. "en-gb", or if +nil+, uses "en-nz" by default.
138
+ #
139
+ attr_accessor :locale
140
+
141
+ # Create an endpoint instance that will be used to make requests to
142
+ # a given resource.
143
+ #
144
+ # +resource+:: Resource name the endpoint targets, e.g. +:Purchase+.
145
+ # String or symbol.
146
+ #
147
+ # +version+:: Optional required interface (API) version for that
148
+ # endpoint. Integer. Default is 1.
149
+ #
150
+ # +options+:: Options Hash. Options are described below. Note that
151
+ # this Hash may be modified during processing.
152
+ #
153
+ # Items in the options hash are required, unless explicitly listed
154
+ # as optional. They are:
155
+ #
156
+ # +discovery_result+:: A Hoodoo::Services::Discovery "For..." family
157
+ # member instance, e.g. a
158
+ # Hoodoo::Services::Discovery::ForHTTP instance.
159
+ # Each subclass describes its required discovery
160
+ # result type, so see its documentation for
161
+ # details.
162
+ #
163
+ # +interaction+:: As in the options for #endpoint_for.
164
+ #
165
+ # +session_id+:: As in the options for #endpoint_for.
166
+ #
167
+ # +locale+:: As in the options for #endpoint_for.
168
+ #
169
+ # OTHERS:: See Hoodoo::Client::Headers' +HEADER_TO_PROPERTY+.
170
+ # All such option keys _MUST_ be Symbols.
171
+ #
172
+ # The out-of-the box initialiser sets up the data for the #resource,
173
+ # #version, #discovery_result, #interaction, #session_id, #locale,
174
+ # #dated_at and #dated_from accessors using this data, so subclass
175
+ # authors don't need to.
176
+ #
177
+ # The endpoint is then used with #list, #show, #create, #update or
178
+ # #delete methods to perform operations on the target resource. See
179
+ # each of those methods for details of their specific requirements;
180
+ # however all have common parameters some or all of which are used
181
+ # across the method 'family':
182
+ #
183
+ # +ident+:: Identifier. This is usually a UUID but some Resources
184
+ # support e.g. a "show" action based on either a UUID
185
+ # or some other unique value (such as a product code,
186
+ # a credit/debit card number or so-on - defined by the
187
+ # Resource in question in its documentation).
188
+ #
189
+ # +query_hash+:: A hash of _unencoded_ data that can be encoded to form
190
+ # a query string. Search and filter data is represented
191
+ # with nested hashes. Embed and reference data uses an
192
+ # array. Example:
193
+ #
194
+ # {
195
+ # offset: 75,
196
+ # limit: 50,
197
+ # sort: 'created_at', # ...or an Array of sort fields
198
+ # direction: 'asc', # ...or a matching Array of directions
199
+ # search: {
200
+ # member_id: "...some UUID..."
201
+ # },
202
+ # _embed: [
203
+ # 'vouchers',
204
+ # 'balances'
205
+ # ],
206
+ # # and/or ...filter: {}..., _reference: []...
207
+ # }
208
+ #
209
+ # This parameter is always optional.
210
+ #
211
+ # +body_hash+:: The Hash representation of the body data that might be
212
+ # sent in an HTTP request (i.e. JSON, as a Hash).
213
+ #
214
+ def initialize( resource, version = 1, options )
215
+ @resource = resource.to_sym
216
+ @version = version.to_i
217
+
218
+ @discovery_result = options[ :discovery_result ]
219
+ @interaction = options[ :interaction ]
220
+
221
+ self.session_id = options[ :session_id ]
222
+ self.locale = options[ :locale ]
223
+
224
+ Hoodoo::Client::Headers::HEADER_TO_PROPERTY.each do | rack_header, description |
225
+ property = description[ :property ]
226
+ property_writer = description[ :property_writer ]
227
+
228
+ self.send( property_writer, options[ property ] ) if options.has_key?( property )
229
+ end
230
+
231
+ configure_with( @resource, @version, options )
232
+ end
233
+
234
+ ########################################################################
235
+ # And then subclass authors implement...
236
+ ########################################################################
237
+
238
+ protected
239
+
240
+ # This protected method is implemented by subclasses and called from
241
+ # the initializer. Subclasses should store resource and version data
242
+ # however they want and validate any required options, raising errors
243
+ # if need be.
244
+ #
245
+ # +resource+:: Resource name the endpoint targets, e.g. +:Purchase+.
246
+ # Symbol.
247
+ #
248
+ # +version+:: Optional required interface (API) version for that
249
+ # endpoint. Integer.
250
+ #
251
+ # +options+:: Options Hash. Same as for #initialize.
252
+ #
253
+ def configure_with( resource, version, options )
254
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#configure_with"
255
+ end
256
+
257
+ # Utility method to aid subclass authors. Not usually overridden.
258
+ #
259
+ # Determine the response class needed for a given action - returns
260
+ # Hoodoo::Client::AugmentedArray or Hoodoo::Client::AugmentedHash
261
+ # (class references, not instances).
262
+ #
263
+ # +action+:: A Symbol from
264
+ # Hoodoo::Services::Middleware::ALLOWED_ACTIONS.
265
+ #
266
+ def response_class_for( action )
267
+ return action === :list ? Hoodoo::Client::AugmentedArray : Hoodoo::Client::AugmentedHash
268
+ end
269
+
270
+ # Utility method to aid subclass authors. Not usually overridden.
271
+ #
272
+ # Return an instance of Hoodoo::Client::AugmentedArray or
273
+ # Hoodoo::Client::AugmentedHash with an associated 404 error (as
274
+ # a fully formed platform error) describing 'Not Found' for the
275
+ # target resource, version and given action.
276
+ #
277
+ # +action+:: A Symbol from
278
+ # Hoodoo::Services::Middleware::ALLOWED_ACTIONS.
279
+ #
280
+ def generate_404_response_for( action )
281
+ data = response_class_for( action ).new
282
+ data.platform_errors.add_error(
283
+ 'platform.not_found',
284
+ 'reference' => { :entity_name => "v#{ @version } of #{ @resource } interface endpoint" }
285
+ )
286
+
287
+ return data
288
+ end
289
+
290
+ # Copy the current value of writable options in this Endpoint
291
+ # instance, to another Endpoint instance. This is useful when one
292
+ # is wrapping another, but to the external user of the wrapping
293
+ # endpoint, they should just be able to set options in that item
294
+ # and have it act as if they'd set them on the thing which it is
295
+ # (not that the caller would know) wrapping.
296
+ #
297
+ # This includes copying over a +session_id+ field value, though
298
+ # often it'll subsequently be rewritten by the wrapping endpoint as
299
+ # it's wrapping something to provide special session management.
300
+ #
301
+ # WARNING: Any +nil+ internal state values will _not_ be copied.
302
+ #
303
+ def copy_updated_options_to( target_endpoint )
304
+ target_endpoint.session_id = self.session_id unless self.session_id.nil?
305
+ target_endpoint.locale = self.locale unless self.locale.nil?
306
+
307
+ Hoodoo::Client::Headers::HEADER_TO_PROPERTY.each do | rack_header, description |
308
+ property = description[ :property ]
309
+ property_writer = description[ :property_writer ]
310
+
311
+ value = self.send( property )
312
+
313
+ target_endpoint.send( property_writer, value ) unless value.nil?
314
+ end
315
+ end
316
+
317
+ public
318
+
319
+ # Obtain a list of resource instance representations.
320
+ #
321
+ # +query_hash+:: See the constructor for more. This is the only way
322
+ # to search or filter the list, via the target
323
+ # Resource's documented supported search/filter
324
+ # parameters and the platform's common all-Resources
325
+ # behaviour.
326
+ #
327
+ # Returns a Hoodoo::Client::AugmentedArray representation of the
328
+ # requested list of resource instances.
329
+ #
330
+ # Call Hoodoo::Client::AugmentedArray#platform_errors (or for
331
+ # service authors implementing resource endpoints, possibly call
332
+ # Hoodoo::Client::AugmentedArray#adds_errors_to? instead) on the
333
+ # returned instance to detect and resolve error conditions _before_
334
+ # examining its Array-derived contents.
335
+ #
336
+ # The array will be empty in successful responses if no items
337
+ # satisfying the list conditions were found. The array contents
338
+ # are undefined in the case of errors.
339
+ #
340
+ def list( query_hash = nil )
341
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#list"
342
+ end
343
+
344
+ # Obtain a resource instance representation.
345
+ #
346
+ # +ident+:: See the constructor for details.
347
+ # +query_hash+:: See the constructor for details.
348
+ #
349
+ # Returns a Hoodoo::Client::AugmentedHash representation of the
350
+ # requested resource instance.
351
+ #
352
+ # Call Hoodoo::Client::AugmentedHash#platform_errors (or for
353
+ # service authors implementing resource endpoints, possibly call
354
+ # Hoodoo::Client::AugmentedHash#adds_errors_to? instead)
355
+ # on the returned instance to detect and resolve error conditions
356
+ # _before_ examining its Hash-derived fields.
357
+ #
358
+ # The hash contents are undefined when errors are returned.
359
+ #
360
+ def show( ident, query_hash = nil )
361
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#show"
362
+ end
363
+
364
+ # Create a resource instance.
365
+ #
366
+ # +body_hash+:: See the constructor for details.
367
+ # +query_hash+:: See the constructor for details.
368
+ #
369
+ # Returns a Hoodoo::Client::AugmentedHash representation of the
370
+ # new resource instance.
371
+ #
372
+ # Call Hoodoo::Client::AugmentedHash#platform_errors (or for
373
+ # service authors implementing resource endpoints, possibly call
374
+ # Hoodoo::Client::AugmentedHash#adds_errors_to? instead)
375
+ # on the returned instance to detect and resolve error conditions
376
+ # _before_ examining its Hash-derived fields.
377
+ #
378
+ # The hash contents are undefined when errors are returned.
379
+ #
380
+ def create( body_hash, query_hash = nil )
381
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#create"
382
+ end
383
+
384
+ # Update a resource instance.
385
+ #
386
+ # +ident+:: See the constructor for details.
387
+ # +body_hash+:: See the constructor for details.
388
+ # +query_hash+:: See the constructor for details.
389
+ #
390
+ # Returns a Hoodoo::Client::AugmentedHash representation of the
391
+ # updated resource instance.
392
+ #
393
+ # Call Hoodoo::Client::AugmentedHash#platform_errors (or for
394
+ # service authors implementing resource endpoints, possibly call
395
+ # Hoodoo::Client::AugmentedHash#adds_errors_to? instead)
396
+ # on the returned instance to detect and resolve error conditions
397
+ # _before_ examining its Hash-derived fields.
398
+ #
399
+ # The hash contents are undefined when errors are returned.
400
+ #
401
+ def update( ident, body_hash, query_hash = nil )
402
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#update"
403
+ end
404
+
405
+ # Delete a resource instance.
406
+ #
407
+ # +ident+:: See the constructor for details.
408
+ # +query_hash+:: See the constructor for details.
409
+ #
410
+ # Returns a Hoodoo::Client::AugmentedHash representation of the
411
+ # now-deleted resource instance,from the instant before deletion.
412
+ #
413
+ # Call Hoodoo::Client::AugmentedHash#platform_errors (or for
414
+ # service authors implementing resource endpoints, possibly call
415
+ # Hoodoo::Client::AugmentedHash#adds_errors_to? instead)
416
+ # on the returned instance to detect and resolve error conditions
417
+ # _before_ examining its Hash-derived fields.
418
+ #
419
+ # The hash contents are undefined when errors are returned.
420
+ #
421
+ def delete( ident, query_hash = nil )
422
+ raise "Subclasses must implement Hoodoo::Client::Endpoint\#delete"
423
+ end
424
+
425
+ end
426
+ end
427
+ end
@@ -0,0 +1,180 @@
1
+ ########################################################################
2
+ # File:: amqp.rb
3
+ # (C):: Loyalty New Zealand 2015
4
+ #
5
+ # Purpose:: Resource endpoint definition.
6
+ # ----------------------------------------------------------------------
7
+ # 05-Mar-2015 (ADH): Created.
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+ class Client # Just used as a namespace here
12
+ class Endpoint # Just used as a namespace here
13
+
14
+ # Talk to a resource that is contacted over AMQP using HTTP emulation
15
+ # via the Alchemy and AMQ Endpoint gems.
16
+ #
17
+ # Calls cannot be made until #alchemy= has been called
18
+ # to set an Alchemy caller instance. The Alchemy +http_request+ method
19
+ # is called on this instance to perform the over-queue HTTP simulation.
20
+ #
21
+ # Configured with a Hoodoo::Services::Discovery::ForAMQP discovery
22
+ # result instance.
23
+ #
24
+ class AMQP < Hoodoo::Client::Endpoint::HTTPBased
25
+
26
+ protected
27
+
28
+ # See Hoodoo::Client::Endpoint#configure_with.
29
+ #
30
+ # Requires a Hoodoo::Services::Discovery::ForAMQP instance in the
31
+ # +discovery_result+ field of the +options+ Hash.
32
+ #
33
+ def configure_with( resource, version, options )
34
+ unless @discovery_result.is_a?( Hoodoo::Services::Discovery::ForAMQP )
35
+ raise "Hoodoo::Client::Endpoint::AMQP must be configured with a Hoodoo::Services::Discovery::ForAMQP instance - got '#{ @discovery_result.class.name }'"
36
+ end
37
+
38
+ # Host and port isn't relevant for Alchemy but *is* needed
39
+ # to keep Rack happy.
40
+
41
+ endpoint_uri = URI.parse( 'http://localhost:80' )
42
+ endpoint_uri.path = @discovery_result.equivalent_path
43
+
44
+ @description = Hoodoo::Client::Endpoint::HTTPBased::DescriptionOfRequest.new
45
+ @description.discovery_result = @discovery_result
46
+ @description.endpoint_uri = endpoint_uri
47
+ end
48
+
49
+ public
50
+
51
+ # Set/get the Alchemy caller instance. Its +http_request+ method is
52
+ # called to perform the over-queue HTTP simulation.
53
+ #
54
+ # Instances of the AMQP endpoint can be created, but cannot be
55
+ # used for resource calls - #list, #show, #create, #update and
56
+ # #delete _cannot_ be called - until an Alchemy instance has been
57
+ # specified. An exception will be raised if you try.
58
+ #
59
+ attr_accessor :alchemy
60
+
61
+ # See Hoodoo::Client::Endpoint#list.
62
+ #
63
+ def list( query_hash = nil )
64
+ d = @description.dup # This does NOT dup the objects to which @description points
65
+ d.action = :list
66
+ d.query_hash = query_hash
67
+
68
+ return do_amqp( d )
69
+ end
70
+
71
+ # See Hoodoo::Client::Endpoint#show.
72
+ #
73
+ def show( ident, query_hash = nil )
74
+ d = @description.dup
75
+ d.action = :show
76
+ d.ident = ident
77
+ d.query_hash = query_hash
78
+
79
+ return do_amqp( d )
80
+ end
81
+
82
+ # See Hoodoo::Client::Endpoint#create.
83
+ #
84
+ def create( body_hash, query_hash = nil )
85
+ d = @description.dup
86
+ d.action = :create
87
+ d.body_hash = body_hash
88
+ d.query_hash = query_hash
89
+
90
+ return do_amqp( d )
91
+ end
92
+
93
+ # See Hoodoo::Client::Endpoint#update.
94
+ #
95
+ def update( ident, body_hash, query_hash = nil )
96
+ d = @description.dup
97
+ d.action = :update
98
+ d.ident = ident
99
+ d.body_hash = body_hash
100
+ d.query_hash = query_hash
101
+
102
+ return do_amqp( d )
103
+ end
104
+
105
+ # See Hoodoo::Client::Endpoint#delete.
106
+ #
107
+ def delete( ident, query_hash = nil )
108
+ d = @description.dup
109
+ d.action = :delete
110
+ d.ident = ident
111
+ d.query_hash = query_hash
112
+
113
+ return do_amqp( d )
114
+ end
115
+
116
+ private
117
+
118
+ # Call Alchemy to make an HTTP simulated request over AMQP to a
119
+ # target resource and return the result as a
120
+ # Hoodoo::Client::AugmentedArray (for 'list' calls) or
121
+ # Hoodoo::Client::AugumentedHash (for all other calls) instance.
122
+ #
123
+ # +description_of_request+:: A Hoodoo::Client::Endpoint::HTTPBased::DescriptionOfRequest
124
+ # instance with all the request details
125
+ # set inside. The +discovery_data+ field
126
+ # must refer to a
127
+ # Hoodoo::Services::Discovery::ForAMQP
128
+ # instance (not re-checked internally).
129
+ #
130
+ def do_amqp( description_of_request )
131
+
132
+ if self.alchemy().nil?
133
+ raise 'Hoodoo::Client::Endpoint::AMQP cannot be used unless an Alchemy instance has been provided'
134
+ end
135
+
136
+ action = description_of_request.action
137
+ data = get_data_for_request( description_of_request )
138
+
139
+ # Host and port are just there to keep Rack happy at the
140
+ # receiving end of the over-AMQP synthesised HTTP request.
141
+
142
+ alchemy_options = {
143
+ :host => description_of_request.endpoint_uri.host,
144
+ :port => description_of_request.endpoint_uri.port,
145
+ :query => data.query_hash,
146
+ :body => data.body_string,
147
+ :headers => data.header_hash
148
+ }
149
+
150
+ unless self.session_id().nil? # Session comes from Endpoint superclass
151
+ alchemy_options[ :session_id ] = self.session_id()
152
+ end
153
+
154
+ http_method = {
155
+ :create => 'POST',
156
+ :update => 'PATCH',
157
+ :delete => 'DELETE'
158
+ }[ action ] || 'GET'
159
+
160
+ description_of_response = DescriptionOfResponse.new
161
+ description_of_response.action = action
162
+
163
+ amqp_response = self.alchemy().http_request(
164
+ description_of_request.discovery_result.queue_name,
165
+ http_method,
166
+ data.full_uri.path,
167
+ alchemy_options
168
+ )
169
+
170
+ description_of_response.http_status_code = amqp_response.status_code.to_i
171
+ description_of_response.http_headers = amqp_response.headers || {}
172
+ description_of_response.raw_body_data = amqp_response.body
173
+
174
+ return get_data_for_response( description_of_response )
175
+ end
176
+
177
+ end
178
+ end
179
+ end
180
+ end