iotaz 0.1.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,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.