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-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
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.
Related to: https://jira.spring.io/browse/INT-3536
Also see previous commit.
Add a mock `Store` to verify we actually call `connect()` after the failure(s).
JIRA: https://jira.spring.io/browse/INT-4232
Currently to implement the synchronization logic when remote file is modified there is only one way: remove local file and provide a `localFilter` which can be clear from the removed file as well.
The Reference Manual claims that `FileSystemPersistentAcceptOnceFileListFilter` can let us pick up a fresh version of the remote file if we configure `preserveTimestamp = true`, but actually `AbstractInboundFileSynchronizer` just bypass that logic because it check a local file for existence.
* Modify `AbstractInboundFileSynchronizer` to compare `lastModified` of the remote file with local version if `preserveTimestamp == true`
* Also replace `AcceptOnceFileListFilter` to the `FileSystemPersistentAcceptOnceFileListFilter` since the first one doesn't care about `lastModified`.
If `preserveTimestamp` isn't in use the `FileSystemPersistentAcceptOnceFileListFilter` works fully similar to the `AcceptOnceFileListFilter`
**Cherry-pick to 4.3.x except test-case**
Make `SftpStreamingMessageSourceTests` compatible with Windows
Looks like SFTP embedded server provides different permissions for files on different OSs
Doc Polishing
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-4226
Since `rabbitTemplate` properly implement `receive()` with `timeout` it looks organic to delegate a `PollableChannel.receive(timeout)` there.
* Refactor `PollableAmqpChannel` to properly delegate `PollableChannel.receive(timeout)` implementation
* Refactor `ChannelTests` to perform `PollableAmqpChannel.receive(timeout)` directly instead of `Thread.sleep()` loop
* Get rid of `BrokerRunning` in favor of the same rule from the `spring-rabbit-junit` dependency
Doc Polishing
Fix DSL AmqpTests
JIRA: https://jira.spring.io/browse/INT-4231
For `FileWritingMessageHandler` and (S)FTP outbound gateways, support
`FileExistsMode.REPLACE_IF_MODIFIED` to allow overwriting an existing file if
the source file modified time is different to the existing file.
Polishing
JIRA: https://jira.spring.io/browse/INT-4230
The `get()` method only preserves the timestamp when an LS operation is done within it.
For MGET ops, we don't perform another LS, so the timestamp was not updated.
Add code to the recursive and non-recursive MGET methods to preserve the timestamp if so configured.
JIRA: https://jira.spring.io/browse/INT-2655
There might be some use-cases when end-user expect more control over sending/receiving messages via `WebServiceTemplate`.
It would be better to delegate (un)marshalling logic to the `WebServiceTemplate.marshalSendAndReceive()` directly.
Fix Checkstyle violations
Polishing
JIRA: https://jira.spring.io/browse/INT-4089
Right now `DefaultSoapHeaderMapper` can map only `String` user-defined headers and only to the `SAOP:Header` attributes.
* Add functionality to map `Source` user-defined headers as sub-elements of the `SAOP:Header`
Polishing
JIRA: https://jira.spring.io/browse/INT-3561
To allow any possible custom properties on the `WebServiceTemplate` it would be better just to have an injection for the rather than try to pursue exposing for all `WebServiceTemplate` setters
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.
https://build.spring.io/browse/INT-FATS5IC-79/
Since there is no guaranty which exception message will be built by the SSL handshake error, we can't rely on only one expectation.
Also fix Checkstyle vulnerabilities in the IP module for ImportOrder rule
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-3923Fixes: #2046
Previously, when connection is lost, the inbound adapter attempted to reconnect on
a schedule with a fixed delay.
If a connection was again lost, while the schedule is still running, we can end up
with another scheduled task running.
This is benign aside from the DEBUG log noise because the scheduled task tests the
connection before reconnecting.
However, if the `recoveryInterval` is short, it could consume CPU.
Change the reconnect to be a one-time scheduled task and reschedule if it fails to
reconnect.
Synchronize all access to the `connected` field.
Add a test case with a short recovery interval, before this fix, we see many logs
`Attempting reconnect`.
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
JIRA: https://jira.spring.io/browse/INT-4216
Add test for running empty array through `ChainFileListFilter`
Assure no exceptions are throw when filter input is empty.
INT-4216: Add fix for ChainFileListFilter edge case
INT-4216: Fix checkstyle error on test class
Add copyright header to test file
* Polishing for `ChainFileListFilter` JavaDocs
* Move `CompositeFileListFilterTests` and `ChainFileListFilterIntegrationTests` to the `filters` package instead of `file` core
JIRA: https://jira.spring.io/browse/INT-4215
Due to type erasure we can't create an empty generic array from an empty list.
Don't attempt to call remaining filters when the list is empty.
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
JIRA: https://jira.spring.io/browse/INT-4211
The latest Spring Data Gemfire fixed `BeanFactoryLocator` issue.
* Now we can remove `@Ignore` from tests which have failed before by the `ClassNotFaoud` reason
* Also fix Checkstyle violations in the Gemfire module classes
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)