Passing a Spring bean to a Camel component - spring

I have a custom component of type FooComponent which is added to the route by the following lines:
from("foo://bar?args=values&etc")
.bean(DownstreamComponent.class)
...
FooComponent creates an endpoint and consumer (of type FooConsumer) which in turn emits messages which get to the DownstreamComponent and the rest of the pipeline.
For monitoring, I need the FooComponent consumer to call a method on a non-Camel object, which I'm creating as a Spring bean. The Camel pipeline is very performance sensitive so I'm unable to divide the FooComponent into two halves and insert the monitor call as a Camel component between them (my preferred solution, since FooComponent shouldn't really have to know about the monitor). And I'm reluctant to turn the method call into a Camel Message that will be picked up by the monitoring component later in the pipeline, as the pipeline filtering becomes complicated later and I don't want to meddle with it more than necessary.
Somewhere inside FooConsumer, I have:
// in the class
#Autowired
Monitor monitor;
// inside the consumer's run method
monitor.noticeSomething();
The problem is that monitor will never be set to the Monitor bean which is created in the rest of the application. As I understand it, it's because FooConsumer itself is not visible to Spring -- an object of that type is created normally inside FooComponent.
So, how can I get FooComponent to find the Monitor instance that it needs to use?
Can I pass it in when the route is created? This seems tricky because the definition is a faux URL "foo://bar?args=values&etc"; I haven't found how to pass Java objects that way.
Can I get Spring to find that #Autowired annotation inside FooConsumer and inject the monitor object somehow?

If you have a singleton instance of Monitor you ought to be able to #Autowire it in the FooComponent class. As Camel will let Spring dependency inject when creating the FooComponent.
Then you can pass on the monitor instance when you create the endpoint / consumer from your component.

The easiest thing to do is to create a Monitor property on the FooComponent class, and wire it in like any other bean.
<bean id="monitorBean" class="my.Monitor"/>
<bean id="foo" class="my.FooComponent">
<property name="monitor" ref="monitorBean"/>
</bean>
Then in your FooConsumer, when you need to get hold of the monitor, call:
Monitor monitor = ((FooComponent) getEndpoint().getComponent()).getMonitor();
If you were changing the monitor bean on a per-endpoint basis, you could use Camel's nifty # syntax to locate a bean with that id, and inject it into an Endpoint property.
foo:something?monitor=#monitorBean
Then to use it in your FooConsumer you simply say:
Monitor monitor = ((FooEndpoint) getEndpoint()).getMonitor();

Related

In Spring Boot how do you register custom converters that are available when parsing application configuration?

In a Spring Boot application how do you register custom converts to be used when processing application configuration?
I have made a custom convert (org.springframework.core.convert.converter.Converter) so it can be used by the ApplicationConversionService/Binder to parse #ConfiguraitonProperties defined in application.properties and application.yaml configuration files but do not know how to register it.
I have tried the solution here https://stackoverflow.com/a/41205653/45708 but it creates an instance of my converter after the application configuration parameters have been processed.
I ran into this issue myself recently. From what I can tell, the key issue is that binding to configuration properties occurs very early in the Spring startup process, before the Application Context is fully initialized. Therefore the usual methods for registering a converter are not reliable. In fact the ConversionService used for configuration binding appear to be a one-off and not really connected to the ConversionService that is stored in the Application Context.
I was able to get something working but it feels like a hack, as it relies on internal implementation details that may work today but not tomorrow. In any case, this is the code I used:
((ApplicationConversionService) ApplicationConversionService.getSharedInstance()).addConverter(myCustomConverter);
The trick I found was to make sure this gets called as soon as possible at application startup so that it gets called before the configuration binding where it's needed. I put it in a #PostConstruct block inside my main #SpringBootApplication class as this seemed to get invoked early on, at least in my case.

Spring Boot: Retrieve config via rest call upon application startup

I d like to make a REST call once on application startup to retrieve some configuration parameters.
For example, we need to retrieve an entity called FleetConfiguration from another server. I d like to do a GET once and save the keep the data in memory for the rest of the runtime.
What s the best way of doing this in Spring? using Bean, Config annotations ..?
I found this for example : https://stackoverflow.com/a/44923402/494659
I might as well use POJOs handle the lifecycle of it myself but I am sure there s a way to do it in Spring without re-inventing the wheel.
Thanks in advance.
The following method will run once the application starts, call the remote server and return a FleetConfiguration object which will be available throughout your app. The FleetConfiguration object will be a singleton and won't change.
#Bean
#EventListener(ApplicationReadyEvent.class)
public FleetConfiguration getFleetConfiguration(){
RestTemplate rest = new RestTemplate();
String url = "http://remoteserver/fleetConfiguration";
return rest.getForObject(url, FleetConfiguration.class);
}
The method should be declared in a #Configuration class or #Service class.
Ideally the call should test for the response code from the remote server and act accordingly.
Better approach is to use Spring Cloud Config to externalize every application's configuration here and it can be updated at runtime for any config change so no downtime either around same.

Mule connector config needs dynamic attributes

I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.

Struts 2 tomcat request/session contamination

I am using Struts 2 v 2.3.16.3 with tomcat 6.
A user will click on an action which finds an object by id and the page displays it. I have encountered a sporadic bug where the user will all of a sudden get the id of another lookup from another user on another machine. So effectively they are both calling the same action but passing different id to the request, but both end up viewing the same id.
This is obviously disastrous, and the data is totally corrupted as both users think they are editing a different record. Any ideas how make sure session/request activity is kept secure to each session?
I am also using spring and am using the #Transactional annotation in my Service layer, which returns the objects from the DAO. Is there something I need to do with this annotation to make it secure for each session ?
I am using org.springframework.orm.hibernate3.HibernateTransactionManager
Classic Thread-UnSafe problem.
Since you nominated Spring, my first guess is that you have not specified the right scope for your action beans in Spring xml configuration.
Be sure you are using scope="prototype" because otherwise the default scope of Spring is Singleton, and you don't want a single(ton) instance of an Action, that would not be ThreadLocal (and hence ThreadSafe) anymore.
If it is not that, it could be something on an Interceptor (that, differently from an action, is not Thread Safe), or you are using something static (in your Business / DAO layer, or in the Action itself) that should be not.

How to unregister an OSGI/Blueprint Service from within the Service?

In my application I have a Service ChatProtocolClient. The implementation is a tcp client which connects to a remote server in the blueprint "init-method" and disconnects in the "destroy-method".
I also have another bundle that uses this ChatProtocolClient's connection to read and post messages from a channel, ChatChannel.
Currently I have an xml file that creates a bean of the ChatProtocolClient, and creates a bean ChatChannel in which a reference to the created ChatProtocolClient service is injected.
But how can I handle disconnects from the server? I'd want to tell the Blueprint framework that my ChatProtocolClient instance is unusable now and it should unregister this instance.
Preferably Blueprint would then automatically call the destroy-method on all dependent beans (beans in which Blueprint injected this service reference) and initialize a new ChatProtocolClient bean and all beans that were destroyed because the dependency failed.
How can this be done?
I found a way to implement this. In this solutions it's not Blueprint that recreates instances of all dependent services. It goes like this:
Connection "Watchdog" beans.
Instead of creating "ChatProtocolClient" Beans, I created ConnectionWatchDog beans from xml. In these beans the BundleContext is injected and the connection properties are set from the .xml file.
The ConnectionWatchDog then tries to create/connect a ChatProtocolClient instance. If connection succeeds, it registers a service in the BundleContext (with bundleContext.registerService(..)). The ServiceRegistration is kept in the watchdog. The watchdog tests the connection on set interval (it runs it's own Thread). If the connection appears to have failed; the watchdog calls the serviceRegistration.unregister() and cleans up the remainders of the client connection instance, ands starts the whole proces of creating, connecting and registering an new ChatProtocolClient instance.
The ChatChannel
The ChatChannel is now configured in Blueprint with a . The xml looks like this:
<blueprint xmlns=...>
<reference-list id="chat-connection" member-type="service-object" interface="com.example.ChatProtocolClientInterface">
<reference-listener bind-method="onBind" unbind-method="onUnbind" ref="Channel1"/>
</reference-list>
<bean id="Channel1" class="ChatChannel" init-method="startUp">
<property name="chatProtocolClient" ref="chat-connection">
... some other properties ...
</bean>
</blueprint>
The member-type set to service-object, means that when a service is registered or unregistered, the ChatChannel will be informed with the "onBind" and "onUnbind" methods. As parameter, they'll get a ChatProtocolClientInterface instance.
I'm not sure whether this is the only or best solution, but it works for me. Note that with this example xml, you'll also need a setter for "chatProtocolClient"; currently I don't use the list that is set by blueprint and I only use the onBind and onUnbind methods.

Resources