rubyamf-ouvrages 2.0.0

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,272 @@
1
+ module RubyAMF
2
+ # RubyAMF configuration container. It can be accessed by calling
3
+ # <tt>RubyAMF.configuration</tt>, or modified in a block like so:
4
+ #
5
+ # RubyAMF.configure do |config|
6
+ # config.gateway_path = "/amf"
7
+ # end
8
+ #
9
+ # === Gateway configuration
10
+ #
11
+ # Gateway configuration includes the gateway path and details about parameter
12
+ # mapping.
13
+ #
14
+ # +gateway_path+::
15
+ # Default: <tt>"/rubyamf/gateway"</tt>. The URL that responds to AMF requests.
16
+ # The URL should start with a "/" and not end with a "/".
17
+ #
18
+ # +populate_params_hash+::
19
+ # Default: <tt>true</tt>. For Rails users, all amf parameters can be accessed
20
+ # in the controller by calling <tt>rubyamf_params</tt>. If enabled, the amf
21
+ # parameters are merged into the <tt>params</tt> hash as well.
22
+ #
23
+ # +show_html_gateway+::
24
+ # Default: <tt>true</tt>. If enabled, non-AMF requests to the gateway url
25
+ # will result in a simple HTML page being returned.
26
+ #
27
+ # +param_mappings+::
28
+ # A hash that stores parameter mappings. Should only be modified through
29
+ # calls to <tt>map_params</tt>
30
+ #
31
+ # === Serialization options
32
+ #
33
+ # RubyAMF provides a wide variety of customization options for serialization
34
+ # to simplify integration.
35
+ #
36
+ # +translate_case+::
37
+ # Default: <tt>false</tt>. If enabled, properties will be converted to
38
+ # underscore style on deserialization from actionscript and will be converted
39
+ # to camelcase on serialization. This allows you to use language appropriate
40
+ # case style and have RubyAMF automatically care of translation.
41
+ #
42
+ # +auto_class_mapping+::
43
+ # Default: <tt>false</tt>. If a class mapping for a given ruby or actionscript
44
+ # class has not been defined, automatically maps it during serialization or
45
+ # deserialization. Nested ruby or actionscript classes will be automatically
46
+ # mapped to the class name without the namespace. Example:
47
+ # <tt>com.rubyamf.User => User</tt> or <tt>RubyAMF::User => User</tt>.
48
+ #
49
+ # +use_array_collection+::
50
+ # Default: <tt>false</tt>. If enabled, all arrays will be serialized as
51
+ # <tt>ArrayCollection</tt> objects. You can override this on a per-array
52
+ # basis by setting <tt>is_array_collection</tt> on the array to <tt>true</tt>
53
+ # or <tt>false</tt>. (Implementation in RocketAMF)
54
+ #
55
+ # +hash_key_access+::
56
+ # Default: <tt>:string</tt>. If set to <tt>:symbol</tt>, all deserialized
57
+ # hashes have the keys as symbols. RocketAMF defaults to strings, so setting
58
+ # to <tt>:symbol</tt> will reduce performance and possibly open you up to
59
+ # memory usage attacks.
60
+ #
61
+ # +preload_models+::
62
+ # If you are using in-model mapping and don't have <tt>auto_class_mapping</tt>
63
+ # enabled, you may need to force classes to be loaded before mapping takes
64
+ # effect. Simply include all necessary classes as strings to have RubyAMF
65
+ # force them to be loaded on initialization.
66
+ # Example: <tt>config.preload_models = ["User", "Course"]</tt>
67
+ #
68
+ # +check_for_associations+::
69
+ # Default: <tt>true</tt>. If enabled, associations that have been pre-loaded,
70
+ # either through :include or simply by being accessed, will be automatically
71
+ # included during serialization without any additional configuration.
72
+ #
73
+ # +ignore_fields+::
74
+ # Default: <tt>['created_at', 'created_on', 'updated_at', 'updated_on']</tt>.
75
+ # A list of all properties that should not be deserialized by default. The
76
+ # class-level <tt>:ignore_fields</tt> config overrides this.
77
+ class Configuration
78
+ # Gateway options
79
+ attr_accessor :gateway_path, :populate_params_hash, :show_html_gateway
80
+ attr_reader :param_mappings
81
+
82
+ # Serialization options
83
+ attr_accessor :translate_case, :auto_class_mapping, :use_array_collection,
84
+ :hash_key_access, :preload_models, :check_for_associations,
85
+ :ignore_fields
86
+
87
+ def initialize
88
+ @gateway_path = "/rubyamf/gateway"
89
+ @param_mappings = {}
90
+ @populate_params_hash = true
91
+ @show_html_gateway = true
92
+
93
+ @translate_case = false
94
+ @auto_class_mapping = false
95
+ @use_array_collection = false
96
+ @hash_key_access = :string
97
+ @preload_models = []
98
+ @check_for_associations = true
99
+ @ignore_fields = ['created_at', 'created_on', 'updated_at', 'updated_on']
100
+ end
101
+
102
+ # Maps the given array of named parameters to the arguments for calls to the
103
+ # given controller and action. For Rails users, the prefered method of
104
+ # parameter mapping is through routing (see RubyAMF::Rails::Routing).
105
+ #
106
+ # Example:
107
+ #
108
+ # config.map_params "UserController", "login", [:session_token, :username, :password]
109
+ # # params hash => {
110
+ # # 0 => "asdf", 1 => "user", 2 => "pass",
111
+ # # :session_token => "asdf", :username => "user", :password => "pass"
112
+ # # }
113
+ def map_params controller, action, params
114
+ @param_mappings[controller.to_s+"#"+action.to_s] = params
115
+ end
116
+
117
+ # Returns the class mapper class being used
118
+ def class_mapper
119
+ if @class_mapper.nil?
120
+ @class_mapper = RubyAMF::ClassMapping
121
+ end
122
+ @class_mapper
123
+ end
124
+
125
+ # Set to the class of any conforming class mapper to use it instead of
126
+ # <tt>RubyAMF::ClassMapping</tt>. If you don't need any of the advanced
127
+ # features offered by the RubyAMF class mapper, you can gain some substantial
128
+ # performance improvements by settings this to
129
+ # <tt>RocketAMF::Ext::FastClassMapping</tt> or <tt>RocketAMF::ClassMapping</tt>
130
+ # for the slower pure-ruby version.
131
+ def class_mapper= klass
132
+ @class_mapper = klass
133
+ end
134
+
135
+ # Loads the legacy config file at the given path or tries to locate it by
136
+ # looking for a <tt>rubyamf_config.rb</tt> file in several possible locations.
137
+ # Automatically run by RubyAMF if you are using Rails 2, it should be run
138
+ # before any additional configuration if you are not using Rails 2, as it
139
+ # overrides all previous configuration.
140
+ def load_legacy path=nil
141
+ # Locate legacy config
142
+ unless path
143
+ possible = []
144
+ possible << File.join(RAILS_ROOT, 'config', 'rubyamf_config.rb') if defined?(RAILS_ROOT)
145
+ possible << File.join('config', 'rubyamf_config.rb')
146
+ possible << 'rubyamf_config.rb'
147
+ unless path = possible.find {|p| File.exists?(p)}
148
+ raise "rubyamf_config.rb not found"
149
+ end
150
+ end
151
+
152
+ # Load legacy config
153
+ $" << "app/configuration" # prevent legacy code require from doing anything
154
+ LegacySandbox.module_eval(File.read(path))
155
+ $".pop
156
+ cm = LegacySandbox::RubyAMF::ClassMappings
157
+ pm = LegacySandbox::RubyAMF::ParameterMappings
158
+
159
+ # Raise exceptions for disabled settings
160
+ if cm.force_active_record_ids != nil; raise "CONFIG PARSE ERROR: force_active_record_ids is no longer supported. Use <tt>:except</tt> if you want to prevent the id from being serialized."; end
161
+ if cm.hash_key_access == :indifferent; raise "CONFIG PARSE ERROR: indifferent hash_key_access is not supported for performance reasons. Use either :string or :symbol, the default."; end
162
+ if cm.default_mapping_scope != nil; raise "CONFIG PARSE ERROR: default_mapping_scope is not supported globally. Please log a feature request if you need it, or use switch to the new config syntax which supports per-model defaults."; end
163
+ if cm.use_ruby_date_time == true; raise "CONFIG PARSE ERROR: use_ruby_date_time is not supported by RocketAMF. Please log a feature request if you need it."; end
164
+ if pm.scaffolding == true; raise "CONFIG PARSE ERROR: scaffolding is not supported. Please log a feature request if you need it."; end
165
+
166
+ # Populate ClassMappings configs from legacy config
167
+ @ignore_fields = cm.ignore_fields unless cm.ignore_fields.nil?
168
+ @translate_case = cm.translate_case if cm.translate_case == true
169
+ @hash_key_access = cm.hash_key_access unless cm.hash_key_access.nil?
170
+ @use_array_collection = cm.use_array_collection if cm.use_array_collection == true
171
+ @check_for_associations = cm.check_for_associations if cm.check_for_associations == false
172
+ mapset = class_mapper.mappings
173
+ (cm.mappings || []).each do |legacy_mapping|
174
+ mapping = {}
175
+ if legacy_mapping[:type] == 'active_resource'
176
+ raise "CONFIG PARSE ERROR: active_resource mapping type is not supported. Please log a feature request or stop using it."
177
+ end
178
+
179
+ # Extract unscoped settings
180
+ mapping[:as] = legacy_mapping[:actionscript]
181
+ mapping[:ruby] = legacy_mapping[:ruby]
182
+ mapping[:methods] = legacy_mapping[:methods] unless legacy_mapping[:methods].nil?
183
+ mapping[:ignore_fields] = legacy_mapping[:ignore_fields] unless legacy_mapping[:ignore_fields].nil?
184
+
185
+ # Process possibly scoped settings
186
+ attrs = legacy_mapping[:attributes]
187
+ assoc = legacy_mapping[:associations]
188
+ if attrs.is_a?(Hash) || assoc.is_a?(Hash)
189
+ # Extract scopes
190
+ scopes = []
191
+ scopes += attrs.keys if attrs.is_a?(Hash)
192
+ scopes += assoc.keys if assoc.is_a?(Hash)
193
+
194
+ # Build settings for scopes
195
+ scopes.each do |scope|
196
+ scoped = mapping.dup
197
+ scoped[:scope] = scope.to_sym
198
+ scoped[:only] = attrs.is_a?(Hash) ? attrs[scope] : attrs
199
+ scoped.delete(:only) if scoped[:only].nil?
200
+ scoped[:include] = assoc.is_a?(Hash) ? assoc[scope] : assoc
201
+ scoped.delete(:include) if scoped[:include].nil?
202
+ mapset.map scoped
203
+ end
204
+ else
205
+ # No scoping
206
+ mapping[:only] = attrs unless attrs.nil?
207
+ mapping[:include] = assoc unless assoc.nil?
208
+ mapset.map mapping
209
+ end
210
+ end
211
+
212
+ # Populate ParameterMapping configs from legacy config
213
+ @populate_params_hash = pm.always_add_to_params if pm.always_add_to_params == false
214
+ (pm.mappings || []).each do |m|
215
+ params = []
216
+ m[:params].each do |k, v|
217
+ unless v =~ /\[(\d+)\]/
218
+ raise "CONFIG PARSE ERROR: parameter mappings are no longer evalled - '#{v}' must match [DIGITS]. Please log a feature request if you need this."
219
+ end
220
+ params[$1.to_i] = k
221
+ end
222
+ self.map_params m[:controller], m[:action], params
223
+ end
224
+
225
+ # Reset sandbox
226
+ cm.reset
227
+ pm.reset
228
+
229
+ self
230
+ end
231
+ end
232
+
233
+ module LegacySandbox #:nodoc:
234
+ module RubyAMF #:nodoc:
235
+ module ClassMappings #:nodoc:
236
+ class << self
237
+ attr_accessor :ignore_fields, :translate_case, :force_active_record_ids, :hash_key_access,
238
+ :assume_types, :default_mapping_scope, :use_ruby_date_time, :use_array_collection,
239
+ :check_for_associations, :mappings
240
+
241
+ def register mapping
242
+ @mappings ||= []
243
+ @mappings << mapping
244
+ end
245
+
246
+ def reset
247
+ methods.each do |m|
248
+ send(m, nil) if m =~ /[\w_]+=/
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ module ParameterMappings #:nodoc:
255
+ class << self
256
+ attr_accessor :always_add_to_params, :scaffolding, :mappings
257
+
258
+ def register mapping
259
+ @mappings ||= []
260
+ @mappings << mapping
261
+ end
262
+
263
+ def reset
264
+ methods.each do |m|
265
+ send(m, nil) if m =~ /[\w_]+=/
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,102 @@
1
+ require 'base64'
2
+
3
+ module RubyAMF
4
+ # Adds several important features to RocketAMF::Envelope. None of these features
5
+ # are dependent on Rails, and as such can be used by any Rack compliant framework.
6
+ # Features are credentials support, easy parameter mapping based on configured
7
+ # parameter mappings, mapping scope support for serialization, and error handling
8
+ # for method dispatch using <tt>each_method_call</tt>.
9
+ class Envelope < RocketAMF::Envelope
10
+ attr_accessor :mapping_scope
11
+
12
+ # Finds and returns credentials set on the request as a hash with keys
13
+ # <tt>username</tt> and <tt>password</tt>, with the type dependent on the
14
+ # <tt>hash_key_access</tt> setting. <tt>setHeader('Credentials')</tt>
15
+ # credentials are used first, followed by new-style <tt>DSRemoteCredentials</tt>.
16
+ # If no credentials are found, a hash is returned with a username and password
17
+ # of <tt>nil</tt>.
18
+ def credentials
19
+ ds_cred_key = RubyAMF.configuration.translate_case ? "ds_remote_credentials" : "DSRemoteCredentials"
20
+ if RubyAMF.configuration.hash_key_access == :symbol
21
+ userid_key = :userid
22
+ username_key = :username
23
+ password_key = :password
24
+ ds_cred_key = ds_cred_key.to_sym
25
+ else
26
+ userid_key = "userid"
27
+ username_key = "username"
28
+ password_key = "password"
29
+ end
30
+
31
+ # Old style setHeader('Credentials', CREDENTIALS_HASH)
32
+ if @headers['Credentials']
33
+ h = @headers['Credentials']
34
+ return {username_key => h.data[userid_key], password_key => h.data[password_key]}
35
+ end
36
+
37
+ # New style DSRemoteCredentials
38
+ messages.each do |m|
39
+ if m.data.is_a?(RocketAMF::Values::RemotingMessage)
40
+ if m.data.headers && m.data.headers[ds_cred_key]
41
+ username,password = Base64.decode64(m.data.headers[ds_cred_key]).split(':')
42
+ return {username_key => username, password_key => password}
43
+ end
44
+ end
45
+ end
46
+
47
+ # Failure case sends empty credentials, because rubyamf_plugin does it
48
+ {username_key => nil, password_key => nil}
49
+ end
50
+
51
+ # Given a controller, action, and the flash arguments array, returns a hash
52
+ # containing the arguments indexed by number as well as named key if a named
53
+ # mapping has been configured. Returned hash respects <tt>hash_key_access</tt>
54
+ # setting for named keys.
55
+ #
56
+ # Example:
57
+ #
58
+ # RubyAMF.configuration.map_params "c", "a", ["param1", "param2"]
59
+ # params = envelope.params_hash "c", "a", ["asdf", "fdsa"]
60
+ # params.should == {:param1 => "asdf", :param2 => "fdsa", 0 => "asdf", 1 => "fdsa"}
61
+ def params_hash controller, action, arguments
62
+ conf = RubyAMF.configuration
63
+ mapped = {}
64
+ mapping = conf.param_mappings[controller+"#"+action]
65
+ arguments.each_with_index do |arg, i|
66
+ mapped[i] = arg
67
+ if mapping && mapping[i]
68
+ mapping_key = conf.hash_key_access == :symbol ? mapping[i].to_sym : mapping[i].to_s
69
+ mapped[mapping_key] = arg
70
+ end
71
+ end
72
+ mapped
73
+ end
74
+
75
+ # Extends default RocketAMF implementation to log caught exceptions and
76
+ # translate them into a RocketAMF::Values::ErrorMessage for return to flash
77
+ # after removing the backtrace (for safety).
78
+ def dispatch_call p
79
+ begin
80
+ ret = p[:block].call(p[:method], p[:args])
81
+ raise ret if ret.is_a?(Exception) # If they return FaultObject like you could in rubyamf_plugin
82
+ ret
83
+ rescue Exception => e
84
+ # Log exception
85
+ RubyAMF.logger.log_error(e)
86
+
87
+ # Clear backtrace so that RocketAMF doesn't send back the full backtrace
88
+ e.set_backtrace([])
89
+
90
+ # Create ErrorMessage object using the source message as the base
91
+ RocketAMF::Values::ErrorMessage.new(p[:source], e)
92
+ end
93
+ end
94
+
95
+ def serialize class_mapper=nil #:nodoc:
96
+ # Create a ClassMapper and set the mapping scope to pass to super implementation.
97
+ cm = class_mapper || RubyAMF::ClassMapper.new
98
+ cm.mapping_scope = mapping_scope if cm.respond_to?(:mapping_scope=)
99
+ super cm
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,31 @@
1
+ module RubyAMF
2
+ class Fault < ::Exception #:nodoc:
3
+ end
4
+ end
5
+
6
+ # Convenience object carried over from rubyamf_plugin, it can be returned for
7
+ # AMF instead of raising an exception.
8
+ #
9
+ # Example:
10
+ #
11
+ # render :amf => FaultObject.new("No users to get")
12
+ class FaultObject
13
+ def self.new *args, &block
14
+ if args.length == 2
15
+ raise "payload for FaultObject is no longer available - if you need it you will need to create a custom class to contain your payload"
16
+ end
17
+ message = args.length > 0 ? args[0] : ''
18
+
19
+ begin
20
+ raise RubyAMF::Fault.new(message)
21
+ rescue Exception => e
22
+ # Fix backtrace
23
+ b = e.backtrace
24
+ b.shift
25
+ e.set_backtrace(b)
26
+
27
+ # Return new fault object
28
+ return e
29
+ end
30
+ end
31
+ end
Binary file
@@ -0,0 +1,18 @@
1
+ module RubyAMF
2
+ # IntermediateObject packages an object with its requested serialization options.
3
+ # This allows the pre-configured serialization configuration to be overridden
4
+ # as needed. They are automatically created by <tt>to_amf</tt> and should not
5
+ # be generated manually.
6
+ class IntermediateObject
7
+ attr_accessor :object, :options
8
+
9
+ def initialize object, options
10
+ @object = object
11
+ @options = options
12
+ end
13
+
14
+ def rubyamf_hash
15
+ @object.rubyamf_hash @options
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+
3
+ module RubyAMF
4
+ class Logger #:nodoc:
5
+ # Log exceptions in rails-style, with cleaned backtrace if available
6
+ def log_error e
7
+ msg = "#{e.class} (#{e.message}):\n "
8
+ msg += clean_backtrace(e).join("\n ")
9
+ logger.fatal(msg)
10
+ end
11
+
12
+ # Send every other method call to internally wrapped logger
13
+ def method_missing name, *args
14
+ logger.send(name, args)
15
+ end
16
+
17
+ private
18
+ # Use rails logger if available or create standard ruby logger to STDERR
19
+ def logger
20
+ unless @logger
21
+ if defined?(Rails) && ::Rails.logger
22
+ @logger = ::Rails.logger
23
+ else
24
+ @logger = ::Logger.new(STDERR)
25
+ end
26
+ end
27
+ @logger
28
+ end
29
+
30
+ # Use Rails backtrace cleaner if it exists to clean
31
+ def clean_backtrace e
32
+ if defined?(Rails) && ::Rails.respond_to?(:backtrace_cleaner)
33
+ ::Rails.backtrace_cleaner.clean(e.backtrace)
34
+ else
35
+ e.backtrace
36
+ end
37
+ end
38
+ end
39
+ end