Class: Arrow::Session::Store

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
PluginFactory
Defined in:
lib/arrow/session/store.rb

Overview

The Arrow::Session::Store class, a derivative of Arrow::Object. Instances of concrete deriviatives of this class provide serialization and semi-permanent storage of session data for Arrow::Session objects.

Derivative Interface ===

In order to create your own session store classes, you need to provide four methods: #insert, #update, #retrieve, #remove. All but one of the methods provides serialization and marking records as dirty in the base class, so unless you want to manage these tasks yourself, you should super() to the parent’s implementation with a block. Examples are provided for each method.

#insert

Insert a new session into the backing store. Example:

def insert
  super {|data| @io.print(data) }
end
#update

Update an existing session’s data in the backing store. Example:

def update
  super {|data| @io.rewind; @io.truncate(0); @io.print(data) }
end
#retrieve

Retrieve the serialized session data from the backing store. Example:

def retrieve
  super { @io.rewind; @io.read }
end
#delete

Delete the session from the backing store. Example:

def delete
  super {|data| @io.close; File.delete(@session_file) }
end

Optional Derivative Interface ===

Serialization ====

If you want to use something other than Marshal for object serialization, you can override the protected methods #serialized_data and #serialized_data= to provide your own serialization.

#serialized_data

Serialize the data in the instance variable @data and return it.

#serialized_data=( serialized )

Deserialize the given serialized data and assign it to @data.

Example (serializing to YAML instead of binary):

require 'yaml'

def serialized_data
  @data.to_yaml
end

def serialized_data=( data )
  @data = YAML.load( data )
end

Lock Recommendation ====

If arrow is configured to use the ‘recommended’ session lock, your session store can recommend one it knows will work (e.g., if your session store is a database, you can recommend a lock that uses database locking). The simple way to do that is to define a RecommendedLocker constant in your class which contains the URI of the locker you wish to use. If you need more control than the URI can provide, you can also override the #create_recommended_lock method, which should return an instance of the locker that should be used.

The method will be given the instantiated Arrow::Session::Id object that identifies the session so that you can derive a filename, primary key, etc.

Example:

def create_recommended_lock( idobj )
  return DBITransactionLock.new( idobj.to_s )
end

Authors

Please see the file LICENSE in the top-level directory for licensing details.

Direct Known Subclasses

FileStore

Constant Summary collapse

RecommendedLocker =

The URI of the lock class recommended for use with this Store.

URI.parse( 'file:.' )
DelegatedMethods =

The methods which are delegate directly to the data hash.

