How to use RabbitListenerEndpointRegistry? - spring

I wanted to destory my specific RabbitListener...
So I searched and most of people used this way.
#Autowired
RabbitListenerEndpointRegistry endpointRegistry;
endpointRegistry.getListenerContainer( "listener_id" ).stop();
But endpointRegistry didn't have any container...
endpointRegistry.getListenerContainers().size() = 0
And I also made a Bean like this in RabbitMqConfiguration.
#Bean
#Qualifier( "RabbitListenerEndpointRegistry" )
public RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry(){
return new RabbitListenerEndpointRegistry();
}
how to fix it ???
#Autowired
RabbitListenerEndpointRegistry endpointRegistry;
endpointRegistry.getListenerContainer( "listener_id" ).stop();
#Bean
#Qualifier( "RabbitListenerEndpointRegistry" )
public RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry(){
return new RabbitListenerEndpointRegistry();
}

You don't need to declare your own RabbitListenerEndpointRegistry - the framework does that for us via RabbitBootstrapConfiguration, when #EnableRabbit is provided on a #Configuration.
Then your #RabbitListener with that listener_id is going to be registered into that global registry and somewhere at runtime you will be able to stop it.

Related

Retrieve all key-value pairs from properties file in Spring Boot with a given prefix and suffix

I have been trying for sometime now. I want to read from the properties file and store as a hashmap.
Here is an example.
sample.properties
pref1.pref2.abc.suf = 1
pref1.pref2.def.suf = 2
...
...
Here is the Config class.
#ConfiguraionProperties
#PropertySource(value = "classpath:sample.properties")
public class Config{
#Autowired
private Environment env;
public HashMap<String, Integer> getAllProps(){
//TO-DO
}
}
I want to be able to return {"abc":1, "def":2};
I stumbled upon answers like using PropertySources, AbstractEnvironment etc., but still can't get my head around using it.
Thanks in advance!
The class
org.springframework.boot.actuate.endpoint.EnvironmentEndpoint
reads all configured properties and puts them in a Map.
This is used to return all properties and their values from a REST endpoint. See production ready endpoints
You can copy the 3 methods that build the Map with all properties from class EnvironmentEndpoint into your own. Then just iterate over the Map and select all properties by their key.
I have done that in one project, worked quite well.
its possible using spring boot #component, #PropertySource and #ConfigurationProperties
create a component like
#Component
#PropertySource(value = "classpath:filename.properties")
#ConfigurationProperties(prefix = "pref1")
public class Properties{
/**
*should be same in properties pref1.pref2.abc.suf = 1
*It will give u like abc.suf = 1 , def.suf = 2
*/
private Map<String,String> pref2;
//setter getter to use another place//
public Map<String, String> getPref2() {
return pref2;
}
public void setPref2(Map<String, String> pref2) {
this.pref2= pref2;
}
}
use in other class suing #autowired
public class PropertiesShow{
#Autowired
private Properties properties;
public void show(){
System.out.println(properties.getPref2());
}
}

Spring Data Key Value Implementation for Oracle KV

