* Some `LockRegistryLeaderInitiator` improvements
It is better to not go to the target lock provider at all
if the current thread is already interrupted.
* Check for the `Thread.currentThread().isInterrupted()` in the `while` loop
and `restartSelectorBecauseOfError()` immediately without checking for a lock
* Fix some other simple typos in the `LockRegistryLeaderInitiator`
**Cherry-pick to `6.0.x`**
* * Introduce a `LeaderSelector.yielding` flag
to revoke leader smoothly.
Turns out just canceling the `Future` may lead to a broken lock
where we cannot unlock it because the target lock repository may not work
with interrupted threads.
This way a new leader must wait until the lock is expired in the store
* Remove the use of instance suppliers on bean definitions
that are processed during the AOT phase.
* The remaining areas that use instance suppliers do so
at runtime and do not use reflection, but instead
are passed the configured bean to register.
See https://github.com/spring-cloud/spring-cloud-stream/issues/2655
**Cherry-pick to `6.0.x`**
Fixes https://github.com/spring-projects/spring-integration/issues/3772
* Add basic To/From Protocol Buffer's com.google.protobuf.Message transformers.
* Allow the proto_type header to specify the type.
* Add tests.
* add Protobuf docs
* Leverage the Spring ProtobufMessageConverter
* move protobuf-java-util to test dependecies as optional
* protobuf docs improvements
* improve the expected type handling
* expected type expression
* fix indentation
* fix indentation for generated test classes
* suppress style check for proto generated classes
* address the transformer doc format
* fix whats new merge conflict
* fix doc sample code
* Some code clean up; fixing typos
* GH-3957: Add JmsInboundGateway.replyToExpression
Fixes https://github.com/spring-projects/spring-integration/issues/3957
Sometimes we cannot use a standard `JmsReplyTo` property for sending replies from the server.
A `DestinationResolver` API does not have access to the request message.
* Introduce a `ChannelPublishingJmsMessageListener.replyToExpression` property to evaluate
a reply destination against request JMS `Message`
* Use this expression only of no `JmsReplyTo` property
* Expose this property on Java DSL level
* To simplify end-user experience with lambda configuration for this property, introduce a `CheckedFunction`
which essentially re-throws exception "sneaky" way
* Fix Javadoc for `CheckedFunction`
* * Fix language in docs
* Fix Javadocs lines length
* Regular `catch` and re-throw in the `CheckedFunction`
* Upgrade dependencies whenever it is reasonable
* Fix deprecations and some new API paths
* Move docs to a new version with respective branching for the `changes-5.5-6.0.adoc`
For better performance by default it is better to not pull
a `io.micrometer:context-propagation` a hard dependency.
* Remove `io.micrometer:context-propagation` dependency management
* It is pulled transitively by the `io.micrometer:micrometer-tracing-integration-test` in test scope
* Rework all the `ContextSnapshot` usage in the reactive code to respective recommended `handle()` API in `Flux` and `Mono`
To propagate an `Observation` from reactive stream (e.g. WebFlux)
we have to capture its context and set it into the current thread scope.
* Add a `io.micrometer:context-propagation` dependency to support reactive context propagation
* Populate a `parentObservation` in the `IntegrationObservation.PRODUCER.observation()`
since it is not available for tracing on `Observation.onStart()`.
Might be tentative until upcoming fix in Micrometer Observation
* Populate from reactive context in the `WebFluxInboundEndpoint` where we use just `send()` operation downstream
* Populate from reactive context in the `MessagingGatewaySupport` where we use `send()` operation downstream or `FluxMessageChannel.subscribeTo()`
* Use `contextCapture()` in the `FluxMessageChannel` to gather a `ThreadLocal` info into a Reactor context
and then set back to `ThreadLocal` in the `transformDeferredContextual()` which really happens on a different thread
* Verify a trace propagation from WebFlux to an integration flow via Brave instrumentation in the `WebFluxObservationPropagationTests`
Fixes https://github.com/spring-projects/spring-integration/issues/3994
Essentially, migrate those hints from Spring Boot Actuator:
an `IntegrationGraphServer` can be used without Spring Boot
* Introduce `IntegrationGraphRuntimeHints` - implementation of `RuntimeHintsRegistrar`
to register reflection hints for `Graph` and top-level `IntegrationNode` types.
* Use `@ImportRuntimeHints` on the `IntegrationGraphServer` to make those hints
conditional.
Related to https://stackoverflow.com/questions/75109345/spring-integration-webflux-inboundgateway-replychannel-for-error-response
The `MessagingGatewaySupport.doSendAndReceiveMessageReactive()` uses `MutableMessageBuilder`
to build a new message for next `send` operation.
Even if this is an error flow, the provided `ErrorMessage` becomes a plain `MutableMessage`.
This may break some downstream logics, like `TracingChannelInterceptor` from Spring Cloud Sleuth,
which checks for the `Message` class to rebuild or reuse a message content.
Therefore, an error handling flow is not able to extract error info because it is just lost.
* Fix `MessagingGatewaySupport.doSendAndReceiveMessageReactive()` to check for message type before
choosing an `AbstractIntegrationMessageBuilder` impl for building a new message.
The regular `MessageBuilder` just builds a new `ErrorMessage` for an exception payload.
* Add `filter()` into a `WebFluxDslTests` error handling flow to be sure that message for
error sub-flow is really an `ErrorMessage`
Fixes https://github.com/spring-projects/spring-integration/issues/3990
Turns out just being on the classpath doesn’t make the type reachable.
If it’s only accessed reflectively then it’s not reachable.
This is exaclt what happened with our `JsonPathUtils` which is used via
reflection from SpEL when that calls its method via function reference
* Change `onReachableType()` logic for `com.jayway.jsonpath.JsonPath` type
to `ClassUtils.isPresent()` on `JsonPathUtils` reflection hint registration.
Currently, when `!resolutionRequired` not resolved channel name
is ignored silently, and we go ahead to `defaultOutputChannel` or
exception thrown
* For better end-user experience `DEBUG` not resolved and ignored channel name if `!resolutionRequired`
* Do not build exception instances in advance
When no `cause` and no clean context of the exception thrown,
the code place where an exception has been created is confusing.
* Fix `SimpleMessageStore` to create an `out of capacity` exception in the
`addMessagesToGroup()` exactly at the point where it is thrown
* Fix `FunctionExpression` and `SupplierExpression` do not pre-create `readOnlyException`:
it is unlikely these kind of expressions are going to be used in the SpEL `write` context,
so we save some time and memory not creating extra object and the plain call `throw new`
gives us a clean context what method call has ended up with such an exception
* * Extract `outOfCapacityException` to the method in the `SimpleMessageStore`
to avoid duplication.
Even if we got in the end extra line in th stack trace, it is still clear from
where it is thrown:
```
org.springframework.messaging.MessagingException: SimpleMessageStore was out of capacity (1) for group 'foo', try constructing it with a larger number.
at org.springframework.integration.store.SimpleMessageStore.outOfCapacityException(SimpleMessageStore.java:324)
at org.springframework.integration.store.SimpleMessageStore.addMessagesToGroup(SimpleMessageStore.java:302)
at org.springframework.integration.store.AbstractMessageGroupStore.addMessageToGroup(AbstractMessageGroupStore.java:189)
at org.springframework.integration.store.SimpleMessageStoreTests.shouldNotHoldMoreThanGroupCapacity(SimpleMessageStoreTests.java:128)
```
* Obtain observed timers in the Integration Graph
The `Observation` populates slightly different Micrometer timer names and their tags
* Fix `MicrometerNodeEnhancer` to search timers in the registry according to the `Observation`
convention if the provided component is observed
* For that purpose expose an `IntegrationManagement.isObserved()` option to check
of component is instrumented with an `Observation`
* Improve the logic in the `IntegrationGraphServer` to delegate into a `Function`
to call `micrometerEnhancer.enhance()` instead of `static` property which might not
be OK in the environment where several integration applications are ran in the same JVM
* * Collect times into graph for inbound gateways & producers
* Fix language in javadoc of new `IntegrationManagement.isObserved()`
* Add `@Nullable` to `MicrometerNodeEnhancer.buildTimerStats()` param to satisfy this method contract
Co-authored-by: Gary Russell <grussell@vmware.com>
Co-authored-by: Gary Russell <grussell@vmware.com>
The time-based tests are very sensitive to an activity on the target machine.
So, strict test sometimes fail.
* Fix `DelayerUsageTests` to deal with approximate values to compare by some percentage
Fixes https://github.com/spring-projects/spring-integration/issues/3953
The replying `MessageHandler` can resolve the target output channel in on-demand manner.
A new messaging annotations on `@Bean` parsing algorithm is missing the lazy-load
opportunity and uses a `RuntimeBeanReference` for output channel options
loading its bean eagerly.
* Fix `AbstractMethodAnnotationPostProcessor` to use a `outputChannelName` and
`defaultOutputChannelName` target properties for channel names to set.
* Expose more reflection hints
* Bring back `@Reflective` on `Pausable` - for possible end-user usage
* Add `ReactiveMessageHandler` hint since its method is used reflectively
in the `IntegrationRSocketMessageHandler`
* Add `@Reflective` on the `ServerRSocketMessageHandler.handleConnectionSetup()`
since it is used reflectively for a `registerHandlerMethod()`
* Add `KafkaRuntimeHints` to expose `Pausable` contract on Kafka inbound endpoints
for SpEL invocation via Control Bus
* Document native images support
* Fix language in docs
Co-authored-by: Gary Russell <grussell@vmware.com>
Co-authored-by: Gary Russell <grussell@vmware.com>
* Also register `Pausable` explicitly and remove its `@Reflective`.
This type is needed for Control Bus SpEL execution, but it might not
be available at runtime because not all endpoints implement it
The `Pausable` & `ManageableSmartLifecycle` types are eligible to be used
from Control Bus.
This one is based on SpEL and therefore requires a reflection for those
types to be available in native image
* GH-3555: Change logger order for errorChannel
Fixes https://github.com/spring-projects/spring-integration/issues/3555
The default global `errorChannel` has a `LoggingHandler` as a subscriber.
It is subscribed without any `order` which may lose logging messages,
when another subscriber with re-throw is present.
* Set default `LoggingHandler` on the default `errorChannel` to `Ordered.LOWEST_PRECEDENCE - 100`
to give a room for custom subscribers without an `order` and still get error logged
* Add extra note in docs about an order for custom subcribers
Co-authored-by: Gary Russell <grussell@vmware.com>
Co-authored-by: Gary Russell <grussell@vmware.com>
* GH-3946: Revise Router channelKeyFallback option
Fixes https://github.com/spring-projects/spring-integration/issues/3946
The `AbstractMappingMessageRouter` has both `resolutionRequired` and `channelKeyFallback`
as `true` by default.
End-users expects them to back off when they set a `defaultOutputChannel`.
They really want something similar to Java `switch` statement
* Change the logic in the `AbstractMappingMessageRouter` to reset `channelKeyFallback`
to `false` when `defaultOutputChannel` to avoid attempts to resolve channel from name,
but rather fallback to `defaultOutputChannel` as it states from th mentioned
Java `switch` statement experience
* Deprecate `RouterSpec.noChannelKeyFallback()` in favor of newly introduced `channelKeyFallback(boolean)`
* Call `channelKeyFallback(false)` from an overloaded `defaultOutputToParentFlow()`
to reflect the mentioned expected behavior in Java DSL as well.
* Respectively, deprecate `KotlinRouterSpec.noChannelKeyFallback()` wrapper
in favor of newly introduced `channelKeyFallback(channelKeyFallback: Boolean)`
* Remove redundant already `noChannelKeyFallback()` option in the `NoFallbackAllowedTests`
* Document the change and new behavior
* Fix `IntegrationGraphServerTests` to `setChannelKeyFallback(true)` explicitly
* Remove not relevant `default-output-channel` from the `DynamicRouterTests-context.xml`
* Reject an `AbstractMappingMessageRouter` configuration where `defaultOutputChannel` is provided
and both `channelKeyFallback` & `resolutionRequired` are set to `true`.
Such a state makes `defaultOutputChannel` as not reachable and may cause some confusions in target
applications.
* Remove `&` symbol from JavaDocs
* Fix `boolean` expression for `AbstractMappingMessageRouter` configuration check
* Fix `IntegrationGraphServerTests` for new router behavior
* Improve language in docs
The `GatewayProxyInitializationAotProcessor` uses mistakenly a `ProxyFactoryBean` type
instead of an expected `GatewayProxyFactoryBean`.
Looks like we don't need to scan for interfaces since they are properly transformed
to the `AnnotationGatewayProxyFactoryBean` bean definition during AOT phase
* GH-3945: Fix `not eligible for getting processed`
Fixes https://github.com/spring-projects/spring-integration/issues/3945
The `IntegrationManagementConfiguration` produces an `IntegrationManagementConfigurer` which is a `BeanPostProcessor`.
According to Spring recommendation this kind of infrastructure beans must be declared as `static`.
Due to an `implements ImportAware, EnvironmentAware` nature of the `IntegrationManagementConfiguration`,
we cannot use `static @Bean` method.
But since the `IntegrationManagementConfiguration` is not involved in any bean post-processing,
it is safe to follow recommendation and mark it as a `@Role(BeanDefinition.ROLE_INFRASTRUCTURE)`.
* Fix `MessagePublishingInterceptor` to initialize `MessagingTemplate` and `DestinationResolver` lazily
* Fix `AbstractMethodAnnotationPostProcessor` to initialize `DestinationResolver` lazily
**Cherry-pick to `5.5.x`**
* * Use `getChannelResolver()` internally in the `AbstractMethodAnnotationPostProcessor`
instead of direct property access which might not be initialized yet
* Use a plain `boolean` for `templateInitialized` in the `MessagePublishingInterceptor`
to avoid skips in other thread where and move on with still not initialized properties
* * Remove unused import
* * Fix `this.` prefix for `beanFactory` property reference
* Add observation for message channels
* Add observation for message channels
The `MessageChannel.send()` is, essentially, only the point in Spring Integration where we produce a message
and can emit a `PRODUCER` kind span.
* Implement `IntegrationObservation.PRODUCER` infrastructure based on the `MessageSenderContext`
* Implement an observation emission in the `AbstractMessageChannel` based on the mentioned `IntegrationObservation.PRODUCER`
* Build a `MutableMessage.of(message)` to be able to modify message header in the `MessageSenderContext` via tracer `Propagator`
or other tracing injection instrument
* Document which components are instrumented with an `ObservationRegistry`
* Fix language in docs
Co-authored-by: Gary Russell <grussell@vmware.com>
Co-authored-by: Gary Russell <grussell@vmware.com>
Turns out the AOT engine deals only with indexed constructor arguments for bean definition
* Rework `GatewayProxyInstantiationPostProcessor.processAheadOfTime()`
to populate a service interface type as an indexed ctor argument instead of generic one
Fixes https://github.com/spring-projects/spring-integration/issues/3686
* Add `src/idea` with respective editor config for IntelliJ IDEA.
Must be imported into an IDE
* Add `src/eclipse` with respective editor config for Eclipse/STS
* Reformat imports in source code according a new editor config
The `GatewayProxyInstantiationPostProcessor` does nothing on the AOT phase.
Therefore, scanned and imported beans for `@MessagingGateway` are not decorated
after AOT
* Implement a `BeanRegistrationAotProcessor` in the `GatewayProxyInstantiationPostProcessor`
to `RegisteredBean.getMergedBeanDefinition()` withe respective `AnnotationGatewayProxyFactoryBean`
and its requirements for ctor arg and `targetType`
* Scan for the `@MessagingGateway` bean in the `GatewayProxyInitializationAotProcessor`
to register respective proxy hints