JIRA: https://jira.spring.io/browse/INT-4501
The call to the `IntegrationFlowBeanPostProcessor#setBeanFactory`
happens during BPP creation.
The introduced call to `beanFactory#getBean` triggers a lot of bean
creations.
For those beans not all `BPP`s are applied.
* Obtain a `flowContext` bean in lazy-load manner
**Cherry-pick to 5.0.x**
Since `IntegrationComponentSpec` is a `FactoryBean`, we need to care
about `Aware` and `init` & `destroy` hooks our selves or delegate
them through the `FactoryBean` wrapper
* Implement `InitializingBean` and `DisposableBean` on the
`IntegrationComponentSpec`
* Call the `Aware` hooks from the `IntegrationFlowBeanPostProcessor`
**Cherry-pick to 5.0.x**
JIRA: https://jira.spring.io/browse/INT-4498
* Use `FileCopyUtils` instead of `StreamUtils` in test-cases when we deal
with `InputStream` s and files resources.
* Fix reflection-based tests with AOP to use an `ArrayList` access
instead of `LinkedList` since an optimization in SF:
6d6aa72e8f
**Cherry-pick to 5.0.x and 4.3.x**
JIRA: https://jira.spring.io/browse/INT-4488
Since `PublisherAnnotationBeanPostProcessor` is quite expensive
(1.5x the CPU used by `MessagingAnnotationPostProcessor` in a simple
application)
* So not register a `PublisherAnnotationBeanPostProcessor` by default.
The `@EnablePublisher` has to be presented on the `@Configuration`
to allow the `@Publisher` AOP
* Change the `<int:annotation-config>` to require a new
`<int:enable-publisher>` sub-element for similar purpose - do not
register `PublisherAnnotationBeanPostProcessor` by default
JIRA: https://jira.spring.io/browse/INT-4452
This is pretty typical in practice to get a `groupTimeout` to be
evaluated to a negative value: some business decisions, sensitive
calculations and so on.
* Treat any non-positive `groupTimeout` as a signal to expire group
immediately without scheduling.
Only `null` is considered as a signal do nothing for the current message
* Polishing for some tests for better performance - saves some execution
time
JIRA: https://jira.spring.io/browse/INT-4489
Make `MessageHistoryConfigurer` as a `BeanPostProcessor` and apply
tracking logic to processed beans if it is already started.
**Cherry-pick to 5.0.x**
JIRA: https://jira.spring.io/browse/INT-4487
Currently the `AbstractReplyProducingMessageHandler` applies advices
only in the `afterPropertiesSet()` phase.
When we use bean references for `MessageHandler`s in Java DSL, the
`.advice()` provided in the flow definition is not applied to the
`AbstractReplyProducingMessageHandler`.
* For consistency with the endpoint configured by the DSL definition,
override and reconfigure advices in the `AbstractReplyProducingMessageHandler`
bean reference during DSL parsing and processing.
Fix `TwitterSearchOutboundGatewayParserTests` for the proper assert
* Destroy RmiInboundGateway.RmiServiceExporter
The internal instance `RmiServiceExporter` of the `RmiInboundGateway`
has to be destroyed together with the outer instance to unbind `service`
from the RMI registry
* Perform some polishing for the `RmiInboundGateway` and optimize
a `AbstractInboundGatewayParser` for late channels binding
* * Polishing some tests
* Expose getters for channels on the `MessagingGatewaySupport`
* Fix RMI tests to use random port
JIRA: https://jira.spring.io/browse/INT-4485
The `IntegrationFlowBeanPostProcessor` performs extra bean registration
for the `IntegrationComponentSpec.get()` result.
Essentially it is going to be the same object in the end, but during
bean registration phase we end up with names conflict.
* Remove an explicit `registerComponent()` for the
`IntegrationComponentSpec.get()`
* Modify `CorrelationHandlerTests` for all possible usage for the
`MessageChannelSpec`, which is essentially a `FactoryBean`
**Cherry-pick to 5.0.x**
JIRA: https://jira.spring.io/browse/INT-4486
The `SmartLifecycle.stop(Runnable callback)` must always call the
`callback` in the end independently of the internal state
* Revise all the `SmartLifecycle` implementations for the proper
`callback` handling
**Cherry-pick to 5.0.x and 4.3.x**
JIRA: https://jira.spring.io/browse/INT-4482
The outer try/catch sends an `ErrorMessage` for all exceptions; it should
only do so for `MessageConversionException`. Integration flow exceptions
will have been already handled by `MessageProducerSupport`.
Also, populate the raw message header consistently - previously it only
was populated for flow exceptions. Although the LEFE contains the raw
message, it should be in the `ErrorMessage` header for consistency.
**cherry-pick to 5.0.x, 4.3.x**
* Polishing - PR Comments
https://build.spring.io/browse/INT-MASTER-1058/
When we destroy manually registered `IntegrationFlow`, we need to
count with sub-flows and iterate all the dependant beans recursively
for full flow removal
**Cherry-pick to 5.0.x**
JIRA: https://jira.spring.io/browse/INT-4476
When mapping outbound headers, if the `AmqpHeaders` `ID` and `Timestamp` headers
are not present, fall back to mapping the `MessageHeaders` variants (if present).
Also fix some PDF overflows.
JIRA: https://jira.spring.io/browse/INT-4474
* Populate proper `Integer.MIN_VALUE` phase for non-`PollingConsumer`s
in the `ConsumerEndpointFactoryBean`
**Cherry-pick to 5.0.x and 4.3.x**
* INT-4471: PubSubChannel: Add errorHandler warn
JIRA: https://jira.spring.io/browse/INT-4471
* When an `Executor` is not provided, log warn that the provided
`ErrorHandler` is ignored.
**Cherry-pick to 5.0.x and 4.3.x**
* * Polish warn message
JIRA: https://jira.spring.io/browse/INT-4478
When we use a `GenericHandler` and an incoming payload is a `Map`, we
copy it into both arguments into the `Object` for the payload
and `Map` for the headers.
This way we lose headers in the target lambda
* Check a size of arguments on the target lambda and don't set a
payload into the `Map` argument if we have more than 1 arguments
**Cherry-pick to 5.0.x**
JIRA: https://jira.spring.io/browse/INT-4477
When running multiple roles, it is useful to be able to determine the
role for a particular context, e.g. in an event.
* Docs
**cherry-pick to 5.0.x**
* Fix LockRegLeaderIn for interrupted Thread.sleep
https://build.spring.io/browse/INT-FATS5IC-517
If current thread is interrupted, the `Thread.sleep()` interrupts
immediately.
In the catch block of the main loop in the `LockRegistryLeaderInitiator`
we have such a dangerous `sleep()` and don't restart election in this
candidate any more
* Move `Thread.sleep()` to else after checking the current thread for
interrupted state
* Remove `LongRunningIntegrationTest` rule from the
`RedisLockRegistryLeaderInitiatorTests` since it now works much faster
after proper `busy-wait` handling
**Cherry-pick to master**
* Ignore interruption on the sleep i catch and move on with loop
JIRA: https://jira.spring.io/browse/INT-4473
Previously, dynamic registration of integration flows with components configured
with the same `id` would fail with duplicate bean names.
Add `useFlowIdAsPrefix()` to the registration builder to enable the option.
Then, in the BPP, check the flag before naming the beans.
**cherry-pick to 5.0.x**
* Polishing according PR comments
* Widen `flowNamePrefix` responsibility in the
`IntegrationFlowBeanPostProcessor` since we may have many other
components in the dynamic flow with the same id, not only consumer
endpoints
When we register `IntegrationFlow` s concurrently at runtime, we may
end up with the problem when we register the same object with the same
bean name, but in different places.
Or when we turn off bean overriding, we end up with the exception that
bean with the name already registered
* Wrap `IntegrationFlow` bean registration in the
`StandardIntegrationFlowContext` into the `Lock` when its bean name
is generating
* Make `StandardIntegrationFlowContext.registry` as `ConcurrentHashMap`
to avoid `ConcurrentModificationException` during `put()` and `remove()`
* Fix concurrency for beans registration with the generation names in
the `IntegrationFlowBeanPostProcessor` using an `IntegrationFlow` id
as a prefix for uniqueness.
**Cherry-pick to 5.0.x**
Fix generated bean name in the WebFluxDslTests
Use only single `Lock` in the `StandardIntegrationFlowContext`:
we don't need a fully blown `LockRegistry` there anymore since we have
only one synchronization block there and it is always around the same
type
* Add `What's New` note, and mention changes in the `dsl.adoc`
Minor doc polishing.
https://build.spring.io/browse/INT-MASTER-1042
The `verifyShutdownWithWait()` test uses extra thread for waiting for
the `TaskScheduler` to finish its tasks.
Also the test doesn't verify the actual behavior at all
* Move `awaitTermination()` to the assert
* Decrease `delay` for the message
* Assert the latch from the handler to be sure that message is scheduled
properly even if `destroy()` call, thanks to required
`waitForTasksToCompleteOnShutdown = true`
* INT-4397: Fix headers filtering for @Transformer
JIRA: https://jira.spring.io/browse/INT-4397
The `AbstractMessageProcessingTransformer` doesn't honor a configured
`notPropagatedHeaders` and copies all the request headers to the
message to return
* Add `setNotPropagatedHeaders()` into the `AbstractMessageProcessingTransformer`
and implement there a logic to filter headers, similar to what we have
in the `AbstractMessageProducingHandler`
* Overrider `updateNotPropagatedHeaders()` in the `MessageTransformingHandler`
to propagate `notPropagatedHeaders` to the `AbstractMessageProcessingTransformer`
delegate
* * Revert `final` for the `AbstractMessageProducingHandler.updateNotPropagatedHeaders()`
* Override `addNotPropagatedHeaders()` for the `MessageTransformingHandler()`
and populate `notPropagatedHeaders` into the target `AbstractMessageProcessingTransformer`
from there
* Also populate `notPropagatedHeaders` from the `AbstractMessageProcessingTransformer.doInit()`
* Implement a `AbstractIntegrationMessageBuilder.filterAndCopyHeadersIfAbsent()`
for a general logic to filter `notPropagatedHeaders` and copy the result
headers set into the target message if they are absent
* Use an new `filterAndCopyHeadersIfAbsent()` in the `AbstractMessageProducingHandler`
and `AbstractMessageProcessingTransformer`to avoid code block duplication
https://build.spring.io/browse/INT-MASTER-1038
When we don't provide an `output-processor` for the `<barrier>`
definition, the new logic in the `IntegrationNamespaceUtils.constructAdapter()`
ends up with the `null` injection into the `BarrierMessageHandler` ctor.
From here there is no guarantee which ctor will be selected:
```
BarrierMessageHandler(long timeout, MessageGroupProcessor outputProcessor)
...
BarrierMessageHandler(long timeout, CorrelationStrategy correlationStrategy)
```
From reflection perspective they both are equal and there is no predictable
outcome which is is going to be selected.
Looks like on Windows and OSX, the second (expected) is selected, but on
Linux it is the first one.
* Fix `IntegrationNamespaceUtils.injectCtorWithAdapter()` do not inject
`adapter` in to the target ctor if it is `null`.
This way the `BarrierMessageHandler(long timeout)` ctor is selected
without any ambiguity
* INT-4389: Default to SimpleSeqSizeReleaseStrategy
JIRA: https://jira.spring.io/browse/INT-4389
An `AbstractCorrelatingMessageHandler` fallback to the
`SimpleSequenceSizeReleaseStrategy` when `releaseStrategy` isn't
provided.
* Make `ReleaseStrategyFactoryBean` to fallback to the
`SimpleSequenceSizeReleaseStrategy` for consistency.
* * Fix `ResequencerParser` to fallback to the null `releaseStrategy`.
This way a subsequent `releasePartialSequences` will set a
`SequenceSizeReleaseStrategy` as a default one
* * Fix `BarrierMessageHandler` to populate a default `CorrelationStrategy`
* * More polishing to `BarrierMessageHandler`
JIRA: https://jira.spring.io/browse/INT-4466
When we schedule group for force complete in the
`AbstractCorrelatingMessageHandler`, we don't track a group `timestamp`
and its `lastModified` before the scheduled task.
This way, in the cluster environment, we may schedule several tasks
for different messages and the first started may release the group too
early.
Just because we extract a `MessageGroup` from the store already in the
task per se.
* Propagate the actual `timestamp` and `lastModified` from group before
scheduling task.
Compare these value with the actual group metadata in the
`processForceRelease()` before performing real `forceRelease()`.
This way we restore behavior before fixing memory leak, when we
propagated full `MessageGroup` to the scheduled task
* Implement `ResequencingMessageHandler.getComponentType()` for
consistency
* Remove unnecessary overhead with the `volatile` on many
`AbstractCorrelatingMessageHandler` properties, which hardly ever can be
changed at runtime
**Cherry-pick to 5.0.x and 4.3.x**
JIRA: https://jira.spring.io/browse/INT-4467
The package tangles is caused by the explicit classes declarations.
* Since we use only method definitions from those classes, there is just
enough to use class names and use reflection to get class objects and
then get methods from them
_The fix is fully compatible for back-porting_
**Cherry-pick to 5.0.x**
* Wrap non-`StandardIntegrationFlow` into Proxy
In previous version all the `IntegrationFlow` beans have been replaced
by the `StandardIntegrationFlow` i the `IntegrationFlowBeanPostProcessor`
if they are lambda.
That works for Java, but doesn't with Kotlin, since lambdas i last one
are not synthetic classes.
Therefore some Java DSL definitions (especially `.subFlowMapping()`)
don't work consistently in two languages.
* Introduce `IntegrationFlowLifecycleAdvice` to wrap all the
non-`StandardIntegrationFlow`s (excluding `IntegrationFlowAdapter`)
into the `Proxy` to expose `SmartLifecycle` and `getInputChannel()`
operations and delegate them to the internal `StandardIntegrationFlow`
created by the `IntegrationFlowBeanPostProcessor`.
* This way any custom `IntegrationFlow` implementations can be used
for manual flow registration via `IntegrationFlowContext`
* Polish `RouterDslTests.kt` for the `@Bean`s for sub-flows.
* Document in the `dsl.adoc` a request-reply approach for the case
when `.subFlowMapping()` refers to an `IntegrationFlow` `@Bean`.
* Polishing for the `FlowServiceTests` since all the
non-`StandardIntegrationFlow`s and not-`IntegrationFlowAdapter`s are
wrapped now to the Proxy.
* Add missing `from()` delegations into the `IntegrationFlowAdapter`
* Polishing for the `ManualFlowTests` since all the `IntegrationFlow`
now are `Lifecycle` after wrapping to the Proxy.
* Add JavaDocs to the IntegrationFlowLifecycleAdvice and polishing for the dsl.adoc
* * Add JavaDocs for the `IntegrationFlowBeanPostProcessor.processIntegrationFlowImpl()`
* Improve JavaDoc for the `RouterSpec.subFlowMapping()`
* Assert in the `FlowServiceTests` that proxied custom flow implements
all the expected interfaces
https://build.spring.io/browse/INT-SI50X-JOB1-56
We can't wait for the latch in the interruptable code flow;
we can't have a round-robing election guarantees.
* Add `Thread.sleep(LockRegistryLeaderInitiator.this.busyWaitMillis)`
to the `LockRegistryLeaderInitiator` when we restart the main task
* Remove latches waiting and thread shifting from the
`RedisLockRegistryLeaderInitiatorTests`
* Use long `busyWaitMillis` for yielding initiator to let the second
candidate to be elected
**Cherry-pick to 5.0.x**
https://build.spring.io/browse/INT-FATS5IC-501/
When we try to wait for the `Latch` in the interruptable code flow,
it is a fact that we step away from the waiting and end up with the
race condition downstream.
* Wrap `Latch` in the interruptable `publishOnRevoked()` code to the
`Executor.execute()`
* Remove `deleteTimeoutMillis` option from the `RedisLockRegistry`
since it doesn't make sense in the interruptable code.
* Add `RedisLockRegistry.setExecutor()` to allow to inject an external
`Executor`
* Add more debug logging into the `LockRegistryLeaderInitiator`
**Cherry-pick to 5.0.x**
https://build.spring.io/browse/INT-MASTER-1024
When the Lettuce Redis client catches an `InterruptedException`, it is
wrapped to the `RedisCommandInterruptedException`, therefore when we
catch an exception on our code level it is not an `InterruptedException`
anymore and we can't proceed in the loop because the tread is
`interrupted` already.
* Check the `interrupted` alongside with the `InterruptedException`
to restart a loop from a fresh thread.
**Cherry-pick to 5.0.x**
* Use Lettuce Redis client; Redis module fixes
The Lettuce client is based on the Netty and more stable, than Jedis
therefore we get a performance improvement for tests
(it saves us at about 30 seconds).
Also this client doesn't fail for me on Windows sporadically (very often)
with the `ConnectionClosedException`
* After switching to the Netty-based client, we expose the interrupted
Thread issue in the `LockRegistryLeaderInitiator`.
If we interrupted (expected behavior), we try to unlock calling
`RedisLockRegistry`, but Netty client reject our request because the
thread is interrupted, therefore we never delete the lock when we yield
our leadership.
Fix the issue with shifting a `RedisTemplate.delete()` operation to the
`ExecutorService` when the current thread is interrupted
* Allow to configure such an `ExecutorService` and timeout to wait for
the `submit()` result
* Refactor `RedisAvailableRule` and all the Redis tests do not expose
the target `RedisConnectionFactory` implementation.
* Make all the test-cases based on the `connectionFactory` created by
the `RedisAvailableTests.setupConnectionFactory()`
* Tweak some unnecessary timeouts and sleeps for better tests task
throughput
* Add a `Log4j2LevelAdjuster` into the `RedisLockRegistryLeaderInitiatorTests`
https://build.spring.io/browse/INT-MASTER-1017
Looks like non-`volatile` `size` property in the `LinkedList` is not
updated properly for the `contains()` assertion, therefore we end up
with the `ConcurrentModificationException`
* Move `assertThat()` into the `synchronized (overridePresent)` block
to enforce CPU cache flushing and, therefore, have an actual value
for the `LinkedList.size` during iteration
JIRA: https://jira.spring.io/browse/INT-4461
Convert `byte[]` to `String` using `URF-8` by default.
Add optional evaluate methods to JsonPathUtils with a Charset to use when
converting `byte[]` to `String`.
This is not currently exposed using SpEL. It can be done, but probably not worth
the effort until somebody asks for it.
**cherry-pick to 5.0.x, 4.3.x**
* Use `BAIS`
For better back-pressure handling do not perform active operations
directly on the current `Flux` (e.g. via `doOnNext()`).
It's better to postpone such a handling to back-pressure ready operators
Like in this `FluxMessageChannel` case, the `.handle()` operator is
wrapping the "hard" `send()` operation.
Also include `.errorStrategyContinue()` do not stop during message
processing
* INT-4458: Do not expose recursive generics API
JIRA: https://jira.spring.io/browse/INT-4458
According Kotlin generics system restrictions we can't expose API
based on the recursive generics, like we have with Java DSL for JMS
* Replace explicit recursive generics on factory method with the wildcard (`?`).
This way both Kotlin and Java are able to instantiate target object and perform
the proper chain API auto-completion
* Fix `JmsInboundChannelAdapterSpec` to deal with provided `S` type for the
`configureListenerContainer()` - the way we can configure a `JmsDefaultListenerContainerSpec`
* Add `kotlin-spring` Gradle plugin to avoid extra `open` modificator on `@Bean` methods
* Add `JmsDslKotlinTests.kt`
**Cherry-pick to 5.0.x excluding Kotlin support**
* Fix `Amqp` DSL factory for recursive generics
* Polishing for Kotlin tests
JIRA: https://jira.spring.io/browse/INT-4456
Since Kotlin compiles lambdas different way than Java, they are not
synthetic classes at runtime anymore.
Therefore we fallback to the method invocation logic, but since Java 8
interfaces has `default` methods as well the `MessagingMethodInvokerHelper`
can't select the target method for invocation
* Use explicit `Function.apply()` for non-synthetic implementations
* Add `RouterDslTests` Kotlin-based test-case
**Cherry-pick to 5.0.x**
* Add more explicit methods for invokers
The `transactionWithCommitAndAdvices()` uses `SimpleRepeatAdvice`
which essentially performs `doPoll()` twice.
In this case we don't have enough messages in the `goodInputWithAdvice`
queue
* Add one more message to the `goodInputWithAdvice` queue during testing
* Increase all the timeouts
* Increase capacity in queues for the `transactionWithCommitAndAdvices()`
**Cherry-pick to 5.0.x and 4.3.x**
JIRA: https://jira.spring.io/browse/INT-4455
When using java config, `setChannelMapping` NPEs due to no AC.
**cherry-pick to 4.3.x, and to master, removing AC check**
* Polishing - PR comment
* Resolve TODO in the `ErrorMessageExceptionTypeRouter`
* INT-4446 Improve EmbeddedJsonHeadersMessageMapper
JIRA: https://jira.spring.io/browse/INT-4446
* Do not recreate message if not necessarily
* Do not let to generate `id` and `timestamp` if they are not mapped
* Use `smartMatch` to allow to configure negative patterns
* Introduce `PatternMatchUtils.smartMatchIgnoreCase()` for convenience
**Cherry-pick to 5.0.x**
* * Polishing `EmbeddedJsonHeadersMessageMapper`