ObjectModel 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/README +849 -0
  2. data/lib/ObjectModel.res/config.yaml +5 -0
  3. data/lib/ObjectModel/AnEntity/BackReferences.rb +113 -0
  4. data/lib/ObjectModel/AnEntity/Bag.rb +129 -0
  5. data/lib/ObjectModel/AnEntity/BagCopy.rb +29 -0
  6. data/lib/ObjectModel/AnEntity/ChildrenBag.rb +10 -0
  7. data/lib/ObjectModel/AnEntity/EntityCopy.rb +38 -0
  8. data/lib/ObjectModel/AnEntity/EntityType.rb +408 -0
  9. data/lib/ObjectModel/AnEntity/ReferencesBag.rb +10 -0
  10. data/lib/ObjectModel/AnEntity/entity_cm.rb +108 -0
  11. data/lib/ObjectModel/Entity.rb +278 -0
  12. data/lib/ObjectModel/Errors/LoadError.rb +3 -0
  13. data/lib/ObjectModel/Errors/NoTransactionError.rb +3 -0
  14. data/lib/ObjectModel/Errors/NotFoundError.rb +2 -0
  15. data/lib/ObjectModel/Errors/OutdatedError.rb +8 -0
  16. data/lib/ObjectModel/Errors/ValidationError.rb +3 -0
  17. data/lib/ObjectModel/Indexes/HashIndex.rb +64 -0
  18. data/lib/ObjectModel/Indexes/IndexStorage.rb +64 -0
  19. data/lib/ObjectModel/Indexes/Manager.rb +72 -0
  20. data/lib/ObjectModel/Metadata.rb +34 -0
  21. data/lib/ObjectModel/Metadata.res/after_event_types.rb +25 -0
  22. data/lib/ObjectModel/Metadata.res/attribute_types_shortcuts.rb +10 -0
  23. data/lib/ObjectModel/Metadata.res/before_event_types.rb +25 -0
  24. data/lib/ObjectModel/Metadata.res/child_types_shortcuts.rb +4 -0
  25. data/lib/ObjectModel/Metadata.res/metadata_checks.rb +9 -0
  26. data/lib/ObjectModel/Metadata.res/reference_types_shortcuts.rb +4 -0
  27. data/lib/ObjectModel/Metadata/DSL.rb +11 -0
  28. data/lib/ObjectModel/Metadata/attribute.rb +56 -0
  29. data/lib/ObjectModel/Metadata/child.rb +50 -0
  30. data/lib/ObjectModel/Metadata/events.rb +109 -0
  31. data/lib/ObjectModel/Metadata/name.rb +20 -0
  32. data/lib/ObjectModel/Metadata/reference.rb +50 -0
  33. data/lib/ObjectModel/Metadata/require.rb +10 -0
  34. data/lib/ObjectModel/Metadata/validate.rb +66 -0
  35. data/lib/ObjectModel/Repository.rb +326 -0
  36. data/lib/ObjectModel/Repository/EventProcessor.rb +58 -0
  37. data/lib/ObjectModel/Repository/ObjectStorage.rb +102 -0
  38. data/lib/ObjectModel/Repository/StreamID.rb +20 -0
  39. data/lib/ObjectModel/Repository/StreamStorage.rb +121 -0
  40. data/lib/ObjectModel/Repository/SystemListener.rb +143 -0
  41. data/lib/ObjectModel/Repository/Transaction.rb +63 -0
  42. data/lib/ObjectModel/Repository/TransactionProcessor.rb +36 -0
  43. data/lib/ObjectModel/Tools/DefaultTransactionStrategy.rb +9 -0
  44. data/lib/ObjectModel/Tools/InMemoryCache.rb +9 -0
  45. data/lib/ObjectModel/Tools/NoCache.rb +18 -0
  46. data/lib/ObjectModel/Tools/OGLRUCache.rb +37 -0
  47. data/lib/ObjectModel/Types/BagType.rb +94 -0
  48. data/lib/ObjectModel/Types/BooleanType.rb +42 -0
  49. data/lib/ObjectModel/Types/ClassType.rb +43 -0
  50. data/lib/ObjectModel/Types/DataType.rb +44 -0
  51. data/lib/ObjectModel/Types/DateType.rb +43 -0
  52. data/lib/ObjectModel/Types/NumberType.rb +62 -0
  53. data/lib/ObjectModel/Types/ObjectType.rb +164 -0
  54. data/lib/ObjectModel/Types/ProcType.rb +43 -0
  55. data/lib/ObjectModel/Types/SingleType.rb +59 -0
  56. data/lib/ObjectModel/Types/StringType.rb +39 -0
  57. data/lib/ObjectModel/_require.rb +43 -0
  58. data/lib/ObjectModel/require.rb +1 -0
  59. data/rakefile +62 -0
  60. data/spec/ObjectModel/BasicSpec/BaseClass.rb +7 -0
  61. data/spec/ObjectModel/BasicSpec/BaseTypes.rb +11 -0
  62. data/spec/ObjectModel/BasicSpec/Descendant.rb +5 -0
  63. data/spec/ObjectModel/BasicSpec/EachTest.rb +14 -0
  64. data/spec/ObjectModel/BasicSpec/UpChild.rb +10 -0
  65. data/spec/ObjectModel/BasicSpec/UpParent.rb +11 -0
  66. data/spec/ObjectModel/ErrorsSpec/AfterCommitError.rb +9 -0
  67. data/spec/ObjectModel/ExtendedSpec/CustomInitialization.rb +11 -0
  68. data/spec/ObjectModel/ExtendedSpec/UpNotNil.rb +8 -0
  69. data/spec/ObjectModel/ExtendedSpec/UpParent.rb +11 -0
  70. data/spec/ObjectModel/ValidationSpec/BaseTypes.rb +11 -0
  71. data/spec/aspect_spec.rb +55 -0
  72. data/spec/back_references_spec.rb +161 -0
  73. data/spec/basic_spec.rb +162 -0
  74. data/spec/cascade_delete_spec.rb +168 -0
  75. data/spec/complex_events_spec.rb +134 -0
  76. data/spec/concurrency_spec.rb +186 -0
  77. data/spec/containment_spec.rb +146 -0
  78. data/spec/data_migration_spec.rb +51 -0
  79. data/spec/errors_spec.rb +65 -0
  80. data/spec/events_spec.rb +173 -0
  81. data/spec/extended_spec.rb +171 -0
  82. data/spec/indexing_spec.rb +56 -0
  83. data/spec/set_in_memory.rb +2 -0
  84. data/spec/set_no_cache.rb +2 -0
  85. data/spec/smoke_test_spec.rb +85 -0
  86. data/spec/stream_spec.rb +143 -0
  87. data/spec/stream_storage.rb +148 -0
  88. data/spec/timer.rb +5 -0
  89. data/spec/validation_spec.rb +87 -0
  90. metadata +186 -0