I would like to use Oracle NoSQL database together with Spring data. The aim is to access the data over spring data repositories and even use spring data rest on top of it.
So I think the spring-data-keyvalue project would help me, to implement an adapter for Oracle NoSQL KV.
I tried to understand the documentation of spring-data-keyvalue (http://docs.spring.io/spring-data/keyvalue/docs/current/reference/html/#key-value.core-concepts), but didn't get the idea.
An example/tutorial about how to implement an adapter from scratch would be very helpful.
What I have is this configuration class where I provide a custom KeyValueAdapter. Now if I use CrudRepository methods it uses my custom adapter.
#Configuration
#EnableMapRepositories
public class KeyValueConfig {
#Bean
public KeyValueOperations keyValueTemplate() {
return new KeyValueTemplate(new OracleKeyValueAdapter());
}
}
The OracleKeyValueAdapter is an implementation of KeyValueAdapter. I got this from the spring-data-keyvalue-redis project (https://github.com/christophstrobl/spring-data-keyvalue-redis/blob/master/src/main/java/org/springframework/data/keyvalue/redis/RedisKeyValueAdapter.java)
public class OracleKeyValueAdapter extends AbstractKeyValueAdapter {
private KVStore store;
public OracleKeyValueAdapter() {
String storeName = "kvstore";
String hostName = "localhost";
String hostPort = "5000";
store = KVStoreFactory.getStore
(new KVStoreConfig(storeName, hostName + ":" + hostPort));
}
//Custom implementations:
#Override
public Object put(Serializable serializable, Object o, Serializable
serializable1) {
return null;
}
#Override
public boolean contains(Serializable serializable, Serializable
serializable1) {
return false;
}
.
.
.
Now I'm trying to implement this OracleKeyValueAdapter, but i don't know if that does even make sense.
Can you help me?
You might want to start with how spring-data-keyvalue is implemented over Redis, the link here should be a good starting point - http://docs.spring.io/spring-data/data-keyvalue/docs/1.0.0.BUILD-SNAPSHOT/reference/redis.html
Let me know how that goes, I am interested in what you are trying to accomplish.
The following configuration should work (tested on v2.4.3)
#Configuration
#EnableMapRepositories
public class Configuration {
#Bean
public KeyValueOperations mapKeyValueTemplate() {
return new KeyValueTemplate(keyValueAdapter());
}
#Bean
public KeyValueAdapter keyValueAdapter() {
return new YourKeyValueAdapter();
}
}
The name (mapKeyValueTemplate) of the KeyValueOperations bean is important here but it can also be changed as followed:
#Configuration
#EnableMapRepositories(keyValueTemplateRef = "foo")
public class Configuration {
#Bean
public KeyValueOperations foo() {
return new KeyValueTemplate(keyValueAdapter());
}
#Bean
public KeyValueAdapter keyValueAdapter() {
return new YourKeyValueAdapter();
}
}
I saw sources of Spring KeyValue Repository:
https://github.com/spring-projects/spring-data-keyvalue
I recomend to understand, how Spring Repository work inside.
If you want to realise own repository (CustomKeyValueRepository), you must create at least 6 classes:
EnableCustomKeyValueRepositories - annotation to enable repository type in your project.
CustomKeyValueRepositoriesRegistrar - registrator for this annotaion.
CustomKeyValueRepository - repository
CustomKeyValueRepositoryConfigurationExtension - implementation of Spring ConfigurationExtension.
CustomKeyValueAdapter - implementation of custom adapter for your data store.
CustomKeyValueConfiguration - configuration of beans Adapter and Template.
I code Infinispan KeyValue Repository by this way:
https://github.com/OsokinAlexander/infinispan-spring-repository
I also write article about this:
https://habr.com/ru/post/535218/
In Chrome you can translate it to your language.
The simplest way you can try implement only CustomKeyValueAdapter and Configuration. In Configuration you must redefine Spring KeyValueAdapter bean and KeyValueTemplate (it is very important that the name of the bean is with a lowercase letter, that's the only way it worked for me):
#Configuration
public class CustomKeyValueConfiguration extends CachingConfigurerSupport {
#Autowired
private ApplicationContext applicationContext;
#Bean
public CustomKeyValueAdapter getKeyValueAdapter() {
return new CustomKeyValueAdapter();
}
#Bean("keyValueTemplate")
public KeyValueTemplate getKeyValueTemplate() {
return new KeyValueTemplate(getKeyValueAdapter());
}
}

Spring listener after ConfigurationPropertiesRebinder handler

I'm trying to reconfigure the SchedulerFactoryBean on EnvironmentChangeEvent(I'm posting to /refresh endpoint).
The problem is that my listener is called before ConfigurationPropertiesRebinder handler and I'm getting not up-to-date configuration properties. They are defined with refresh scope :
#RefreshScope
#ConfigurationProperties("pnr2xdf")
public class MyProperties{
public String triggerExpression;
}
My EnvironmentChangeEvent handler bean is defined with #Order(value = Ordered.LOWEST_PRECEDENCE) but this doesn't help as ConfigurationPropertiesRebinder has the same order.
I know that I can explicitly force rebinding with ConfigurationPropertiesRebinder.rebind() but this will cause rebind being called twice.
What is the recommended way to achieve this?
Thanks
#AutoConfigureAfter(name = "org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration")
public class ConfigChangeListenerAutoConfiguration {
#Bean
#ConditionalOnClass(name = "org.springframework.cloud.context.environment.EnvironmentChangeEvent")
public DemoConfigChangeListener demoConfigChangeListener() {
return new DemoConfigChangeListener();
}
}

How to replace a constructor injected object with mocked object in spock

I know that the question is very big but I just want to clear the situation i am into.
I am working on an application that consumes the JMS messages from the message broker.
We are using camel route on the consumer side. All the object required in route builder are injected through constructor injection using spring .
I want to mock the behavior of the actual processing, Once the consumer receives the message from the queue. All the classes gets loaded via the spring configuration.
Below are the three classes:
CustomRouteBuilder.java
public CustomRouteBuilder extends RouteBuilder{
private CustomRouteAdapter customAdapter;
public CustomRouteBuilder (CustomRouteAdapter customAdapter){
this.customAdapter = customAdapter
}
public void configure(RouteDefinition route){
route.bean(customAdapter);
}
}
CustomRouteAdapter.java
public class CustomRouteAdapter {
private Orchestrator orchestrator;
public CustomRouteAdapter (Orchestrator orchestrator){
this.orchestrator = orchestrator;
}
#Handler
public void process(String message){
orchestrator.generate(message) ;
}
}
Orchestrator.java
public class Orchestrator{
private Service service;
public Orchestrator(Service service){
this.service = service;
}
public void generateData(String message){
service.process(message);
}
}
As per our requirement we have to load this configuration file and then write the functional test using spock.
Below is my
CustomRouteBuilderTest.groovy file.
import org.springframework.test.util.ReflectionTestUtils
import spock.lang.Specification
#ContextConfiguration(classes=[CustomRouteBuilderTest.Config.class])
class CustomRouteBuilderTest extends Specification{
private static final String message = "Hello";
Orchestrator orchestrator;
#Autowired
CustomRouteAdapter customRouteAdapter;
def setup(){
orchestrator = Mock(Orchestrator)
ReflectionTestUtils.setField(customRouteAdapter,"orchestrator",orchestrator)
orchestrator.generate(message )
}
private String getMessageAsJson() {
//return json string;
}
private String getMessage() {
// return message;
}
private Map<String, Object> doMakeHeaders() {
//Create message headers
}
private void doSendMessage(){
Thread.sleep(5000)
Map<String,Object> messageHeader = doMakeHeaders()
byte [] message = getMessageAsJson().getBytes()
CamelContext context = new DefaultCamelContext()
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(jmsBrokerUrl)
context.addComponent("activeMQComponent",JmsComponent.jmsComponent(connectionFactory))
ProducerTemplate template = context.createProducerTemplate()
context.start();
template.sendBodyAndHeaders("queueName", message, messageHeader)
}
def "test message consumption"(){
given:
doSendMessage()
}
#Configuration
#Import([FunctionalTestCommonConfig.class,CustomRouteBuilderConfig.class])
#PropertySource(value="classpath:test.properties")
static class Config{
}
}
The problem that here is even though I inject the mocked object to the adapter using ReflectionTestUtils , I am not able to define its behavior correctly.
And when the message is received the orchestrator tries to process it.
My Requirement is that:
Adapter should be called from the camel route automatically which happens but
when the orechestrator.generate is called from the adapter then nothing should happen it should simply return.
But here nothing like that is going on.
Each time I send a message the consumer(RouteBuilder) receives it and calls the handler function which then calls the
orchestrator.generate(message)
function and the orchestrator starts processing and throws an exception from service level.
Any one can please help me on this.
I suppose your beans have been proxified by Spring, and this proxy use cglib (because you see CustomRouteBuilder$$EnhancerBySpringCGLIB$$ad2783ae).
If it's really the case, you didn't #Autowired in your test the real instance of your CustomRouteAdapter but a cglib proxy: Spring creates a new class, extending the realclass, and overriding all the methods of this class. The new method delegate to the real instance.
When you change the orchestrator field, you are in reality changing the orchestrator field of the proxy, which is not used by the real instance.
There are severals ways to achieve what you want to do:
add a setOrchestrator method in CustomRouteAdapter
create the mock in your spring configuration and let spring inject this mock instead of a real instance of Orchestrator
Inject the orchestrator in the real instance (ugly - I didn't recommend you that, it didn't help in the testability of your code!)
customRouteAdapter.targetSource.target.orchestrator = _themock_

Check which beans have loaded in spring context

I am having a series of odd errors in testing and deployment. They seem to indicate that some of my beans are not loading into the context, despite them being defined in applicationContext.xml.
Is there any way to check during testing which beans have actually been loaded? Or to find a complete list of beans loaded at run time?
Thanks,
b
At startup, Spring logs at info level the names of all the beans being loaded by a context. Or in code, you can use getBeanDefinitionNames() to get all the bean names.
if there is more than one context say if you are using spring mvc you can use something more powerful like this.
public class SampleContextApplicationListener implements ApplicationListener<ApplicationContextEvent> {
private Map<String,ApplicationContext> contextMap = new Hashtable<String,ApplicationContext>();
#Override
public void onApplicationEvent(ApplicationContextEvent event) {
if( event instanceof ContextStartedEvent || event instanceof ContextRefreshedEvent){
this.getContextMap().put(event.getApplicationContext().getDisplayName(), event.getApplicationContext());
}
}
public Map<String,ApplicationContext> getContextMap() {
return contextMap;
}
}
You can then inject the listener where it is needed, and extract the map of contextens and then interogate it for all its bean, using the getBeanDefinitionNames()
#Autowired
private StatusTestsApplicationListener listener;

Resources