[
	:[], :default, :default=, :each, :each_key, :each_pair, :each_value,
	:empty?, :fetch, :has_key?, :has_value?, :include?, :index, :invert,
	:keys, :length, :member?, :merge, :rehash, :reject, :select, :size,
	:sort, :to_a, :value?, :values
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Object

deprecate_class_method, deprecate_method, inherited

Constructor Details

#initialize(uri, idobj) ⇒ Store

Create a new Arrow::Session::Store object.



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/arrow/session/store.rb', line 135

def initialize( uri, idobj )
	@data		= {}
	@id			= idobj
	@new		= true
	@modified	= false

	unless idobj.new?
		self.retrieve
	end

	super()
end

Instance Attribute Details

#dataObject (readonly)

The raw session data hash



158
159
160
# File 'lib/arrow/session/store.rb', line 158

def data
  @data
end

Class Method Details

.create(uri, idobj) ⇒ Object

Overridden factory method: handle a URI object or a name



123
124
125
126
# File 'lib/arrow/session/store.rb', line 123

def self::create( uri, idobj )
	uri = Arrow::Session.parse_uri( uri ) if uri.is_a?( String )
	super( uri.scheme.dup, uri, idobj )
end

.derivativeDirsObject

Returns the Array of directories to search for derivatives; part of the PluginFactory interface.



117
118
119
# File 'lib/arrow/session/store.rb', line 117

def self::derivativeDirs
	[ 'arrow/session', 'arrow/session/store' ]
end

Instance Method Details

#[]=(key, value) ⇒ Object Also known as: store

Set the value for the specified key.



162
163
164
165
# File 'lib/arrow/session/store.rb', line 162

def []=( key, value )
	@data[ key ] = value
	@modified = true
end

#clearObject

Clear all key/value pairs from the store for this session.



183
184
185
186
# File 'lib/arrow/session/store.rb', line 183

def clear
	@data.clear
	@modified = true
end

Returns an instance of the recommended lock object for the receiving store. If no recommended locking strategy is known, this method raises a SessionError.



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/arrow/session/store.rb', line 294

def create_recommended_lock( idobj )
	self.log.debug "Searching for recommended lock for %s" %
		self.class.name

	# Traverse the class hierarchy to find a class which defines a
	# RecommendedLocker constant
	adviceClass = self.class.ancestors.find {|klass|
		klass.const_defined?( :RecommendedLocker )
	} or raise SessionError, "No recommended locker for %p" %
		self.class.ancestors

	uri = adviceClass.const_get( :RecommendedLocker ) or
		raise SessionError, "Could not fetch RecommendedLocker constant"

	self.log.debug "Creating recommended lock %s" % uri
	uri = Arrow::Session.parse_uri( uri ) if
		uri.is_a?( String )

	lock = Arrow::Session::Lock.create( uri, idobj )
	self.log.debug "Created recommended lock object: %p" % lock

	return lock
end

#delete(key, &block) ⇒ Object

Deletes and returns a key-value pair from the receiver whose key is equal to key. If the key is not found, returns the default value. If the optional code-block is given and the key is not found, the block is called with the key, and the return value is used as the result of the method.



174
175
176
177
178
179
# File 'lib/arrow/session/store.rb', line 174

def delete( key, &block )
	rval = @data.delete( key, &block )
	return rval
ensure
	@modified = true if rval != @data.default
end

#insert {|self.serialized_data| ... } ⇒ Object

Insert the current data hash into whatever permanent storage the Store object is acting as an interface to. Concrete implementations should provide an overriding implementation of this method that calls #super with a block which will be called with the serialized data that should be stored.

Yields:

  • (self.serialized_data)


253
254
255
256
257
# File 'lib/arrow/session/store.rb', line 253

def insert
	self.log.debug "Inserting session data for key %s" % @id
	yield( self.serialized_data )
	@new = @modified = false
end

#merge!(other, &block) ⇒ Object Also known as: update

Adds the contents of the other hash to the session data, overwriting entries in the session data with values from the other hash where there are duplicates. If a block is given, it is called for each duplicate key, and the return value is the value set in the hash.



194
195
196
197
198
# File 'lib/arrow/session/store.rb', line 194

def merge!( other, &block ) # :yields: key, sessionValue, otherValue
	@data.merge!( other, &block )
ensure
	@modified = true
end

#modified?Boolean

Returns true if the receiver’s data is out of sync with the data in the backing store.

Returns:

  • (Boolean)


224
225
226
# File 'lib/arrow/session/store.rb', line 224

def modified?
	@modified
end

#new?Boolean

Returns true if the data in the receiver has not yet been saved to the backing store, or if the entry in the backing store has been deleted since it was last saved.

Returns:

  • (Boolean)


232
233
234
# File 'lib/arrow/session/store.rb', line 232

def new?
	@new
end

#reject!(&block) ⇒ Object Also known as: delete_if

Deletes every key-value pair from the session data for which the block evaluates to true.



213
214
215
216
217
218
# File 'lib/arrow/session/store.rb', line 213

def reject!( &block ) # :yields: key, value
	rval = @data.reject!( &block )
	return rval
ensure
	@modified = true if rval
end

#removeObject

Permanently remove the data hash associated with the id used in the receiver’s creation from permanent storage.



285
286
287
288
# File 'lib/arrow/session/store.rb', line 285

def remove
	self.log.debug "Removing session data for key %s" % @id
	@new = true
end

#replace(other) ⇒ Object

Replace the contents of the session hash with those of the given other hash.



204
205
206
207
208
# File 'lib/arrow/session/store.rb', line 204

def replace( other )
	@data.replace( other )
ensure
	@modified = true
end

#retrieveObject

Retrieve the data hash stored in permanent storage associated with the id the object was created with. Concrete implementations should provide an overriding implementation of this method that calls #super with a block that returns the serialized data to be restored.



276
277
278
279
280
# File 'lib/arrow/session/store.rb', line 276

def retrieve
	self.log.debug "Retrieving session data for key %s" % @id
	self.serialized_data = yield
	@new = @modified = false
end

#saveObject

Save the session data to the backing store



238
239
240
241
242
243
244
245
# File 'lib/arrow/session/store.rb', line 238

def save
	return false unless self.modified? || self.new?
	if self.new?
		self.insert
	else
		self.update
	end
end