JIRA: https://jira.spring.io/browse/INT-4225
* To allow flexible way to convert incoming messages for the target arguments in method invocation
add `ConfigurableCompositeMessageConverter` global bean under `ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME`
* Retrieve that bean for the `MessageHandlerMethodFactor` in the `MessagingMethodInvokerHelper` to enrich afterwards target `HandlerMethodArgumentResolver`s
* The `ContentTypeConversionTests` demonstrates conversion incoming JOSN `string` into the target POJO argument in the service method
* Add `@Primary` support
* Add documentation about `@Primary` and `contentType` conversion
INT-1800: Add MTOM Support for WS
JIRA: https://jira.spring.io/browse/INT-1800
The Simple WebService Inbound and Outbound Gateways can operate with `WebServiceMessage`s directly.
This allows to create those messages manually and add attachments to them.
Or, on the other hand, process incoming messages with attachments manually.
For this purpose the `SimpleWebServiceOutboundGateway` is supplied with new `extractPayload` property.
Also the `UnmarshallingTransformer` can now process `MimeMessage` as payload to unmarshal it into object graph with attachments if that
INT-4225: Add MessageConverters infrastructure
JIRA: https://jira.spring.io/browse/INT-4225
* To allow flexible way to convert incoming messages for the target arguments in method invocation
add `ConfigurableCompositeMessageConverter` global bean under `ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME`
* Retrieve that bean for the `MessageHandlerMethodFactor` in the `MessagingMethodInvokerHelper` to enrich afterwards target `HandlerMethodArgumentResolver`s
* The `ContentTypeConversionTests` demonstrates conversion incoming JOSN `string` into the target POJO argument in the service method
* Add `@Primary` support
* Add documentation about `@Primary` and `contentType` conversion
Doc Polishing
Change `@Primary` to `@Default`
Doc Polishing
JIRA: https://jira.spring.io/browse/INT-4234
When the actual argument type is `Message` there is no reason to go down the `if...else` logic.
This doesn't work for Lambda anyway because of generics erasure in case of `GenericTransformer`, but that is the fix for case of direct interface implementation
JIRA: https://jira.spring.io/browse/INT-4229
* Make `SpelPropertyAccessorRegistrar` as `public` class and provide more API to customize it.
This class allows to register `PropertyAccessor` s for shared `EvaluationContext`
* Document how to configure SpEL functions and `PropertyAccessor` s with Java Config
**cherry-pick to 4.3.x**
JIRA: https://jira.spring.io/browse/INT-4237
It was possible to flush (close) the file while a write was in process; more likely when
`flushWhenIdle` is false.
This probably would not occur in the real world, just tests with short flush intervals,
but certainly possible.
There is already a lock used to prevent concurrent writes while appending; use the same
lock when flushing.
JIRA: https://jira.spring.io/browse/INT-4233
INT-4233: Add (S)FTP FileInfo Header (Streaming)
JIRA: https://jira.spring.io/browse/INT-4233
Add the complete file info as JSON (when Jackson or Boon available) to the message headers
when streaming inbound.
Provide a mechanism to configure Boon to provide similar output to Jackson.
Also allow subclasses to provide their own object mapper.
Also clean up after the AMQP DSL tests, and don't use a queue `foo`. I often have such a queue
with content; this caused tests to fail.
Use SimpleJsonSerializer
Doc Polishing
Polishing - PR Comments
More Polishing
* Polishing according latest PR comments
JIRA: https://jira.spring.io/browse/INT-4227
Expose `MessagingAnnotationPostProcessor` for inheritors.
The `CustomMessagingAnnotationTests` demonstrates how custom Messaging Annotation can be registered and used
**Cherry-pick to 4.3.x**
Add `setupCustomPostProcessors()` and `addMessagingAnnotationPostProcessor` to the `MessagingAnnotationPostProcessor`
Expose some API for inheritors
JIRA: https://jira.spring.io/browse/INT-4236
Add methods to obtain status from the `SmartLifecycleRoleController`.
* Polishing according PR comments.
* Fix log messages in the `SmartLifecycleRoleController` from the Zookeeper mentioning
JIRA: https://jira.spring.io/browse/INT-4228
Previously, if a bean definition for a channel exists, but has configuration issues,
the `AbstractMethodAnnotationPostProcessor` still went ahead and created a `DirectChannel`.
Only with TRACE logging was the root cause apparent.
This was because all `BeanException` s cause that behavior.
Now, only `NoSuchBeanDefinitionException` will cause auto-creation of channels.
Tested with mocks and a real Boot app, which now correctly reports
```
15:28:41.582 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'rabbitConnectionFactory' available
```
The `MessagingMethodInvokerHelper` extracts `targetClass` to process methods and avoid extra methods when class is Proxy
The `InvocableHandlerMethod` is based on the reflection method invocation and we should use runtime methods on the proxy to invoke.
We don't see such a problem in SpEL because it is parsed from the plain String to the real code later
Polishing
Add an Advice to the test.
JIRA: https://jira.spring.io/browse/INT-4218
* Add `InvocableHandlerMethod` invocation threshold logic to give up eventually in favor of permanent expression evaluation
* Add `ParametersWrapper.toString()` for better logging messages
* Log `InvocableHandlerMethod` invocation failure message in favor of SpEL only once when `failedAttempts` is exceeded already
* Switch to `spelOnly` mode after that
* Refactor `MessagingMethodInvokerHelper.processInternal()` to separate SpEL or Ivocable logic via their own invocation methods
* Move `MessagingMethodInvokerHelper.HandlerMethod` static fields to the `MessagingMethodInvokerHelper` level since it doesn't matter from this class perspective but can be reused in other places from top level of the `MessagingMethodInvokerHelper` class
* Catch `IllegalArgumentException` with the `java.lang.ClassCastException@...` message.
See http://stackoverflow.com/questions/16042591/reflections-illegalargumentexception-causes for more info
Address PR comments
* Make `handlerMethod.failedAttempts` conditional expression as `>=` to avoid race conditions in multi-threaded environment
* Analyze StackTrace for the class of the `IllegalStateExpception` avoid SpEL fall back in case of user exception, not reflection invocation
* Fix race condition in the `TcpNioConnectionTests`, when atomic value is set after `latch.countDown()`
To avoid confusing `.bridge(null)` in the end of flow for replying to the gateway on top introduce simple `.bridge()` with just delegation to the `.bridge(null)` with the same result as before
JIRA: https://jira.spring.io/browse/INT-4222
See INT-4214; the `DefaultMessageHandlerMethodFactory` requires a conversion service
and sets up a default.
Some SI components propagated a `null` conversion service which overwrote the default
causing runtime exceptions.
Caused by: java.lang.IllegalArgumentException: ConversionService must not be null
at org.springframework.util.Assert.notNull(Assert.java:163) ~[spring-core-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
JIRA: https://jira.spring.io/browse/INT-4220
Currently when an error is thrown from the event publishing the role granting is broken and we just go to the role revoking.
* Since it's just an event publishing it shouldn't effect the original leader election.
* `try...catch` event publishing in the `LeaderInitiator` and `logger.warn` an `Exception`
* Make `leader/Context` as `@FunctionalInterface` for simple Lambda use-case like `NULL_CONTEXT` - `() -> false`
* Remove all the internal `NullContext` implementations in favor of above mention Lambda
* In the `LockRegistryLeaderInitiator` use `CustomizableThreadFactory` instead of custom `ThreadFactory` for prefixing
* Add `zookeeper/leader/LeaderInitiator#getContext()` for external usage and consistency with other similar components
* Fix `CuratorContext.toString()` typo
JIRA: https://jira.spring.io/browse/INT-4221
* Upgrade to those versions of Spring project dependencies which potentially will provide similar fix
**Cherry-pick to 4.3.x**
Fixesspring-projects/spring-integration-java-dsl#140
Allow to provide any custom `MessageProducer` impl for the `.handle()`, not only `AbstractReplyProducingMessageHandler` extension
Polishing
JIRA: https://jira.spring.io/browse/INT-4217
Previously, SpEL method calls with required header parameters had the following form:
#target.messageAndHeader(message, headers['number'] != null ? headers['number'] : T(org.springframework.util.Assert).isTrue(false, 'required header not available: number'))
The SpEL compiler cannot compile this because the else clause of the ternary has no `exitDescriptor` to indicate the type.
Change the expression to use a function for required headers.
Also use an Elvis operator when possible.
Some examples of new expressions:
#target.optionalAndRequiredHeader(headers['prop'] ?: null, #requiredHeader(headers, 'num'))
#target.optionalAndRequiredDottedHeader(headers['dot1'] != null ? headers['dot1'].foo : null,
#requiredHeader(headers, 'dot2').baz
In the second case, we can't use an Elvis because we're accessing a `foo` property of the header.
__cherry-pick to 4.3.x__
- make `ParametersWrapper` `static`
- minor conflicts in imports
- remove the perf test
* Polishing: remove redundant annotation args for their default values usage
Several problems:
- Setting the system property is not enough since the `static` parser already has its configuration
- Changing the ParametersWrapper to `private` makes property accessing not compilable (the method and class must be public).
- The expression...
#target.messageAndHeader(message, headers['number'] != null ? headers['number'] : T(org.springframework.util.Assert).isTrue(false, 'required header not available: number'))
...is not compilable anyway because the right arguent to the `!=` is not compilable because the `TypeReference.exitTypeDescriptor` is `null`.
This commit addresses the first two.
Polishing
Use a compilable method.
* Simple polishing
JIRA: https://jira.spring.io/browse/INT-4214
* Rework `MessagingMethodInvokerHelper` to delegate to the `InvocableHandlerMethod` with its `HandlerMethodArgumentResolver` infrastructure instead of SpEL
* Introduce several `HandlerMethodArgumentResolver` to address some SI use-cases like `@Payloads`, `@Payload(expression = "")` and `Collection` as argument
* Initialize `DefaultMessageHandlerMethodFactory` in the `MessagingMethodInvokerHelper.start()`.
With that I observed several `Lifecycle` problem when we don't have proper delegate from the top.
* Fix `AbstractCorrelatingMessageHandler` and similar to delegate `Lifecycle` properly
* Fix `ReactiveConsumer` to delegate `Lifecycle` to the `MessageHandler`
* Fix `MutableMessage` do not `generateId()` and set `timestamp` headers if we already have them in the provided headers
* With all that `Lifecycle` many tests must be fixed to call `start()`
Add SpEL fallback variant to the MessagingMethodInvokerHelper
Add `MessagingMethodInvokerHelper.setUseSpelInvoker(boolean)`
Add `MethodInvokingMessageProcessorTests.testPerformanceSpelVersusInvocable()`
Add Compiled SpEL comparison
* Add `MapArgumentResolver` to cover `Properties` case
* add `MessagingMethodInvokerHelper.HandlerMethod.spelOnly` state, when we definitely can perform ony SpEL for provided arguments, e.g. `@Header` with expression
* Catch `IllegalStateException` with the `"argument type mismatch"` message to fallback to SpEL invocation
* Add `Iterator` support for the `CollectionArgumentResolver`
* Add `integrationConversionService` bean registration into the `TestUtils.createTestApplicationContext()`
* Tweak `.travis.yml` to try to download latest JDK, the current `1.8.0_31` is pretty old already and has some bugs
* Adjust some failing tests to use `TestUtils.createTestApplicationContext()` to rely on newly added `integrationConversionService` bean
Fix failed tests: `ctx.refresh()`
Polishing current year in Copyright
* JavaDocs for `CollectionArgumentResolver` and `MapArgumentResolver`
* Propagate `ConversionService` from the `MessagingMethodInvokerHelper` to the `MapArgumentResolver.java`
Fix `MessagingMethodInvokerHelper` to propagate `BeanFactory` into `MapArgumentResolver` as well
The `MapArgumentResolver` now `extends AbstractExpressionEvaluator`, too
Fix JavaDoc typo
Otherwise we end up with the case to break the flow which expect message from the explicit channel.
Add JavDocs to `.wireTap()` to explain behaviour in the end of flow
JIRA: https://jira.spring.io/browse/INT-4210
Previously use-case like:
```
.transform()
.log()
.get();
```
failed with the `Dispatcher has no subscribers` for an implicit channel populated by the `.wireTap()` because actually `LoggingHandler` is placed on the wire-tapped channel
Since logically it looks like end-user tries to have `LoggingHandler` as a terminal of the flow, we add `nullChannel` if `WireTapSpec` is in the end of the flow definition.
If user would like to continue flow (e.g. return reply to the `replyChannel`), he must end more EIP-methods after `.log()` (like before, of course)
JIRA: https://jira.spring.io/browse/INT-4207
Enhance `AbstractMessageProducingHandler` to fallback for `replyChannel` to the `reply` if it is `Message`.
That lets to avoid extra `bridge` configuration afterwards to make that `reply` as `request` for the same `replyChannel` resolution.
This situation happens in case of error handling when the request message is `ErrorMessage`, typically without original headers to properly consult.
But at the same time `failedMessage` in the `MessagingException` has all required headers.
JIRA: https://jira.spring.io/browse/INT-4206
* Fix unnecessary dependency resolution in BOM module
* Fix `MessagingMethodInvokerHelper` to handle `$MockitoMock$` generated classed which isn't CGLib `Proxies` any more
* Provide fixes for test classes according upgrade to Mockito `2.5`
* Fix Ceckstyle do not allow static imports for deprecated Mockito classes
* Move `SubscribableChannelPublisherAdapter` and `PollableChannelPublisherAdapter` logic to the `MessageChannelReactiveUtils` public API
* Rework `ReactiveConsumer` and `IntegrationFlowDefinition.toReactivePublisher()` to use `MessageChannelReactiveUtils`
* Add `ReactiveSubscribableChannel` interface to represent abstraction with capability to subscribe to `Publisher`
* Implement `ReactiveSubscribableChannel` in the `ReactiveChannel`
* Add `IntegrationFlows.from(Publisher)` factory and use newly introduced `ReactiveSubscribableChannel.subscribeTo()`
* Add `MessageChannels.reactive()` factory methods for the `ReactiveChannelSpec`
* Make `ReactiveChannel` as an `AbstractMessageChannel` to give an interception opportunity and gather metrics for `send()`
* A `ReactiveStreamsTests.testFromPublisher()` demonstrate how to subscribe to the `Flux` from an `IntegrationFlow` and at the same time get a gain of the runtime flow registration
* The `ReactiveChannelTests.testMessageChannelReactiveAdaptation()` demonstrates how to use `MessageChannelReactiveUtils.toPublisher()` (name can be changes though...)
JIRA: https://jira.spring.io/browse/INT-4134
* Introduce `AnnotationGatewayProxyFactoryBean` to parse `@MessagingGateway` annotation directly in the bean.
Useful for Java (`@Bean`) configuration variant
* Use `AnnotationGatewayProxyFactoryBean` for the newly introduced `IntegrationFlows.from(Class<?>)`
* Override `requestChannel` in the result gateways to the auto-created `DirectChannel` in the current `IntegrationFlowDefinition`
* Register `AnnotationGatewayProxyFactoryBean` from the `IntegrationFlows.from(Class<?>)` as a bean with the name like: `IntegrationFlow` bean name plus `.gateway` suffix
* Merge `GatewayCompletableFutureProxyFactoryBean` to `GatewayProxyFactoryBean`, since we are based on the Java 8 already anyway
JIRA: https://jira.spring.io/browse/INT-4197
Since `Collection<Message<?>>` can be possible only if we are dealing with messages as a group (`MethodInvokingMessageListProcessor`), the case with the `List<?>` param for Messaging Annotation method should not be treated as candidate for `messages` collection.
* Add `this.canProcessMessageList` condition to avoid `messages` SpEL expression when we are not in the `MethodInvokingMessageListProcessor` environment
**Cherry-pick to 4.3.x**
* Fix Array creating formatting
* Add comment about `ReflectiveMethodExecutor` to the `testRouterWithListParam()`
* Send one test data as as `Collection` to be sure that `@Router` parameters mapping works well
JIRA: https://jira.spring.io/browse/INT-4201
name<->value alias was not processed correctly so using
`@Header(name = "baz") String baz` did not work.
Use `SynthesizingMethodParameter`.
JIRA: https://jira.spring.io/browse/INT-4196
Add `CollectionCallback` option to the `MongoDbOutboundGateway`
Add XML support to CollectionCallback
Fix PR comments
Fix issue with javadoc parsing
* Polishing code style, JavaDocs and some Docs
There is tiny time window when `LockRegistryLeaderInitiator` can be stopped during `Context.yield()` invocation.
In this case the `LockRegistryLeaderInitiator` goes to the stopped state, but a new `leaderSelector` is submitted for election.
Therefore in the `LockRegistryLeaderInitiatorTests.competing()` the second initiator may not get be granted because there is uncontrolled `leaderSelector` task on background.
We can overcome it with always `this.initiator.stop()` for the `LockRegistryLeaderInitiatorTests`, but to be sure in the fix it would be better to leave as is.
Also add `@Rule Log4jLevelAdjuster` for future diagnostics
**Cherry-pick to 4.3.x**
No reason to load class one more time if `MethodMetadata` is already `StandardMethodMetadata`
See https://jira.spring.io/browse/SPR-14505
**Cherry-pick to 4.3.x**
https://build.spring.io/browse/INT-MJATS41-856
According the attempts to read method from class in the proper order, there is a fix in SF to do that via ASM.
Therefore `beanDefinition.getSource()` isn't `StandardMethodMetadata` any more.
Fortunately we can simply assert against `returnTypeName` to check for the `MessageHandler`
See https://jira.spring.io/browse/SPR-14505
**Cherry-pick to 4.3.x**
Fixes GH-2007 (https://github.com/spring-projects/spring-integration/issues/2007)
To allow more straightforward extension and avoid some extra mocking provide some `protected` methods for the `IntegrationComponentScanRegistrar` which can be implement in some specific cases, like Spring Boot auto-configuration
The `EnableComponentScanTests` demonstrates how it can be done now in case of `basePackage` overriding
JIRA: https://jira.spring.io/browse/INT-4195
Avoid the N^2 search in `SequenceAwareMessageGroup` when the group is a
`SimpleMessageGroup`.
Avoid the use of the header accessor if the N^2 search is needed (SPR-15045).
Polishing - PR Comments
JIRA: https://jira.spring.io/browse/INT-4193
When using the internal `SequenceAwareMessageGroup` within an correlating
message handler, the messages were copied to a new collection before
checking for duplicate sequences in `canAdd()`.
This was unnecessary since we never add anything to this group, if `canAdd()`
returns true, the message is added to the store; this group is discarded.
Instead, use the message collection from the original group; although it is
not modifiable, this is not an issue because we don't need to modify it.
Conflicts:
spring-integration-core/src/main/java/org/springframework/integration/store/SimpleMessageGroup.java
spring-integration-core/src/main/java/org/springframework/integration/store/SimpleMessageGroupFactory.java
src/reference/asciidoc/aggregator.adoc
* Polishing `aggregator.adoc` to reflect reality
https://build.spring.io/browse/INT-MASTER-478
The `EmitterProcessor` proves to be unstable in between subscribers which come and go away from time to time.
Looks like buffered events are dropped when we don't have subscriber just after the previous one has been unsubscribed
* Change the logic in the `IntegrationFlowDefinition.toReactivePublisher()` to call `ReactiveConsumer.adaptToPublisher(MessageChannel)` directly to return provided `Publisher<?>` to the caller for his own responsibility.
This way we don't have any buffering or prefetching in the Framework because we don't do any `Subscription.request(n)` explicitly
* Prove the fix with polishing to the `ReactiveStreamsTests.testPollableReactiveFlow()`
Right now we don't poll `QueueChannel` if there is no demand, therefore we don't need extra `CountDownLatch` to wait for second subscriber.
Plus the logic now remains as a `queue` manner: consumers are concurrent for the data in the `QueueChannel`
Extra `@Repeat(10)` for confirmation.
Previously it failed sporadically, what is confirmed with that one more CI failure
JIRA: https://jira.spring.io/browse/INT-4181
* To avoid duplicate code move actual `Metrics` resolution to the `IntegrationManagementConfigurer` and delegate from the `IntegrationMBeanExporter` for backward compatibility
* Minor refactoring and improvements in the `IntegrationMBeanExporter`
* Fix typos in the `jms/AsyncGatewayTests`
**Cherry-pick to 4.3.x**
https://build.spring.io/browse/INT-MASTER-473/
There is a race condition when we perform `onSubscribeCall()`, but the actual subscription isn't happened yet, therefore a new data for the `EmitterProcessor` is dropped because there is no subscriber yet to drain the buffer
JIRA: https://jira.spring.io/browse/INT-4182
To avoid extra allocation for the `SimpleDateFormat` use a new Java 8 `DateTimeFormatter` based on new `Temporal` abstraction
Leave test-cases as is to save some time for other tasks
Fix RedisLockRegistry for the proper formatter and ZoneId
https://build.spring.io/browse/INT-MASTER-468/
Looks like demand in the `FluxTake` isn't honored:
```
public void request(long n) {
if (wip != 0) {
s.request(n);
}
else if (WIP.compareAndSet(this, 0, 1)) {
if (n >= this.n) {
s.request(Long.MAX_VALUE);
}
else {
s.request(n);
}
}
}
````
It isn't clear why we request from upstream `Long.MAX_VALUE`, if we have only strong `n` limit
So, revert to the `secondSubscriberLatch` and don't send the next message until the subscription from the second `Flux`
https://build.spring.io/browse/INT-MASTER-467/
Even if `EmitterProcessor` looks good for us not requesting until real `subscriber()`, it doesn't keep backlog for late subscribers like it happens some times in our subscriber in the separate Thread.
The solution should be considered as tentative because the real one must be based on the fact that `AMPH` has to perform `subscription.request(n)` as a fact of the subscription from downstream.
In other words mid-flow components should work as passive subscribers and be based on downstream demand