synapse-core 0.1.2
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.
- data/lib/synapse.rb +351 -0
- data/lib/synapse/command/command_bus.rb +45 -0
- data/lib/synapse/command/command_callback.rb +18 -0
- data/lib/synapse/command/command_filter.rb +17 -0
- data/lib/synapse/command/command_handler.rb +13 -0
- data/lib/synapse/command/dispatch_interceptor.rb +16 -0
- data/lib/synapse/command/duplication.rb +43 -0
- data/lib/synapse/command/errors.rb +27 -0
- data/lib/synapse/command/filters/validation.rb +32 -0
- data/lib/synapse/command/gateway.rb +34 -0
- data/lib/synapse/command/interceptor_chain.rb +31 -0
- data/lib/synapse/command/interceptors/serialization.rb +35 -0
- data/lib/synapse/command/message.rb +19 -0
- data/lib/synapse/command/rollback_policy.rb +22 -0
- data/lib/synapse/command/simple_command_bus.rb +138 -0
- data/lib/synapse/command/wiring.rb +47 -0
- data/lib/synapse/domain/aggregate_root.rb +121 -0
- data/lib/synapse/domain/event_container.rb +127 -0
- data/lib/synapse/domain/message.rb +82 -0
- data/lib/synapse/domain/message_builder.rb +34 -0
- data/lib/synapse/domain/stream.rb +108 -0
- data/lib/synapse/duplication.rb +60 -0
- data/lib/synapse/errors.rb +13 -0
- data/lib/synapse/event_bus/event_bus.rb +40 -0
- data/lib/synapse/event_bus/event_listener.rb +16 -0
- data/lib/synapse/event_bus/event_listener_proxy.rb +12 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +69 -0
- data/lib/synapse/event_bus/wiring.rb +23 -0
- data/lib/synapse/event_sourcing/aggregate_factory.rb +69 -0
- data/lib/synapse/event_sourcing/aggregate_root.rb +104 -0
- data/lib/synapse/event_sourcing/conflict_resolver.rb +80 -0
- data/lib/synapse/event_sourcing/entity.rb +64 -0
- data/lib/synapse/event_sourcing/member.rb +72 -0
- data/lib/synapse/event_sourcing/repository.rb +119 -0
- data/lib/synapse/event_sourcing/snapshot/count_stream.rb +86 -0
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +91 -0
- data/lib/synapse/event_sourcing/snapshot/taker.rb +73 -0
- data/lib/synapse/event_sourcing/storage_listener.rb +34 -0
- data/lib/synapse/event_sourcing/stream_decorator.rb +25 -0
- data/lib/synapse/event_store/errors.rb +16 -0
- data/lib/synapse/event_store/event_store.rb +43 -0
- data/lib/synapse/event_store/in_memory.rb +59 -0
- data/lib/synapse/event_store/mongo/cursor_event_stream.rb +63 -0
- data/lib/synapse/event_store/mongo/event_store.rb +86 -0
- data/lib/synapse/event_store/mongo/per_commit_strategy.rb +253 -0
- data/lib/synapse/event_store/mongo/per_event_strategy.rb +143 -0
- data/lib/synapse/event_store/mongo/storage_strategy.rb +113 -0
- data/lib/synapse/event_store/mongo/template.rb +73 -0
- data/lib/synapse/identifier.rb +23 -0
- data/lib/synapse/message.rb +101 -0
- data/lib/synapse/message_builder.rb +38 -0
- data/lib/synapse/process_manager/correlation.rb +32 -0
- data/lib/synapse/process_manager/correlation_resolver.rb +14 -0
- data/lib/synapse/process_manager/correlation_set.rb +58 -0
- data/lib/synapse/process_manager/process.rb +71 -0
- data/lib/synapse/repository/errors.rb +26 -0
- data/lib/synapse/repository/lock_manager.rb +40 -0
- data/lib/synapse/repository/locking.rb +97 -0
- data/lib/synapse/repository/pessimistic_lock_manager.rb +61 -0
- data/lib/synapse/repository/repository.rb +109 -0
- data/lib/synapse/serialization/converter.rb +39 -0
- data/lib/synapse/serialization/converter/chain.rb +45 -0
- data/lib/synapse/serialization/converter/factory.rb +68 -0
- data/lib/synapse/serialization/converter/identity.rb +29 -0
- data/lib/synapse/serialization/converter/json.rb +31 -0
- data/lib/synapse/serialization/converter/ox.rb +31 -0
- data/lib/synapse/serialization/errors.rb +12 -0
- data/lib/synapse/serialization/lazy_object.rb +61 -0
- data/lib/synapse/serialization/message/data.rb +25 -0
- data/lib/synapse/serialization/message/metadata.rb +13 -0
- data/lib/synapse/serialization/message/serialization_aware.rb +17 -0
- data/lib/synapse/serialization/message/serialization_aware_message.rb +66 -0
- data/lib/synapse/serialization/message/serialized_message.rb +201 -0
- data/lib/synapse/serialization/message/serialized_message_builder.rb +64 -0
- data/lib/synapse/serialization/message/serialized_object_cache.rb +50 -0
- data/lib/synapse/serialization/message/serializer.rb +47 -0
- data/lib/synapse/serialization/revision_resolver.rb +30 -0
- data/lib/synapse/serialization/serialized_object.rb +37 -0
- data/lib/synapse/serialization/serialized_type.rb +31 -0
- data/lib/synapse/serialization/serializer.rb +98 -0
- data/lib/synapse/serialization/serializer/marshal.rb +32 -0
- data/lib/synapse/serialization/serializer/oj.rb +34 -0
- data/lib/synapse/serialization/serializer/ox.rb +31 -0
- data/lib/synapse/uow/factory.rb +28 -0
- data/lib/synapse/uow/listener.rb +79 -0
- data/lib/synapse/uow/listener_collection.rb +93 -0
- data/lib/synapse/uow/nesting.rb +262 -0
- data/lib/synapse/uow/provider.rb +71 -0
- data/lib/synapse/uow/storage_listener.rb +14 -0
- data/lib/synapse/uow/transaction_manager.rb +27 -0
- data/lib/synapse/uow/uow.rb +178 -0
- data/lib/synapse/upcasting/chain.rb +78 -0
- data/lib/synapse/upcasting/context.rb +58 -0
- data/lib/synapse/upcasting/data.rb +30 -0
- data/lib/synapse/upcasting/single_upcaster.rb +57 -0
- data/lib/synapse/upcasting/upcaster.rb +55 -0
- data/lib/synapse/version.rb +3 -0
- data/lib/synapse/wiring/message_wiring.rb +41 -0
- data/lib/synapse/wiring/wire.rb +55 -0
- data/lib/synapse/wiring/wire_registry.rb +61 -0
- data/test/command/duplication_test.rb +54 -0
- data/test/command/gateway_test.rb +25 -0
- data/test/command/interceptor_chain_test.rb +26 -0
- data/test/command/serialization_test.rb +37 -0
- data/test/command/simple_command_bus_test.rb +141 -0
- data/test/command/validation_test.rb +42 -0
- data/test/command/wiring_test.rb +73 -0
- data/test/domain/aggregate_root_test.rb +57 -0
- data/test/domain/fixtures.rb +31 -0
- data/test/domain/message_test.rb +61 -0
- data/test/domain/stream_test.rb +35 -0
- data/test/duplication_test.rb +40 -0
- data/test/event_bus/wiring_test.rb +46 -0
- data/test/event_sourcing/aggregate_factory_test.rb +28 -0
- data/test/event_sourcing/aggregate_root_test.rb +76 -0
- data/test/event_sourcing/entity_test.rb +34 -0
- data/test/event_sourcing/fixtures.rb +85 -0
- data/test/event_sourcing/repository_test.rb +102 -0
- data/test/event_sourcing/snapshot/aggregate_taker_test.rb +39 -0
- data/test/event_sourcing/snapshot/deferred_taker_test.rb +19 -0
- data/test/event_sourcing/snapshot/integration_test.rb +65 -0
- data/test/event_sourcing/storage_listener_test.rb +77 -0
- data/test/event_store/in_memory_test.rb +47 -0
- data/test/process_manager/correlation_set_test.rb +49 -0
- data/test/process_manager/correlation_test.rb +24 -0
- data/test/process_manager/process_test.rb +52 -0
- data/test/repository/locking_test.rb +101 -0
- data/test/serialization/converter/factory_test.rb +33 -0
- data/test/serialization/converter/identity_test.rb +17 -0
- data/test/serialization/converter/json_test.rb +31 -0
- data/test/serialization/converter/ox_test.rb +40 -0
- data/test/serialization/fixtures.rb +17 -0
- data/test/serialization/lazy_object_test.rb +32 -0
- data/test/serialization/message/metadata_test.rb +19 -0
- data/test/serialization/message/serialization_aware_message_test.rb +88 -0
- data/test/serialization/message/serialized_message_builder_test.rb +41 -0
- data/test/serialization/message/serialized_message_test.rb +140 -0
- data/test/serialization/message/serializer_test.rb +50 -0
- data/test/serialization/revision_resolver_test.rb +12 -0
- data/test/serialization/serialized_object_test.rb +36 -0
- data/test/serialization/serialized_type_test.rb +27 -0
- data/test/serialization/serializer/marshal_test.rb +22 -0
- data/test/serialization/serializer/oj_test.rb +24 -0
- data/test/serialization/serializer/ox_test.rb +36 -0
- data/test/serialization/serializer_test.rb +20 -0
- data/test/test_helper.rb +19 -0
- data/test/uow/factory_test.rb +23 -0
- data/test/uow/outer_commit_listener_test.rb +50 -0
- data/test/uow/provider_test.rb +70 -0
- data/test/uow/uow_test.rb +337 -0
- data/test/upcasting/chain_test.rb +29 -0
- data/test/upcasting/fixtures.rb +66 -0
- data/test/wiring/wire_registry_test.rb +60 -0
- data/test/wiring/wire_test.rb +51 -0
- metadata +263 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Serialization
|
|
3
|
+
# Represents a mechanism for determining the revision of a payload being serialized
|
|
4
|
+
# @abstract
|
|
5
|
+
class RevisionResolver
|
|
6
|
+
# Determines the revision of the given payload type
|
|
7
|
+
#
|
|
8
|
+
# @abstract
|
|
9
|
+
# @param [Class] payload_type
|
|
10
|
+
# @return [String] The revision of the given payload type
|
|
11
|
+
def revision_of(payload_type); end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Implementation of a revision resolver that returns a fixed value. This could be an
|
|
15
|
+
# application version number, for example
|
|
16
|
+
class FixedRevisionResolver < RevisionResolver
|
|
17
|
+
# @param [String] revision
|
|
18
|
+
# @return [undefined]
|
|
19
|
+
def initialize(revision)
|
|
20
|
+
@revision = revision
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @param [Class] payload_type
|
|
24
|
+
# @return [String] Returns the fixed revision
|
|
25
|
+
def revision_of(payload_type)
|
|
26
|
+
@revision.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Serialization
|
|
3
|
+
class SerializedObject
|
|
4
|
+
# @return [Object]
|
|
5
|
+
attr_reader :content
|
|
6
|
+
|
|
7
|
+
# @return [Class]
|
|
8
|
+
attr_reader :content_type
|
|
9
|
+
|
|
10
|
+
# @return [SerializedType]
|
|
11
|
+
attr_reader :type
|
|
12
|
+
|
|
13
|
+
# @param [Object] content
|
|
14
|
+
# @param [Class] content_type
|
|
15
|
+
# @param [SerializedType] type
|
|
16
|
+
# @return [undefined]
|
|
17
|
+
def initialize(content, content_type, type)
|
|
18
|
+
@content = content
|
|
19
|
+
@content_type = content_type
|
|
20
|
+
@type = type
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ==(other)
|
|
24
|
+
self.class === other and
|
|
25
|
+
other.content == @content and
|
|
26
|
+
other.content_type == @content_type and
|
|
27
|
+
other.type == @type
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias eql? ==
|
|
31
|
+
|
|
32
|
+
def hash
|
|
33
|
+
@content.hash ^ @content_type.hash ^ @type.hash
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Serialization
|
|
3
|
+
class SerializedType
|
|
4
|
+
# @return [String]
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
7
|
+
# @return [String]
|
|
8
|
+
attr_reader :revision
|
|
9
|
+
|
|
10
|
+
# @param [String] name
|
|
11
|
+
# @param [String] revision
|
|
12
|
+
# @return [undefined]
|
|
13
|
+
def initialize(name, revision = nil)
|
|
14
|
+
@name = name
|
|
15
|
+
@revision = revision
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ==(other)
|
|
19
|
+
self.class === other and
|
|
20
|
+
other.name == @name and
|
|
21
|
+
other.revision == @revision
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
alias eql? ==
|
|
25
|
+
|
|
26
|
+
def hash
|
|
27
|
+
@name.hash ^ @revision.hash
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Serialization
|
|
3
|
+
# Represents a mechanism for serializing and deserializing objects
|
|
4
|
+
# @abstract
|
|
5
|
+
class Serializer
|
|
6
|
+
# @return [ConverterFactory]
|
|
7
|
+
attr_accessor :converter_factory
|
|
8
|
+
|
|
9
|
+
# @return [RevisionResolver]
|
|
10
|
+
attr_accessor :revision_resolver
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@converter_factory = ConverterFactory.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @param [Object] object
|
|
17
|
+
# @param [Class] representation_type
|
|
18
|
+
# @return [SerializedObject]
|
|
19
|
+
def serialize(object, representation_type)
|
|
20
|
+
content = perform_serialize(object)
|
|
21
|
+
content = convert(content, native_content_type, representation_type)
|
|
22
|
+
type = type_for(object.class)
|
|
23
|
+
|
|
24
|
+
SerializedObject.new(content, representation_type, type)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param [SerializedObject] serialized_object
|
|
28
|
+
# @return [Object]
|
|
29
|
+
def deserialize(serialized_object)
|
|
30
|
+
content = convert(serialized_object.content, serialized_object.content_type, native_content_type)
|
|
31
|
+
type = class_for(serialized_object.type)
|
|
32
|
+
|
|
33
|
+
perform_deserialize(content, type)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param [Class] representation_type
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def can_serialize_to?(representation_type)
|
|
39
|
+
converter_factory.has_converter?(String, representation_type)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @param [SerializedType] serialized_type
|
|
43
|
+
# @return [Class]
|
|
44
|
+
def class_for(serialized_type)
|
|
45
|
+
begin
|
|
46
|
+
serialized_type.name.constantize
|
|
47
|
+
rescue
|
|
48
|
+
raise UnknownSerializedTypeError, 'Unknown serialized type %s' % serialized_type.name
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @param [Class] type
|
|
53
|
+
# @return [SerializedType]
|
|
54
|
+
def type_for(type)
|
|
55
|
+
if @revision_resolver
|
|
56
|
+
SerializedType.new(type.to_s, @revision_resolver.revision_of(type))
|
|
57
|
+
else
|
|
58
|
+
SerializedType.new(type.to_s)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
protected
|
|
63
|
+
|
|
64
|
+
# Serializes the given Ruby object
|
|
65
|
+
#
|
|
66
|
+
# @abstract
|
|
67
|
+
# @param [Object] content The original Ruby object to serialize
|
|
68
|
+
# @return [Object] Should be in the native content type of the serializer
|
|
69
|
+
def perform_serialize(content); end
|
|
70
|
+
|
|
71
|
+
# Deserializes the given serialized content into the given Ruby type
|
|
72
|
+
#
|
|
73
|
+
# @abstract
|
|
74
|
+
# @param [Object] content Should be in the native content type of the serializer
|
|
75
|
+
# @param [Class] type The class type to be deserialized into
|
|
76
|
+
# @return [Object] The deserialized object
|
|
77
|
+
def perform_deserialize(content, type); end
|
|
78
|
+
|
|
79
|
+
# Returns the native content type that the serializer works with
|
|
80
|
+
#
|
|
81
|
+
# @abstract
|
|
82
|
+
# @return [Class]
|
|
83
|
+
def native_content_type; end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# Converts the given content from the given source type to the given target type
|
|
88
|
+
#
|
|
89
|
+
# @param [Object] original
|
|
90
|
+
# @param [Class] source_type
|
|
91
|
+
# @param [Class] target_type
|
|
92
|
+
# @return [Object]
|
|
93
|
+
def convert(original, source_type, target_type)
|
|
94
|
+
converter_factory.converter(source_type, target_type).convert_content(original)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module Serialization
|
|
3
|
+
# Implementation of a serializer that uses the built-in marshaling library
|
|
4
|
+
#
|
|
5
|
+
# Note that this serializer is not necessarily the fastest serializer available, nor is it
|
|
6
|
+
# flexible. Output is binary and difficult to modify, which means upcasting is not possible
|
|
7
|
+
# when using this serializer.
|
|
8
|
+
class MarshalSerializer < Serializer
|
|
9
|
+
# This serializer doesn't provide any configuration options
|
|
10
|
+
|
|
11
|
+
protected
|
|
12
|
+
|
|
13
|
+
# @param [Object] content
|
|
14
|
+
# @return [Object]
|
|
15
|
+
def perform_serialize(content)
|
|
16
|
+
Marshal.dump content
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @param [Object] content
|
|
20
|
+
# @param [Class] type
|
|
21
|
+
# @return [Object]
|
|
22
|
+
def perform_deserialize(content, type)
|
|
23
|
+
Marshal.load content
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Class]
|
|
27
|
+
def native_content_type
|
|
28
|
+
String
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'oj'
|
|
2
|
+
|
|
3
|
+
module Synapse
|
|
4
|
+
module Serialization
|
|
5
|
+
# Implementation of a serializer that uses the Optimized JSON (Oj) marshaling library
|
|
6
|
+
class OjSerializer < Serializer
|
|
7
|
+
# @return [Hash] Options that will be passed to the Oj dump method
|
|
8
|
+
attr_accessor :serialize_options
|
|
9
|
+
|
|
10
|
+
# @return [Hash] Options that will be passed to the Oj load method
|
|
11
|
+
attr_accessor :deserialize_options
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
# @param [Object] content
|
|
16
|
+
# @return [Object]
|
|
17
|
+
def perform_serialize(content)
|
|
18
|
+
Oj.dump content, @serialize_options
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param [Object] content
|
|
22
|
+
# @param [Class] type
|
|
23
|
+
# @return [Object]
|
|
24
|
+
def perform_deserialize(content, type)
|
|
25
|
+
Oj.load content, @deserialize_options
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Class]
|
|
29
|
+
def native_content_type
|
|
30
|
+
String
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'ox'
|
|
2
|
+
|
|
3
|
+
module Synapse
|
|
4
|
+
module Serialization
|
|
5
|
+
# Implementation of a serializer that uses the Optimized XML (Ox) marshaling library
|
|
6
|
+
class OxSerializer < Serializer
|
|
7
|
+
# @return [Hash] Options that will be passed to the Ox dump method
|
|
8
|
+
attr_accessor :serialize_options
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# @param [Object] content
|
|
13
|
+
# @return [Object]
|
|
14
|
+
def perform_serialize(content)
|
|
15
|
+
Ox.dump content, @serialize_options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param [Object] content
|
|
19
|
+
# @param [Class] type
|
|
20
|
+
# @return [Object]
|
|
21
|
+
def perform_deserialize(content, type)
|
|
22
|
+
Ox.parse_obj content
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Class]
|
|
26
|
+
def native_content_type
|
|
27
|
+
String
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module UnitOfWork
|
|
3
|
+
# Factory that creates and configures new unit of work instances
|
|
4
|
+
class UnitOfWorkFactory
|
|
5
|
+
# @return [TransactionManager]
|
|
6
|
+
attr_accessor :transaction_manager
|
|
7
|
+
|
|
8
|
+
# @param [UnitOfWorkProvider] provider
|
|
9
|
+
# @return [undefined]
|
|
10
|
+
def initialize(provider)
|
|
11
|
+
@provider = provider
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Creates and starts a unit of work
|
|
15
|
+
# @return [UnitOfWork]
|
|
16
|
+
def create
|
|
17
|
+
unit = UnitOfWork.new @provider
|
|
18
|
+
|
|
19
|
+
if @transaction_manager
|
|
20
|
+
unit.transaction_manager = @transaction_manager
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
unit.start
|
|
24
|
+
unit
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module UnitOfWork
|
|
3
|
+
# Listener that is registered to a unit of work and is notified of state changes
|
|
4
|
+
# @abstract
|
|
5
|
+
class UnitOfWorkListener
|
|
6
|
+
# Invoked when the unit of work has been started
|
|
7
|
+
#
|
|
8
|
+
# @param [UnitOfWork] unit
|
|
9
|
+
# @return [undefined]
|
|
10
|
+
def on_start(unit); end
|
|
11
|
+
|
|
12
|
+
# Invoked when an event is registered for publication when the unit of work is committed
|
|
13
|
+
#
|
|
14
|
+
# Listeners may alter event information. Note that the listener must ensure the functional
|
|
15
|
+
# meaning of the message does not change. Typically, this is done only by modifying the
|
|
16
|
+
# metadata of the message.
|
|
17
|
+
#
|
|
18
|
+
# @param [UnitOfWork] unit
|
|
19
|
+
# @param [EventMessage] event
|
|
20
|
+
# @return [EventMessage]
|
|
21
|
+
def on_event_registered(unit, event)
|
|
22
|
+
event
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Invoked before aggregates are committed, and before any events are published
|
|
26
|
+
#
|
|
27
|
+
# This phase can be used to do validation or any other activity that should be able to
|
|
28
|
+
# prevent event publication in certain circumstances.
|
|
29
|
+
#
|
|
30
|
+
# @param [UnitOfWork] unit
|
|
31
|
+
# @param [Array<AggregateRoot>] aggregates
|
|
32
|
+
# @param [Hash<EventBus, Array>] events
|
|
33
|
+
# @return [undefined]
|
|
34
|
+
def on_prepare_commit(unit, aggregates, events); end
|
|
35
|
+
|
|
36
|
+
# Invoked before the transaction bound to this unit of work is committed, but after all
|
|
37
|
+
# other commit activities (publication of events and storage of aggregates) are performed
|
|
38
|
+
#
|
|
39
|
+
# This gives a resource manager the opportunity to take actions that must be part of the
|
|
40
|
+
# same transaction. Note that this method is only invoked if the unit of work is bound
|
|
41
|
+
# to a transaction.
|
|
42
|
+
#
|
|
43
|
+
# @param [UnitOfWork] unit
|
|
44
|
+
# @param [Object] transaction
|
|
45
|
+
# @return [undefined]
|
|
46
|
+
def on_prepare_transaction_commit(unit, transaction); end
|
|
47
|
+
|
|
48
|
+
# Invoked when the unit of work is committed
|
|
49
|
+
#
|
|
50
|
+
# At this point, any registered aggregates have been stored and any registered events have
|
|
51
|
+
# been scheduled for publication. When processing of this method causes an exception, the
|
|
52
|
+
# unit of work may choose to rollback.
|
|
53
|
+
#
|
|
54
|
+
# @param [UnitOfWork] unit
|
|
55
|
+
# @return [undefined]
|
|
56
|
+
def after_commit(unit); end
|
|
57
|
+
|
|
58
|
+
# Invoked when the unit of work is rolled back
|
|
59
|
+
#
|
|
60
|
+
# Alternatively, the unit of work may choose to invoke this method when the commit of the
|
|
61
|
+
# unit of work failed as well.
|
|
62
|
+
#
|
|
63
|
+
# @param [UnitOfWork] unit
|
|
64
|
+
# @param [Error] cause
|
|
65
|
+
# @return [undefined]
|
|
66
|
+
def on_rollback(unit, cause = nil); end
|
|
67
|
+
|
|
68
|
+
# Invoked while a unit of work is being cleaned up
|
|
69
|
+
#
|
|
70
|
+
# This gives listeners the opportunity to release resources that might have been acquired
|
|
71
|
+
# during commit or rollback operations, such as locks. This method is always called after all
|
|
72
|
+
# listeners have been notified of a commit or rollback operation.
|
|
73
|
+
#
|
|
74
|
+
# @param [UnitOfWork] unit
|
|
75
|
+
# @return [undefined]
|
|
76
|
+
def on_cleanup(unit); end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Synapse
|
|
2
|
+
module UnitOfWork
|
|
3
|
+
# Represents a mechanism for notifying registered listeners in a specific order of precendence
|
|
4
|
+
#
|
|
5
|
+
# When {#on_start}, {#on_event_registered}, {#on_prepare_commit} and
|
|
6
|
+
# {#on_prepare_transaction_commit} are invoked, the listeners will be notified the order
|
|
7
|
+
# they were added to this colleciton. When {#after_commit}, {#on_rollback} and {#on_cleanup}
|
|
8
|
+
# are called, listeners will be notified in the reverse order they were added to this
|
|
9
|
+
# collection.
|
|
10
|
+
#
|
|
11
|
+
# This behavior is particularly useful for an auditing listener, which could log a commit
|
|
12
|
+
# before any listeners are allowed to do anything, and log that the commit is finished after
|
|
13
|
+
# all other listeners have finished.
|
|
14
|
+
class UnitOfWorkListenerCollection < UnitOfWorkListener
|
|
15
|
+
def initialize
|
|
16
|
+
@listeners = Array.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Pushes a unit of work listener onto the end of this collection
|
|
20
|
+
#
|
|
21
|
+
# @param [UnitOfWorkListener] listener
|
|
22
|
+
# @return [undefined]
|
|
23
|
+
def push(listener)
|
|
24
|
+
@listeners.push listener
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
alias << push
|
|
28
|
+
|
|
29
|
+
# @param [UnitOfWork] unit
|
|
30
|
+
# @return [undefined]
|
|
31
|
+
def on_start(unit)
|
|
32
|
+
@listeners.each do |listener|
|
|
33
|
+
listener.on_start unit
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param [UnitOfWork] unit
|
|
38
|
+
# @param [EventMessage] event
|
|
39
|
+
# @return [EventMessage]
|
|
40
|
+
def on_event_registered(unit, event)
|
|
41
|
+
@listeners.each do |listener|
|
|
42
|
+
event = listener.on_event_registered unit, event
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
event
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param [UnitOfWork] unit
|
|
49
|
+
# @param [Array<AggregateRoot>] aggregates
|
|
50
|
+
# @param [Hash<EventBus, Array>] events
|
|
51
|
+
# @return [undefined]
|
|
52
|
+
def on_prepare_commit(unit, aggregates, events)
|
|
53
|
+
@listeners.each do |listener|
|
|
54
|
+
listener.on_prepare_commit unit, aggregates, events
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @param [UnitOfWork] unit
|
|
59
|
+
# @param [Object] transaction
|
|
60
|
+
# @return [undefined]
|
|
61
|
+
def on_prepare_transaction_commit(unit, transaction)
|
|
62
|
+
@listeners.each do |listener|
|
|
63
|
+
listener.on_prepare_transaction_commit unit, transaction
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @param [UnitOfWork] unit
|
|
68
|
+
# @return [undefined]
|
|
69
|
+
def after_commit(unit)
|
|
70
|
+
@listeners.reverse_each do |listener|
|
|
71
|
+
listener.after_commit unit
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @param [UnitOfWork] unit
|
|
76
|
+
# @param [Error] cause
|
|
77
|
+
# @return [undefined]
|
|
78
|
+
def on_rollback(unit, cause = nil)
|
|
79
|
+
@listeners.reverse_each do |listener|
|
|
80
|
+
listener.on_rollback unit, cause
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @param [UnitOfWork] unit
|
|
85
|
+
# @return [undefined]
|
|
86
|
+
def on_cleanup(unit)
|
|
87
|
+
@listeners.reverse_each do |listener|
|
|
88
|
+
listener.on_cleanup unit
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|