@@ -0,0 +1,20 @@
1
+ module ObjectModel
2
+ class Metadata
3
+ definition[:name] = Object.new.singleton_class do
4
+ def initial_value klass; klass.name end
5
+
6
+ def copy value; value.clone end
7
+
8
+ def inherit pvalue, cvalue; cvalue end
9
+ end
10
+
11
+ attr_accessor :name
12
+
13
+ class DSL
14
+ def name name
15
+ name.should_not! :be_nil
16
+ @meta.name = name
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ module ObjectModel
2
+ class Metadata
3
+ class References < Hash
4
+ def initialize
5
+ super{should! :be_never_called}
6
+ end
7
+
8
+ def copy
9
+ c = References.new
10
+ each{|n, m| c[n] = m.copy}
11
+ return c
12
+ end
13
+
14
+ def inherit parent
15
+ parent.copy.merge copy
16
+ end
17
+ end
18
+
19
+ class Reference
20
+ include OpenConstructor
21
+
22
+ attr_accessor :name, :ivname, :title, :type, :parameters
23
+
24
+ def copy; clone end
25
+ end
26
+
27
+ definition[:references] = Object.new.singleton_class do
28
+ def initial_value klass; References.new end
29
+
30
+ def copy references; references.copy end
31
+
32
+ def inherit pvalue, cvalue;
33
+ cvalue.inherit pvalue
34
+ end
35
+ end
36
+
37
+ attr_accessor :references
38
+
39
+ class DSL
40
+ def reference name, type = :single, other = {}
41
+ type.should! :be_in, Metadata::REFERENCE_TYPES_SHORTCUTS
42
+ values = {:name => name, :ivname => name.to_iv, :type => Metadata::REFERENCE_TYPES_SHORTCUTS[type]}.merge(other)
43
+ ref = Reference.new.set_with_check values
44
+ @meta.references[name] = ref
45
+
46
+ @klass._define_reference ref
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,10 @@
1
+ ObjectModel::Metadata
2
+ ObjectModel::Metadata::DSL
3
+ %w{
4
+ attribute
5
+ child
6
+ events
7
+ name
8
+ reference
9
+ validate
10
+ }.each{|file| require "#{File.dirname(__FILE__)}/#{file}"}
@@ -0,0 +1,66 @@
1
+ module ObjectModel
2
+ class Metadata
3
+ class Validations < Array
4
+ def copy
5
+ self.clone
6
+ end
7
+
8
+ def inherit parent
9
+ v = Validations.new
10
+ v.replace parent + self
11
+ v
12
+ end
13
+
14
+ def validate entity
15
+ every.validate entity
16
+ end
17
+ end
18
+
19
+ class Validation
20
+ attr_reader :method, :block
21
+
22
+ def initialize method = nil, &block
23
+ if method
24
+ method.should! :be_a, Symbol
25
+ block.should! :be_nil
26
+ @method = method
27
+ elsif block
28
+ method.should! :be_nil
29
+ @block = block
30
+ else
31
+ should! :be_never_called
32
+ end
33
+ end
34
+
35
+ def validate entity
36
+ if @method
37
+ entity.send @method
38
+ elsif @block
39
+ entity.instance_eval &@block
40
+ else
41
+ should! :be_never_called
42
+ end
43
+ end
44
+ end
45
+
46
+ definition[:validation] = Object.new.singleton_class do
47
+ def initial_value klass; Validations.new end
48
+
49
+ def copy validations; validations.copy end
50
+
51
+ def inherit pvalue, cvalue;
52
+ cvalue.inherit pvalue
53
+ end
54
+ end
55
+
56
+ attr_accessor :validation
57
+
58
+ class DSL
59
+ def validate method = nil, &block
60
+ vs = Validations.new
61
+ vs << Validation.new(method, &block)
62
+ @meta.validation = vs
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,326 @@
1
+ class Repository
2
+ inherit Log
3
+ attr_reader :storage, :indexes_storage, :stream_storage, :entity_listeners, :_index_manager
4
+
5
+ INITIALIZATION_SYNC = Monitor.new
6
+
7
+ def initialize name, params = {}
8
+ INITIALIZATION_SYNC.synchronize do
9
+ super()
10
+
11
+ config = Dir.getwd + "/config/object_model.yaml"
12
+
13
+ @name = name.to_s; @name.should_not! :be_nil
14
+ @params = params
15
+ @dir = params[:directory] || CONFIG[:directory]
16
+ @dir.should_not! :be_nil
17
+
18
+ check_the_same
19
+
20
+ # Disk Storages
21
+ @storage = ObjectStorage.new @name, @dir
22
+ @indexes_storage = Indexes::IndexStorage.new @name, @dir
23
+ @stream_storage = StreamStorage.new @name, @dir, CONFIG[:buffer_size]
24
+
25
+ # Synchronization
26
+ @sync, @entity_loading_sync, @stream_sync = Sync.new, Monitor.new, Monitor.new
27
+
28
+ # Listeners
29
+ @entity_listeners = []
30
+
31
+ # Transaction Strategy
32
+ if params.include? :transaction_strategy
33
+ klass = params[:transaction_strategy].should! :be_a, Class
34
+ @transaction_strategy = klass.new self
35
+ else
36
+ @transaction_strategy = Tools::DefaultTransactionStrategy.new self
37
+ end
38
+
39
+ # Cache
40
+ if params.include? :cache
41
+ @entities_cache = params[:cache]
42
+ else
43
+ cache_class_name = CONFIG[:cache]; cache_class_name.should_not! :be_nil
44
+ cache_class = eval cache_class_name, TOPLEVEL_BINDING, __FILE__, __LINE__
45
+ cache_parameters = CONFIG[:cache_parameters]
46
+ @entities_cache = cache_parameters ? cache_class.new(self, cache_parameters) : cache_class.new
47
+ end
48
+
49
+ # Indexes
50
+ index_def = params[:indexes] || []
51
+ index_def.should! :be_a, Array
52
+ index_def << Indexes::HashIndex.new(:path){|e| e.path}
53
+
54
+ @index_manager = Indexes::Manager.new self
55
+ @indexes_storage.index_manager = @index_manager
56
+ index_def.each{|index| @index_manager.add index}
57
+ build_indexes
58
+ end
59
+ end
60
+
61
+ def isolate &b
62
+ @sync.synchronize :SH do
63
+ b.call
64
+ end
65
+ end
66
+
67
+ def transaction transaction_or_name = nil, &b
68
+ Thread.current[:om_transaction].should! :be_nil
69
+
70
+ tr = if transaction_or_name.is_a? Transaction
71
+ transaction_or_name
72
+ else
73
+ t = @transaction_strategy.create_new
74
+ t.name = transaction_or_name if transaction_or_name
75
+ t
76
+ end
77
+ tr.repository = self
78
+
79
+ @sync.synchronize :SH do
80
+ begin
81
+ Thread.current[:om_transaction] = tr
82
+ b.call tr
83
+ ensure
84
+ Thread.current[:om_transaction] = nil
85
+ end
86
+ if tr.commited?
87
+ begin
88
+ tr.event_processor.fire_after_commit
89
+ ensure
90
+ @transaction_strategy.after_commit tr if tr.managed
91
+ end
92
+ end
93
+ end
94
+ return tr
95
+ end
96
+
97
+ def commit tr
98
+ if t = Thread.current[:om_transaction]
99
+ t.should! :equal?, tr
100
+ _commit tr
101
+ else
102
+ transaction(tr){_commit tr}
103
+ end
104
+ end
105
+
106
+ def put key, value
107
+ storage.put key, value
108
+ end
109
+
110
+ def get key
111
+ storage.get key
112
+ end
113
+
114
+ def _commit tr
115
+ processor = TransactionProcessor.new self, tr
116
+ processor.check_outdated
117
+ tr.event_processor.fire_before_commit
118
+
119
+ begin
120
+ @sync.synchronize(:EX) do
121
+ processor.write_back
122
+ @storage.transaction do
123
+ processor.persist
124
+ @index_manager.update tr
125
+ end
126
+ @entities_cache.update tr
127
+ end
128
+ rescue Exception => e
129
+ close
130
+ log.error "Fatal Error, Repository '#{@name}' can't be used!"
131
+ raise e
132
+ end
133
+
134
+ tr.commited!
135
+ return tr
136
+ end
137
+
138
+ def close
139
+ INITIALIZATION_SYNC.synchronize do
140
+ @sync.synchronize(:EX) do
141
+ @storage.close
142
+ @indexes_storage.close
143
+ @@runing.delete @name + @dir
144
+ end
145
+ end
146
+ end
147
+
148
+ def clear
149
+ close
150
+ Repository.delete @name, @dir
151
+ initialize @name, @params
152
+ end
153
+
154
+ def by_id entity_id
155
+ @entity_loading_sync.synchronize do
156
+ entity = @entities_cache[entity_id]
157
+ unless entity
158
+ entity = AnEntity::EntityType.load entity_id, self, @storage
159
+ entity.should_not! :be_nil
160
+ @entities_cache[entity_id] = entity
161
+ end
162
+ return entity
163
+ end
164
+ end
165
+
166
+ def include_id? entity_id
167
+ @entity_loading_sync.synchronize do
168
+ entity = @entities_cache[entity_id]
169
+ if entity
170
+ return true
171
+ else
172
+ return AnEntity::EntityType.storage_include? entity_id, @storage
173
+ end
174
+ end
175
+ end
176
+
177
+ def build_indexes
178
+ @sync.synchronize(:EX){@index_manager.build_indexes}
179
+ end
180
+
181
+ def clear_indexes
182
+ @sync.synchronize(:EX){@index_manager.clear_indexes}
183
+ end
184
+
185
+ def add_index index
186
+ @sync.synchronize(:EX) do
187
+ @index_manager.add index
188
+ @index_manager.build_indexes
189
+ end
190
+ end
191
+
192
+ def delete_index index_name
193
+ @sync.synchronize(:EX){@index_manager.delete index_name}
194
+ end
195
+
196
+ def index name
197
+ @index_manager[name]
198
+ end
199
+
200
+ def include? path
201
+ path = path.to_s if path.is_a? Path
202
+ path.should! :be_a, String
203
+
204
+ entity_id = index(:path).get_entity_id path
205
+ entity_id.should! :be_a, [String, NilClass]
206
+
207
+ return entity_id != nil
208
+ end
209
+
210
+ def [] path
211
+ path = path.to_s if path.is_a? Path
212
+ path.should! :be_a, String
213
+
214
+ entity_id = index(:path).get_entity_id path
215
+ raise_without_self NotFoundError, "Entity with Path '#{path}' not found!", ObjectModel if entity_id == nil
216
+
217
+ entity_id.should! :be_a, String
218
+ return by_id entity_id
219
+ end
220
+
221
+ def to_s
222
+ "#<Repository: #{@name}>"
223
+ end
224
+
225
+ def inspect
226
+ to_s
227
+ end
228
+
229
+ def print name = nil
230
+ @storage.print name
231
+ end
232
+
233
+ class << self
234
+ def delete name, directory = CONFIG[:directory];
235
+ INITIALIZATION_SYNC.synchronize do
236
+ name = name.to_s
237
+ path = File.join(directory, name)
238
+ FileUtils.rm_rf path if File.exist? path
239
+ end
240
+ end
241
+ end
242
+
243
+ def _index_manager; @index_manager end
244
+
245
+ def print
246
+ @storage.print
247
+ @indexes_storage.print
248
+ end
249
+
250
+ protected
251
+ def check_the_same
252
+ @@runing ||= Set.new
253
+ if @@runing.include?(@name + @dir)
254
+ raise_without_self "Forbiden to open two the same Repositories simultaneously!"
255
+ end
256
+ @@runing << @name + @dir
257
+ end
258
+ end
259
+
260
+ # Stream
261
+ class Repository
262
+ def stream_metadata_read id
263
+ @stream_storage.metadata_read id
264
+ end
265
+
266
+ def stream_metadata_put id, metadata
267
+ @stream_storage.metadata_put id, metadata
268
+ end
269
+
270
+ def stream_size id
271
+ @stream_storage.stream_size id
272
+ end
273
+
274
+ def size
275
+ @storage.size
276
+ end
277
+
278
+ def each &b
279
+ AnEntity::EntityType.each_entity_in_repository self, &b
280
+ end
281
+
282
+ def stream_put data = nil, &block;
283
+ id = nil
284
+ @stream_sync.synchronize{id = StreamID.new(storage.generate(:stream_id))}
285
+ @stream_storage.stream_put id, data, &block
286
+ return id
287
+ end
288
+
289
+ def stream_put_each stream
290
+ id = nil
291
+ @stream_sync.synchronize{id = StreamID.new(storage.generate(:stream_id))}
292
+ @stream_storage.stream_put_each id, stream
293
+ return id
294
+ end
295
+
296
+ def stream_put_from_file file_name
297
+ File.open file_name, "r" do |f|
298
+ stream_put_each f
299
+ end
300
+ end
301
+
302
+ def stream_read_to_file id, file_name
303
+ File.open file_name, "w" do |to|
304
+ stream_read_each(id){|part| to.write part}
305
+ end
306
+ end
307
+
308
+ def stream_read id, &block;
309
+ @stream_storage.stream_read id, &block
310
+ end
311
+
312
+ def stream_read_each id, &block
313
+ @stream_storage.stream_read_each id, &block
314
+ end
315
+
316
+ def stream_collect_garbage object_space = ObjectSpace
317
+ @stream_sync.synchronize do
318
+ ObjectSpace.garbage_collect
319
+ memory = Set.new
320
+ object_space.each_object(StreamID){|s| memory.add s.sid.to_s}
321
+ @stream_storage.list_of_ids.each do |id|
322
+ @stream_storage.delete StreamID.new(id) unless memory.include?(id)
323
+ end
324
+ end
325
+ end
326
+ end