operaton-bpm-client 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.
- checksums.yaml +7 -0
- data/README.md +134 -0
- data/lib/operaton/bpm/client/backoff/backoff_strategy.rb +20 -0
- data/lib/operaton/bpm/client/backoff/error_aware_backoff_strategy.rb +22 -0
- data/lib/operaton/bpm/client/backoff/exponential_backoff_strategy.rb +38 -0
- data/lib/operaton/bpm/client/backoff/exponential_error_backoff_strategy.rb +38 -0
- data/lib/operaton/bpm/client/exceptions.rb +74 -0
- data/lib/operaton/bpm/client/external_task_client.rb +20 -0
- data/lib/operaton/bpm/client/external_task_client_builder.rb +18 -0
- data/lib/operaton/bpm/client/impl/engine_client.rb +132 -0
- data/lib/operaton/bpm/client/impl/engine_client_exception.rb +25 -0
- data/lib/operaton/bpm/client/impl/engine_client_logger.rb +54 -0
- data/lib/operaton/bpm/client/impl/engine_rest_exception_dto.rb +28 -0
- data/lib/operaton/bpm/client/impl/external_task_client_builder_impl.rb +349 -0
- data/lib/operaton/bpm/client/impl/external_task_client_impl.rb +41 -0
- data/lib/operaton/bpm/client/impl/external_task_client_logger.rb +236 -0
- data/lib/operaton/bpm/client/impl/object_mapper.rb +44 -0
- data/lib/operaton/bpm/client/impl/permanent_url_resolver.rb +22 -0
- data/lib/operaton/bpm/client/impl/request_dto.rb +24 -0
- data/lib/operaton/bpm/client/impl/request_executor.rb +143 -0
- data/lib/operaton/bpm/client/interceptor/auth/basic_auth_provider.rb +42 -0
- data/lib/operaton/bpm/client/interceptor/client_request_context.rb +16 -0
- data/lib/operaton/bpm/client/interceptor/client_request_interceptor.rb +18 -0
- data/lib/operaton/bpm/client/interceptor/impl/client_request_context_impl.rb +28 -0
- data/lib/operaton/bpm/client/interceptor/impl/request_interceptor_handler.rb +43 -0
- data/lib/operaton/bpm/client/spi/data_format.rb +32 -0
- data/lib/operaton/bpm/client/spi/data_format_configurator.rb +31 -0
- data/lib/operaton/bpm/client/spi/data_format_provider.rb +31 -0
- data/lib/operaton/bpm/client/task/external_task.rb +22 -0
- data/lib/operaton/bpm/client/task/external_task_handler.rb +28 -0
- data/lib/operaton/bpm/client/task/external_task_service.rb +18 -0
- data/lib/operaton/bpm/client/task/impl/dto/bpmn_error_request_dto.rb +35 -0
- data/lib/operaton/bpm/client/task/impl/dto/complete_request_dto.rb +33 -0
- data/lib/operaton/bpm/client/task/impl/dto/extend_lock_request_dto.rb +29 -0
- data/lib/operaton/bpm/client/task/impl/dto/failure_request_dto.rb +43 -0
- data/lib/operaton/bpm/client/task/impl/dto/lock_request_dto.rb +29 -0
- data/lib/operaton/bpm/client/task/impl/dto/set_variables_request_dto.rb +29 -0
- data/lib/operaton/bpm/client/task/impl/external_task_impl.rb +128 -0
- data/lib/operaton/bpm/client/task/impl/external_task_service_impl.rb +90 -0
- data/lib/operaton/bpm/client/task/ordering_config.rb +78 -0
- data/lib/operaton/bpm/client/task/sorting_dto.rb +29 -0
- data/lib/operaton/bpm/client/topic/impl/dto/fetch_and_lock_request_dto.rb +47 -0
- data/lib/operaton/bpm/client/topic/impl/dto/fetch_and_lock_response_dto.rb +32 -0
- data/lib/operaton/bpm/client/topic/impl/dto/topic_request_dto.rb +70 -0
- data/lib/operaton/bpm/client/topic/impl/topic_subscription_builder_impl.rb +164 -0
- data/lib/operaton/bpm/client/topic/impl/topic_subscription_impl.rb +76 -0
- data/lib/operaton/bpm/client/topic/impl/topic_subscription_manager.rb +222 -0
- data/lib/operaton/bpm/client/topic/impl/topic_subscription_manager_logger.rb +52 -0
- data/lib/operaton/bpm/client/topic/topic_subscription.rb +20 -0
- data/lib/operaton/bpm/client/topic/topic_subscription_builder.rb +22 -0
- data/lib/operaton/bpm/client/url_resolver.rb +15 -0
- data/lib/operaton/bpm/client/variable/client_values.rb +33 -0
- data/lib/operaton/bpm/client/variable/impl/abstract_typed_value_mapper.rb +59 -0
- data/lib/operaton/bpm/client/variable/impl/default_value_mappers.rb +71 -0
- data/lib/operaton/bpm/client/variable/impl/format/json/json_data_format.rb +82 -0
- data/lib/operaton/bpm/client/variable/impl/format/json/json_data_format_provider.rb +34 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/boolean_value_mapper.rb +35 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/byte_array_value_mapper.rb +53 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/date_value_mapper.rb +61 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/double_value_mapper.rb +36 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/file_value_mapper.rb +73 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/integer_value_mapper.rb +36 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/json_value_mapper.rb +35 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/long_value_mapper.rb +36 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/null_value_mapper.rb +45 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/number_value_mapper.rb +25 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/object_value_mapper.rb +151 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/primitive_value_mapper.rb +44 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/short_value_mapper.rb +36 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/string_value_mapper.rb +35 -0
- data/lib/operaton/bpm/client/variable/impl/mapper/xml_value_mapper.rb +35 -0
- data/lib/operaton/bpm/client/variable/impl/type/json_type_impl.rb +24 -0
- data/lib/operaton/bpm/client/variable/impl/type/xml_type_impl.rb +24 -0
- data/lib/operaton/bpm/client/variable/impl/typed_value_field.rb +36 -0
- data/lib/operaton/bpm/client/variable/impl/typed_values.rb +100 -0
- data/lib/operaton/bpm/client/variable/impl/value/deferred_file_value_impl.rb +57 -0
- data/lib/operaton/bpm/client/variable/impl/value/json_value_impl.rb +26 -0
- data/lib/operaton/bpm/client/variable/impl/value/xml_value_impl.rb +26 -0
- data/lib/operaton/bpm/client/variable/impl/value_mapper.rb +42 -0
- data/lib/operaton/bpm/client/variable/impl/value_mappers.rb +26 -0
- data/lib/operaton/bpm/client/variable/impl/variable_value.rb +55 -0
- data/lib/operaton/bpm/client/variable/value/deferred_file_value.rb +19 -0
- data/lib/operaton/bpm/client/variable/value/json_value.rb +16 -0
- data/lib/operaton/bpm/client/variable/value/xml_value.rb +16 -0
- data/lib/operaton/bpm/client/version.rb +9 -0
- data/lib/operaton/bpm/client.rb +121 -0
- data/lib/operaton/bpm/engine/variable/typed_value.rb +153 -0
- data/lib/operaton/bpm/engine/variable/value_type.rb +126 -0
- data/lib/operaton/bpm/engine/variable/variable_map.rb +72 -0
- data/lib/operaton/bpm/engine/variable/variables.rb +197 -0
- data/lib/operaton-bpm-client.rb +3 -0
- metadata +188 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../topic_subscription"
|
|
4
|
+
|
|
5
|
+
module Operaton
|
|
6
|
+
module Bpm
|
|
7
|
+
module Client
|
|
8
|
+
module Topic
|
|
9
|
+
module Impl
|
|
10
|
+
# Mirrors org.operaton.bpm.client.topic.impl.TopicSubscriptionImpl
|
|
11
|
+
class TopicSubscriptionImpl
|
|
12
|
+
include TopicSubscription
|
|
13
|
+
|
|
14
|
+
attr_reader :topic_name, :lock_duration, :external_task_handler, :variable_names, :business_key
|
|
15
|
+
attr_accessor :process_definition_id, :process_definition_id_in,
|
|
16
|
+
:process_definition_key, :process_definition_key_in,
|
|
17
|
+
:process_definition_version_tag, :tenant_id_in
|
|
18
|
+
|
|
19
|
+
def initialize(topic_name, lock_duration, external_task_handler,
|
|
20
|
+
topic_subscription_manager, variable_names, business_key)
|
|
21
|
+
@topic_name = topic_name
|
|
22
|
+
@lock_duration = lock_duration
|
|
23
|
+
@external_task_handler = external_task_handler
|
|
24
|
+
@topic_subscription_manager = topic_subscription_manager
|
|
25
|
+
@variable_names = variable_names
|
|
26
|
+
@business_key = business_key
|
|
27
|
+
@local_variables = false
|
|
28
|
+
@without_tenant_id = false
|
|
29
|
+
@include_extension_properties = false
|
|
30
|
+
@process_variables = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def close
|
|
34
|
+
@topic_subscription_manager.unsubscribe(self)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def local_variables?
|
|
38
|
+
@local_variables
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
attr_writer :local_variables
|
|
42
|
+
|
|
43
|
+
attr_reader :process_variables
|
|
44
|
+
|
|
45
|
+
def process_variables=(process_variables)
|
|
46
|
+
@process_variables ||= {}
|
|
47
|
+
@process_variables.merge!(process_variables)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def without_tenant_id?
|
|
51
|
+
@without_tenant_id
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
attr_writer :without_tenant_id
|
|
55
|
+
|
|
56
|
+
def include_extension_properties?
|
|
57
|
+
@include_extension_properties
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
attr_writer :include_extension_properties
|
|
61
|
+
|
|
62
|
+
# Java equality is based on class and topic name only.
|
|
63
|
+
def ==(other)
|
|
64
|
+
other.instance_of?(self.class) && topic_name == other.topic_name
|
|
65
|
+
end
|
|
66
|
+
alias eql? ==
|
|
67
|
+
|
|
68
|
+
def hash
|
|
69
|
+
[self.class, topic_name].hash
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "topic_subscription_manager_logger"
|
|
4
|
+
require_relative "dto/topic_request_dto"
|
|
5
|
+
require_relative "dto/fetch_and_lock_response_dto"
|
|
6
|
+
require_relative "../../task/impl/external_task_service_impl"
|
|
7
|
+
require_relative "../../task/external_task_handler"
|
|
8
|
+
require_relative "../../backoff/error_aware_backoff_strategy"
|
|
9
|
+
require_relative "../../impl/engine_client_exception"
|
|
10
|
+
require_relative "../../impl/external_task_client_logger"
|
|
11
|
+
require_relative "../../exceptions"
|
|
12
|
+
|
|
13
|
+
module Operaton
|
|
14
|
+
module Bpm
|
|
15
|
+
module Client
|
|
16
|
+
module Topic
|
|
17
|
+
module Impl
|
|
18
|
+
# Mirrors org.operaton.bpm.client.topic.impl.TopicSubscriptionManager.
|
|
19
|
+
# Runs the fetch-and-lock loop on a dedicated thread.
|
|
20
|
+
class TopicSubscriptionManager
|
|
21
|
+
attr_reader :engine_client
|
|
22
|
+
|
|
23
|
+
def initialize(engine_client, typed_values, client_lock_duration)
|
|
24
|
+
@engine_client = engine_client
|
|
25
|
+
@subscriptions = []
|
|
26
|
+
@subscriptions_mutex = Mutex.new
|
|
27
|
+
@task_topic_requests = []
|
|
28
|
+
@external_task_handlers = {}
|
|
29
|
+
@client_lock_duration = client_lock_duration
|
|
30
|
+
@typed_values = typed_values
|
|
31
|
+
@external_task_service = Task::Impl::ExternalTaskServiceImpl.new(engine_client)
|
|
32
|
+
@is_backoff_strategy_disabled = false
|
|
33
|
+
@backoff_strategy = nil
|
|
34
|
+
|
|
35
|
+
@is_running = false
|
|
36
|
+
@state_mutex = Mutex.new
|
|
37
|
+
@acquisition_monitor = Mutex.new
|
|
38
|
+
@is_waiting = ConditionVariable.new
|
|
39
|
+
@resume_signaled = false
|
|
40
|
+
@thread = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def run
|
|
44
|
+
while running?
|
|
45
|
+
begin
|
|
46
|
+
acquire
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
logger.exception_while_acquiring_tasks(e)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def stop
|
|
54
|
+
@state_mutex.synchronize do
|
|
55
|
+
return unless @is_running
|
|
56
|
+
|
|
57
|
+
@is_running = false
|
|
58
|
+
end
|
|
59
|
+
resume
|
|
60
|
+
begin
|
|
61
|
+
@thread&.join
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
logger.exception_while_shutting_down(e)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def start
|
|
68
|
+
@state_mutex.synchronize do
|
|
69
|
+
return if @is_running
|
|
70
|
+
|
|
71
|
+
@is_running = true
|
|
72
|
+
@thread = Thread.new { run }
|
|
73
|
+
@thread.name = "TopicSubscriptionManager"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def subscribe(subscription)
|
|
78
|
+
@subscriptions_mutex.synchronize do
|
|
79
|
+
if @subscriptions.include?(subscription)
|
|
80
|
+
raise logger.topic_name_already_subscribed_exception(subscription.topic_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@subscriptions << subscription
|
|
84
|
+
end
|
|
85
|
+
resume
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def unsubscribe(subscription)
|
|
89
|
+
@subscriptions_mutex.synchronize { @subscriptions.delete(subscription) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def subscriptions
|
|
93
|
+
@subscriptions_mutex.synchronize { @subscriptions.dup }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def running?
|
|
97
|
+
@state_mutex.synchronize { @is_running }
|
|
98
|
+
end
|
|
99
|
+
alias is_running? running?
|
|
100
|
+
|
|
101
|
+
def backoff_strategy=(backoff_strategy)
|
|
102
|
+
@backoff_strategy = backoff_strategy
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def disable_backoff_strategy
|
|
106
|
+
@is_backoff_strategy_disabled = true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
protected
|
|
110
|
+
|
|
111
|
+
def acquire
|
|
112
|
+
@task_topic_requests.clear
|
|
113
|
+
@external_task_handlers.clear
|
|
114
|
+
subscriptions.each { |subscription| prepare_acquisition(subscription) }
|
|
115
|
+
|
|
116
|
+
return if @task_topic_requests.empty?
|
|
117
|
+
|
|
118
|
+
fetch_and_lock_response = fetch_and_lock(@task_topic_requests)
|
|
119
|
+
|
|
120
|
+
fetch_and_lock_response.external_tasks.each do |external_task|
|
|
121
|
+
topic_name = external_task.topic_name
|
|
122
|
+
task_handler = @external_task_handlers[topic_name]
|
|
123
|
+
|
|
124
|
+
if task_handler
|
|
125
|
+
handle_external_task(external_task, task_handler)
|
|
126
|
+
else
|
|
127
|
+
logger.task_handler_is_null(topic_name)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
run_backoff_strategy(fetch_and_lock_response) unless @is_backoff_strategy_disabled
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def prepare_acquisition(subscription)
|
|
135
|
+
@task_topic_requests << Dto::TopicRequestDto.from_topic_subscription(subscription, @client_lock_duration)
|
|
136
|
+
@external_task_handlers[subscription.topic_name] = subscription.external_task_handler
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def fetch_and_lock(task_topic_requests)
|
|
140
|
+
logger.fetch_and_lock(task_topic_requests)
|
|
141
|
+
external_tasks = @engine_client.fetch_and_lock(task_topic_requests)
|
|
142
|
+
Dto::FetchAndLockResponseDto.new(external_tasks)
|
|
143
|
+
rescue Client::Impl::EngineClientException => e
|
|
144
|
+
logger.exception_while_performing_fetch_and_lock(e)
|
|
145
|
+
Dto::FetchAndLockResponseDto.new(
|
|
146
|
+
client_logger.handled_engine_client_exception("fetching and locking task", e)
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def handle_external_task(external_task, task_handler)
|
|
151
|
+
variables = external_task.variables
|
|
152
|
+
external_task.received_variable_map = @typed_values.wrap_variables(external_task, variables)
|
|
153
|
+
|
|
154
|
+
begin
|
|
155
|
+
Task::ExternalTaskHandler.invoke(task_handler, external_task, @external_task_service)
|
|
156
|
+
rescue ExternalTaskClientException => e
|
|
157
|
+
logger.exception_on_external_task_service_method_invocation(external_task.topic_name, e)
|
|
158
|
+
rescue StandardError => e
|
|
159
|
+
logger.exception_while_executing_external_task_handler(external_task.topic_name, e)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def run_backoff_strategy(fetch_and_lock_response)
|
|
164
|
+
external_tasks = fetch_and_lock_response.external_tasks
|
|
165
|
+
|
|
166
|
+
if @backoff_strategy.is_a?(Backoff::ErrorAwareBackoffStrategy) ||
|
|
167
|
+
@backoff_strategy.method(:reconfigure).arity != 1
|
|
168
|
+
@backoff_strategy.reconfigure(external_tasks, fetch_and_lock_response.error)
|
|
169
|
+
else
|
|
170
|
+
@backoff_strategy.reconfigure(external_tasks)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
suspend(@backoff_strategy.calculate_backoff_time)
|
|
174
|
+
rescue StandardError => e
|
|
175
|
+
logger.exception_while_executing_backoff_strategy_method(e)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def suspend(wait_time_ms)
|
|
179
|
+
return unless wait_time_ms.positive? && running?
|
|
180
|
+
|
|
181
|
+
@acquisition_monitor.synchronize do
|
|
182
|
+
end_time = monotonic_ms + wait_time_ms
|
|
183
|
+
remaining = wait_time_ms
|
|
184
|
+
|
|
185
|
+
while remaining.positive? && running?
|
|
186
|
+
break if @resume_signaled
|
|
187
|
+
|
|
188
|
+
@is_waiting.wait(@acquisition_monitor, remaining / 1000.0)
|
|
189
|
+
break if @resume_signaled
|
|
190
|
+
|
|
191
|
+
remaining = end_time - monotonic_ms
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
logger.timeout(wait_time_ms) if remaining <= 0 && running? && !@resume_signaled
|
|
195
|
+
@resume_signaled = false
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def resume
|
|
200
|
+
@acquisition_monitor.synchronize do
|
|
201
|
+
@resume_signaled = true
|
|
202
|
+
@is_waiting.signal
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def monotonic_ms
|
|
207
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def logger
|
|
211
|
+
Client::Impl::ExternalTaskClientLogger.topic_subscription_manager_logger
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def client_logger
|
|
215
|
+
Client::Impl::ExternalTaskClientLogger.client_logger
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../impl/external_task_client_logger"
|
|
4
|
+
|
|
5
|
+
module Operaton
|
|
6
|
+
module Bpm
|
|
7
|
+
module Client
|
|
8
|
+
module Topic
|
|
9
|
+
module Impl
|
|
10
|
+
# Mirrors org.operaton.bpm.client.topic.impl.TopicSubscriptionManagerLogger
|
|
11
|
+
class TopicSubscriptionManagerLogger < Client::Impl::ExternalTaskClientLogger
|
|
12
|
+
def exception_while_performing_fetch_and_lock(error)
|
|
13
|
+
log_error("001", "Exception while fetching and locking task.", error)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def exception_while_executing_external_task_handler(topic_name, error)
|
|
17
|
+
log_error("002", "Exception while executing external task handler '#{topic_name}'.", error)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def exception_while_shutting_down(error)
|
|
21
|
+
log_error("003", "Exception while shutting down:", error)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def exception_on_external_task_service_method_invocation(topic_name, error)
|
|
25
|
+
log_error("004", "Exception on external task service method invocation for topic '#{topic_name}':", error)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def exception_while_executing_backoff_strategy_method(error)
|
|
29
|
+
log_error("005", "Exception while executing back off strategy method.", error)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def exception_while_acquiring_tasks(error)
|
|
33
|
+
log_error("006", "Exception while acquiring tasks.", error)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def task_handler_is_null(topic_name)
|
|
37
|
+
log_error("007", "Task handler is null for topic '#{topic_name}'.")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def fetch_and_lock(subscriptions)
|
|
41
|
+
log_debug("008", "Fetch and lock new external tasks for #{subscriptions.size} topics")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def timeout(wait_time)
|
|
45
|
+
log_debug("009", "Timed out after #{wait_time} ms without a signal.")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Operaton
|
|
4
|
+
module Bpm
|
|
5
|
+
module Client
|
|
6
|
+
module Topic
|
|
7
|
+
# Mirrors org.operaton.bpm.client.topic.TopicSubscription. Documents
|
|
8
|
+
# the contract implemented by Topic::Impl::TopicSubscriptionImpl.
|
|
9
|
+
module TopicSubscription
|
|
10
|
+
INTERFACE_METHODS = %i[
|
|
11
|
+
close topic_name lock_duration external_task_handler variable_names
|
|
12
|
+
local_variables? business_key process_definition_id process_definition_id_in
|
|
13
|
+
process_definition_key process_definition_key_in process_definition_version_tag
|
|
14
|
+
process_variables without_tenant_id? tenant_id_in include_extension_properties?
|
|
15
|
+
].freeze
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Operaton
|
|
4
|
+
module Bpm
|
|
5
|
+
module Client
|
|
6
|
+
module Topic
|
|
7
|
+
# Mirrors org.operaton.bpm.client.topic.TopicSubscriptionBuilder.
|
|
8
|
+
# Documents the fluent contract implemented by
|
|
9
|
+
# Topic::Impl::TopicSubscriptionBuilderImpl.
|
|
10
|
+
module TopicSubscriptionBuilder
|
|
11
|
+
INTERFACE_METHODS = %i[
|
|
12
|
+
lock_duration handler variables local_variables business_key
|
|
13
|
+
process_definition_id process_definition_id_in process_definition_key
|
|
14
|
+
process_definition_key_in process_definition_version_tag
|
|
15
|
+
process_variables_equals_in process_variable_equals without_tenant_id
|
|
16
|
+
tenant_id_in include_extension_properties open
|
|
17
|
+
].freeze
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Operaton
|
|
4
|
+
module Bpm
|
|
5
|
+
module Client
|
|
6
|
+
# Mirrors org.operaton.bpm.client.UrlResolver. Any object responding to
|
|
7
|
+
# #base_url can act as a URL resolver.
|
|
8
|
+
module UrlResolver
|
|
9
|
+
def base_url
|
|
10
|
+
raise NotImplementedError, "#{self.class} must implement #base_url"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../engine/variable/variables"
|
|
4
|
+
require_relative "impl/type/json_type_impl"
|
|
5
|
+
require_relative "impl/type/xml_type_impl"
|
|
6
|
+
|
|
7
|
+
module Operaton
|
|
8
|
+
module Bpm
|
|
9
|
+
module Client
|
|
10
|
+
module Variable
|
|
11
|
+
# Mirrors org.operaton.bpm.client.variable.ClientValues, which extends
|
|
12
|
+
# the engine Variables factory with json and xml typed values.
|
|
13
|
+
module ClientValues
|
|
14
|
+
extend Engine::Variable::VariablesFactory
|
|
15
|
+
|
|
16
|
+
JSON = Impl::Type::JsonTypeImpl.new
|
|
17
|
+
XML = Impl::Type::XmlTypeImpl.new
|
|
18
|
+
|
|
19
|
+
def self.json_value(json_value, is_transient = false)
|
|
20
|
+
Impl::Value::JsonValueImpl.new(json_value, is_transient)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.xml_value(xml_value, is_transient = false)
|
|
24
|
+
Impl::Value::XmlValueImpl.new(xml_value, is_transient)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
require_relative "impl/value/json_value_impl"
|
|
33
|
+
require_relative "impl/value/xml_value_impl"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "value_mapper"
|
|
4
|
+
|
|
5
|
+
module Operaton
|
|
6
|
+
module Bpm
|
|
7
|
+
module Client
|
|
8
|
+
module Variable
|
|
9
|
+
module Impl
|
|
10
|
+
# Mirrors org.operaton.bpm.client.variable.impl.AbstractTypedValueMapper
|
|
11
|
+
class AbstractTypedValueMapper
|
|
12
|
+
include ValueMapper
|
|
13
|
+
|
|
14
|
+
attr_reader :value_type
|
|
15
|
+
|
|
16
|
+
def initialize(value_type)
|
|
17
|
+
@value_type = value_type
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def type
|
|
21
|
+
value_type
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def serialization_dataformat
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def can_handle_typed_value(typed_value)
|
|
29
|
+
type = typed_value.type
|
|
30
|
+
(type.nil? || type_matches?(type)) && can_write_value(typed_value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def can_handle_typed_value_field(typed_value_field)
|
|
34
|
+
type = typed_value_field.type
|
|
35
|
+
!type.nil? && type == value_type.name && can_read_value(typed_value_field)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
|
|
40
|
+
# In Java this is valueType.getClass().isAssignableFrom(type.getClass()),
|
|
41
|
+
# where every value type has its own class. Ruby value types are
|
|
42
|
+
# singleton instances, so identity comparison is the equivalent.
|
|
43
|
+
def type_matches?(type)
|
|
44
|
+
type.equal?(value_type)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def can_write_value(typed_value)
|
|
48
|
+
raise NotImplementedError
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def can_read_value(typed_value_field)
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "value_mappers"
|
|
4
|
+
require_relative "../../impl/external_task_client_logger"
|
|
5
|
+
|
|
6
|
+
module Operaton
|
|
7
|
+
module Bpm
|
|
8
|
+
module Client
|
|
9
|
+
module Variable
|
|
10
|
+
module Impl
|
|
11
|
+
# Mirrors org.operaton.bpm.client.variable.impl.DefaultValueMappers
|
|
12
|
+
class DefaultValueMappers
|
|
13
|
+
include ValueMappers
|
|
14
|
+
|
|
15
|
+
def initialize(default_serialization_format)
|
|
16
|
+
@serializer_list = []
|
|
17
|
+
@default_serialization_format = default_serialization_format
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def find_mapper_for_typed_value(typed_value)
|
|
21
|
+
type = typed_value.type
|
|
22
|
+
raise logger.value_mapper_exception_while_serializing_abstract_value(type.name) if type&.abstract?
|
|
23
|
+
|
|
24
|
+
matched_serializers = []
|
|
25
|
+
@serializer_list.each do |serializer|
|
|
26
|
+
next unless serializer.can_handle_typed_value(typed_value)
|
|
27
|
+
|
|
28
|
+
matched_serializers << serializer
|
|
29
|
+
break if serializer.type.primitive_value_type?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
case matched_serializers.size
|
|
33
|
+
when 1
|
|
34
|
+
matched_serializers.first
|
|
35
|
+
when 0
|
|
36
|
+
raise logger.value_mapper_exception_due_to_serializer_not_found_for_typed_value(typed_value)
|
|
37
|
+
else
|
|
38
|
+
# ambiguous match, use default serializer
|
|
39
|
+
matched_serializers.find { |s| s.serialization_dataformat == @default_serialization_format } ||
|
|
40
|
+
matched_serializers.first
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def find_mapper_for_typed_value_field(typed_value_field)
|
|
45
|
+
matched_serializer = @serializer_list.find { |s| s.can_handle_typed_value_field(typed_value_field) }
|
|
46
|
+
|
|
47
|
+
if matched_serializer.nil?
|
|
48
|
+
raise logger.value_mapper_exception_due_to_serializer_not_found_for_typed_value_field(
|
|
49
|
+
typed_value_field.value
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
matched_serializer
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_mapper(serializer)
|
|
57
|
+
@serializer_list << serializer
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
|
|
63
|
+
def logger
|
|
64
|
+
Client::Impl::ExternalTaskClientLogger.client_logger
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require_relative "../../../../spi/data_format"
|
|
5
|
+
require_relative "../../../../exceptions"
|
|
6
|
+
|
|
7
|
+
module Operaton
|
|
8
|
+
module Bpm
|
|
9
|
+
module Client
|
|
10
|
+
module Variable
|
|
11
|
+
module Impl
|
|
12
|
+
module Format
|
|
13
|
+
module Json
|
|
14
|
+
# Stands in for org.operaton.bpm.client.variable.impl.format.json
|
|
15
|
+
# .JacksonJsonDataFormat, using Ruby's JSON library.
|
|
16
|
+
class JsonDataFormat
|
|
17
|
+
include Spi::DataFormat
|
|
18
|
+
|
|
19
|
+
NAME = "application/json"
|
|
20
|
+
|
|
21
|
+
def name
|
|
22
|
+
NAME
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def can_map(value)
|
|
26
|
+
json_native?(value) || value.respond_to?(:as_json) || value.respond_to?(:to_h)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write_value(value)
|
|
30
|
+
JSON.generate(jsonify(value))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# type_identifier is the stored objectTypeName; JSON deserialization
|
|
34
|
+
# in Ruby is generic (hashes/arrays), so it is not used for
|
|
35
|
+
# reconstruction the way Jackson uses Java type names.
|
|
36
|
+
def read_value(value, _type_identifier = nil)
|
|
37
|
+
JSON.parse(value)
|
|
38
|
+
rescue JSON::ParserError => e
|
|
39
|
+
raise DataFormatException.new("Unable to parse JSON value", e)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def canonical_type_name(value)
|
|
43
|
+
value.class.name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
protected
|
|
47
|
+
|
|
48
|
+
def jsonify(value)
|
|
49
|
+
case value
|
|
50
|
+
when Hash
|
|
51
|
+
value.transform_values { |v| jsonify(v) }
|
|
52
|
+
when Array
|
|
53
|
+
value.map { |v| jsonify(v) }
|
|
54
|
+
when String, Numeric, TrueClass, FalseClass, NilClass
|
|
55
|
+
value
|
|
56
|
+
else
|
|
57
|
+
if value.respond_to?(:as_json)
|
|
58
|
+
value.as_json
|
|
59
|
+
elsif value.respond_to?(:to_h)
|
|
60
|
+
jsonify(value.to_h)
|
|
61
|
+
else
|
|
62
|
+
value
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def json_native?(value)
|
|
68
|
+
case value
|
|
69
|
+
when Hash, Array, String, Numeric, TrueClass, FalseClass, NilClass
|
|
70
|
+
true
|
|
71
|
+
else
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../../spi/data_format_provider"
|
|
4
|
+
require_relative "json_data_format"
|
|
5
|
+
|
|
6
|
+
module Operaton
|
|
7
|
+
module Bpm
|
|
8
|
+
module Client
|
|
9
|
+
module Variable
|
|
10
|
+
module Impl
|
|
11
|
+
module Format
|
|
12
|
+
module Json
|
|
13
|
+
# Stands in for JacksonJsonDataFormatProvider; registered with the
|
|
14
|
+
# provider registry when the gem is loaded.
|
|
15
|
+
class JsonDataFormatProvider
|
|
16
|
+
include Spi::DataFormatProvider
|
|
17
|
+
|
|
18
|
+
def data_format_name
|
|
19
|
+
JsonDataFormat::NAME
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_instance
|
|
23
|
+
JsonDataFormat.new
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Spi::DataFormatProvider.register(JsonDataFormatProvider.new)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|