iotaz 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,299 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #--
4
+ # Copyright � Peter Wood, 2005
5
+ #
6
+ # The contents of this file are subject to the Mozilla Public License Version
7
+ # 1.1 (the "License"); you may not use this file except in compliance with the
8
+ # License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.mozilla.org/MPL/
11
+ #
12
+ # Software distributed under the License is distributed on an "AS IS" basis,
13
+ # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14
+ # the specificlanguage governing rights and limitations under the License.
15
+ #
16
+ # The Original Code is the FireRuby extension for the Ruby language.
17
+ #
18
+ # The Initial Developer of the Original Code is Peter Wood. All Rights
19
+ # Reserved.
20
+ #++
21
+ #
22
+
23
+ require 'thread'
24
+
25
+ module Iotaz
26
+ #
27
+ # This class represents an object within an object pool and shouldn't really
28
+ # be used outside of this context.
29
+ #
30
+ class PoolObject
31
+ #
32
+ # This is the constructor for the PoolObject class.
33
+ #
34
+ # ==== Parameters
35
+ # object:: The object to be held within the pool.
36
+ #
37
+ def initialize(object)
38
+ @object = object
39
+ @reserved = false
40
+ @timestamp = Time.new
41
+ end
42
+
43
+
44
+ #
45
+ # This method reserves a pool object.
46
+ #
47
+ def reserve
48
+ if @reserve
49
+ raise IotazError.new('Reserve called on reserved pool object.')
50
+ end
51
+ @reserved = true
52
+ @timestamp = Time.new
53
+ end
54
+
55
+
56
+ #
57
+ # This method releases a previously reserved pool object.
58
+ #
59
+ def release
60
+ if @reserve == false
61
+ raise IotazError.new('Release called on unreserved pool object.')
62
+ end
63
+ @reserved = false
64
+ @timestamp = Time.new
65
+ end
66
+
67
+
68
+ # Class attribute accessor.
69
+ attr_reader :object, :reserved, :timestamp
70
+ end # End of the PoolObject class.
71
+
72
+
73
+ #
74
+ # This class represents a simple object pool. It should be noted that this
75
+ # class starts a thread of it's own to monitor for idle resources if an
76
+ # idle period is set. Note also that the idle period and the idle test
77
+ # interval cannot be reduced to less than 60 seconds each. The pool is
78
+ # considered immutable after it is created.
79
+ #
80
+ class ObjectPool
81
+ # A definition for the minimum idle period setting.
82
+ MIN_IDLE = 60
83
+
84
+ # A definition for the minimum idle checking interval.
85
+ MIN_INTERVAL = 60
86
+
87
+
88
+ #
89
+ # This is the constructor for the ObjectPool class.
90
+ #
91
+ # ==== Parameters
92
+ # factory:: A reference to the object that will be used to manufacture
93
+ # and destroy the resource objects. This object must have
94
+ # methods called create and destroy.
95
+ # maximum:: The maximum amount of objects the pool is permitted to have
96
+ # available.
97
+ # minimum:: The minimum amount of objects that the pool is permitted
98
+ # to have available. Defaults to zero.
99
+ # idle:: The minimum amount of time, in seconds, that a resource my
100
+ # be idle before being destroyed. If set to -1, the default
101
+ # value then the resource objects will never be destroyed.
102
+ # interval:: The period, in seconds between checks for idle entries.
103
+ # Defaults to 600 seconds (10 minutes).
104
+ #
105
+ # ==== Exceptions
106
+ # IotazError:: Generated whenever a problem occurs with the settings for
107
+ # the object pool.
108
+ #
109
+ def initialize(factory, maximum, minimum=0, idle=-1, interval=600)
110
+ if maximum.kind_of?(Integer) == false or maximum < minimum
111
+ raise IotazError.new('Invalid object pool maximum setting specified.')
112
+ end
113
+
114
+ @factory = factory
115
+ @objects = []
116
+ @maximum = maximum
117
+ @minimum = minimum
118
+ @mutex = Mutex.new
119
+ @thread = nil
120
+ @blocked = []
121
+ if idle >= 0
122
+ @idle = idle > MIN_IDLE ? idle : MIN_IDLE
123
+ else
124
+ @idle = -1
125
+ end
126
+ @interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL
127
+
128
+ start_thread if idle != -1
129
+
130
+ # Add the minimum number of resources.
131
+ @minimum.times do
132
+ @objects.push(PoolObject.new(@factory.create))
133
+ end
134
+ end
135
+
136
+
137
+ #
138
+ # This method obtains an object from the pool. If there isn't a free
139
+ # object in the pool one will be manufactured unless the pool has
140
+ # reached maximum capacity. The calling thread will block until a
141
+ # resource has become available. The method also accepts a block
142
+ # which delimits the lease time that the acquired object is given.
143
+ # The acquired object is passed as a parameter to the block and is
144
+ # automatically released when the block exits. If a block is given
145
+ # then the method always returns nil.
146
+ #
147
+ # ==== Parameters
148
+ # wait:: A boolean flag to indicate whether the thread will wait for
149
+ # the resource to become available if one isn't immediately
150
+ # available.
151
+ #
152
+ # ==== Exceptions
153
+ # IotazError:: Generated whenever the caller has indicated that they are
154
+ # not prepared to wait for a pool object and a pool object is
155
+ # not immediately available.
156
+ # Exception:: If a block is given and, during it's execution, an
157
+ # exception is raised it will be thrown out of the method
158
+ # call as is.
159
+ #
160
+ def acquire(wait=true)
161
+ resource = nil
162
+ while resource == nil
163
+ @mutex.synchronize do
164
+ resource = @objects.find {|object| object.reserved == false}
165
+ if resource == nil
166
+ if @objects.size < @maximum
167
+ resource = PoolObject.new(@factory.create)
168
+ resource.reserve
169
+ @objects.push(resource)
170
+ resource = resource.object
171
+ else
172
+ @blocked.push(Thread.current) if wait
173
+ end
174
+ else
175
+ resource.reserve
176
+ resource = resource.object
177
+ end
178
+ end
179
+ if resource == nil and wait == false
180
+ raise IotazError.new('Pooled object not available.')
181
+ end
182
+ Thread.stop if resource == nil and wait == true
183
+ end
184
+
185
+ if block_given?
186
+ begin
187
+ yield(resource)
188
+ rescue Exception => error
189
+ raise error
190
+ ensure
191
+ release(resource)
192
+ resource = nil
193
+ end
194
+ end
195
+
196
+ resource
197
+ end
198
+
199
+
200
+ #
201
+ # This method returns an object to the pool. This method will also
202
+ # restart any threads waiting for pool resources.
203
+ #
204
+ # ==== Parameters
205
+ # object:: A reference to the object instance being returned to the
206
+ # pool.
207
+ #
208
+ def release(object)
209
+ @mutex.synchronize do
210
+ resource = @objects.find {|entry| entry.object == object}
211
+ if resource != nil
212
+ resource.release
213
+ @blocked.each do |thread|
214
+ thread.run
215
+ end
216
+ @blocked = []
217
+ end
218
+ end
219
+ end
220
+
221
+
222
+ #
223
+ # This method initiates the thread that monitors the pool for idle
224
+ # resources.
225
+ #
226
+ def start_thread
227
+ @mutex.synchronize do
228
+ if @therad == nil
229
+ @thread = Thread.new do
230
+ idle_sweep
231
+ sleep(@interval)
232
+ end
233
+ end
234
+ end
235
+ end
236
+
237
+
238
+ #
239
+ # This method cleans up the resources associated with a pool and shuts
240
+ # down it's monitor thread. The method should be called before the
241
+ # application using the pool terminates.
242
+ #
243
+ def shutdown
244
+ @mutex.synchronize do
245
+ @thread.exit if @thread != nil
246
+ @objects.each do |entry|
247
+ @factory.destroy(entry.object)
248
+ end
249
+ end
250
+ end
251
+
252
+
253
+ #
254
+ # This method returns the number of objects currently held within a
255
+ # an object pool.
256
+ #
257
+ def size
258
+ @objects.size
259
+ end
260
+
261
+
262
+ #
263
+ # This method returns the number of objects currently available within
264
+ # an object pool.
265
+ #
266
+ def available
267
+ total = 0
268
+ @mutex.synchronize do
269
+ @objects.each {|entry| total += 1 if entry.reserved == false}
270
+ end
271
+ total
272
+ end
273
+
274
+
275
+ #
276
+ # This method is used internally by the pool to remove idle entries
277
+ #
278
+ def idle_sweep
279
+ @mutex.synchronize do
280
+ @objects.delete_if do |entry|
281
+ result = false
282
+ if Time.new.to_i - entry.timestamp.to_i >= @interval and
283
+ @objects.size > @minimum
284
+ @factory.destroy(entry.object)
285
+ result = true
286
+ end
287
+ result
288
+ end
289
+ end
290
+ end
291
+
292
+
293
+ # Class attribute accessor.
294
+ attr_reader :factory, :minimum, :maximum, :idle, :interval
295
+
296
+ # Method access alterations.
297
+ private :start_thread, :idle_sweep
298
+ end # End of the ObjectPool class.
299
+ end # End of the Iotaz module.
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #--
4
+ # Copyright (C) Peter Wood, 2005
5
+ #
6
+ # The contents of this file are subject to the Mozilla Public License Version
7
+ # 1.1 (the "License"); you may not use this file except in compliance with the
8
+ # License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.mozilla.org/MPL/
11
+ #
12
+ # Software distributed under the License is distributed on an "AS IS" basis,
13
+ # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14
+ # the specificlanguage governing rights and limitations under the License.
15
+ #
16
+ # The Original Code is the FireRuby extension for the Ruby language.
17
+ #
18
+ # The Initial Developer of the Original Code is Peter Wood. All Rights
19
+ # Reserved.
20
+ #++
21
+ #
22
+
23
+ module Iotaz
24
+ module Persistent
25
+ # Module constants.
26
+ @@code = [%q{@@iotaz_meta_data = Iotaz::IotazMetaData.new(self)},
27
+ %q{def self.class_basename(source)
28
+ name = source.instance_of?(String) ? source : source.name
29
+ index = name.rindex("::")
30
+ if index != nil
31
+ index += 2
32
+ name = name[index, name.length - index]
33
+ end
34
+ name
35
+ end},
36
+ %q{def self.iotaz_meta_data
37
+ @@iotaz_meta_data
38
+ end},
39
+ %q{def self.persistent_attr(name, column=nil, readonly=false)
40
+ attr :"#{name}", true
41
+ private :"#{name}=" if readonly
42
+ name = name.id2name if name.class == Symbol
43
+ attribute = Attribute.new(name, column)
44
+ @@iotaz_meta_data.add_attribute(attribute)
45
+ end},
46
+ %q{def self.sequence_attr(name, column=nil, key=true,
47
+ source=nil, readonly=true,
48
+ create=true, update=false)
49
+ attr :"#{name}", true
50
+ private :"#{name}=" if readonly
51
+ name = name.id2name if name.class == Symbol
52
+ events = ""
53
+ if create == true and update == false
54
+ events = 'INSERT'
55
+ elsif create == false and update == true
56
+ events = 'UPDATE'
57
+ else
58
+ events = 'INSERT,UPDATE'
59
+ end
60
+ generator = source
61
+ if source == nil
62
+ generator = "#{class_basename(self)}_ID_SQ".upcase
63
+ end
64
+ attribute = GeneratedAttribute.new(name, 'SEQUENCE',
65
+ events, generator,
66
+ column)
67
+ @@iotaz_meta_data.add_attribute(attribute, key)
68
+ end},
69
+ %q{def self.date_attr(name, column=nil, create=true,
70
+ update=false, value='TODAY',
71
+ readonly=true)
72
+ attr :"#{name}", true
73
+ private :"#{name}=" if readonly
74
+ name = name.id2name if name.class == Symbol
75
+ events = ""
76
+ if create == true and update == false
77
+ events = 'INSERT'
78
+ elsif create == false and update == true
79
+ events = 'UPDATE'
80
+ else
81
+ events = 'INSERT,UPDATE'
82
+ end
83
+ attribute = GeneratedAttribute.new(name, 'DATE', events,
84
+ value, column)
85
+ @@iotaz_meta_data.add_attribute(attribute)
86
+ end},
87
+ %q{def self.time_attr(name, column=nil, create=true,
88
+ update=false, readonly=true)
89
+ attr :"#{name}", true
90
+ private :"#{name}=" if readonly
91
+ name = name.id2name if name.class == Symbol
92
+ events = ""
93
+ if create == true and update == false
94
+ events = 'INSERT'
95
+ elsif create == false and update == true
96
+ events = 'UPDATE'
97
+ else
98
+ events = 'INSERT,UPDATE'
99
+ end
100
+ attribute = GeneratedAttribute.new(name, 'TIME', events,
101
+ 'NOW', column)
102
+ @@iotaz_meta_data.add_attribute(attribute)
103
+ end},
104
+ %q{def self.timestamp_attr(name, column=nil, create=true,
105
+ update=false, readonly=true)
106
+ attr :"#{name}", true
107
+ private :"#{name}=" if readonly
108
+ name = name.id2name if name.class == Symbol
109
+ events = ""
110
+ if create == true and update == false
111
+ events = 'INSERT'
112
+ elsif create == false and update == true
113
+ events = 'UPDATE'
114
+ else
115
+ events = 'INSERT,UPDATE'
116
+ end
117
+ attribute = GeneratedAttribute.new(name, 'TIMESTAMP',
118
+ events, 'NOW', column)
119
+ @@iotaz_meta_data.add_attribute(attribute)
120
+ end},
121
+ %q{def self.table_name=(name)
122
+ @@iotaz_meta_data.table = name
123
+ end}]
124
+
125
+
126
+ #
127
+ # This method gets invoked whenever this module is used to extend an
128
+ # existing class or module.
129
+ #
130
+ # ==== Parameters
131
+ # target:: A reference to the class or module that is being extended.
132
+ #
133
+ def Persistent.extend_object(target)
134
+ @@code.each do |entry|
135
+ target.module_eval(entry)
136
+ end
137
+ end
138
+
139
+
140
+ #
141
+ # This method gets invoked whenever this module is included into another
142
+ # module or class.
143
+ #
144
+ # ==== Parameters
145
+ # target:: A reference to the class or module including the Persistent
146
+ # module.
147
+ #
148
+ def Persistent.append_features(target)
149
+ super(target)
150
+ @@code.each do |entry|
151
+ target.module_eval(entry)
152
+ end
153
+ end
154
+ end # End of the Persistent module
155
+ end # End of the Iotaz module.