How to do integration test with activemq and spring3? - spring

I have a code like this, but I'm not sure how would I test this piece of of code that I extracted from my project. I'm using Spring3 and ActiveMQ. And I'm using spring to do remote HTTPInvoker that's why I have the GateWay. So, when I call method submit in my Gateway, it's going to send a JMS message via JMSDispatcher. How would you inject JmsTemplate to Gateway? As far as I know, if I want to test JMS I have to configure it in application-context.xml in Spring and inject overridden JmsTemplate. So, I could test the message inside the queue? But I can't inject JmsTemplate to Gateway since Mockito will complain about not having that field inside Gateway.
public class Gateway {
#Autowired
private ProcessController processController;
public void submit() {
processControllerFactory.submit();
}
}
public ProcessController {
#Autowired
private JMSDispatcher jmsDispatcher;
public void submit() {
// do something
jmsDispatcher.send(message);
}
}
public JMSDispatcher {
#Autowired
#Qualifier("someJmsTemplate")
private JmsTemplate jmsTemplate;
public void send(MessageCreator message) {
jmsTemplate.send(message);
}
}

Related

Intercepting Camel #Consume

I have an existing application which is using Apache Camel to send messages to SEDA endpoints for Async processing and would like to intercept calls to these methods for instrumentation.
Example code:
#Component
public class CamelMessageService {
private static final Logger log = LoggerFactory.getLogger(CamelMessageService.class);
public static final String QUEUE = "seda:message";
#Resource
private ProducerTemplate producerTemplate;
public void send() {
producerTemplate.sendBody(QUEUE, "Hello World");
}
#Consume(uri = QUEUE)
public void receive(#Body String payload) {
log.info("Received message {}", payload);
}
}
Is there a way to intercept all methods annotated with #Consume before invoking. I looked at an AOP based approach but this seemed to fall over due to existing Spring/Camel proxying of these classes.
I have also tried using various Camel Intercept routes and adding a custom InterceptStrategy but it seems that the example above does not create a Camel route so is not intercepted.
EDIT: On further investigation in seems that these endpoints can be Intercepted using camel but only if there is at least 1 other route defined in the Camel Context?
#Component
class MyRouteBuilder extends RouteBuilder {
private static final Logger log = LoggerFactory.getLogger(MyRouteBuilder.class);
public void configure() {
interceptSendToEndpoint(CamelMessageService.QUEUE)
.process(exchange -> log.info("intercepted exchange {}", exchange));
from("timer:hello?period={{timer.period}}").routeId("hello").routeGroup("hello-group")
.transform().simple("yo")
.filter(simple("${body} contains 'foo'"))
.to("log:foo")
.end()
.to("stream:out");
}
}
If I run this app with the Route Builder above then my interceptor is triggered if however I comment out the hello route it is not?
Any help would be greatly appreciated.

Spring event notify all scoped beans possible?

The Spring event mechanism supports publishing application events and listening to these events. as it is explained in this question: Scoped Spring events possible? spring event notify only the current request session listeners. so my question is that possible to notify all existent scoped beans.
code example:
#Controller
public class FooController {
#Autowired
private ApplicationEventPublisher publisher;
#GetMapping("/fireEvent")
public void notifyAllScopedBeans() {
publisher.publishEvent(new FooEvent(this));
}
}
#SessionScope
#Component
public class FooListener {
private String username = "this bean username"
#EventListener(FooEvent.class)
public void listen() {
System.out.println("I'm listening. PS : I am
"+this.username);
}
}

push a dynamic message in Scheduler websocket using spring boot using stomp

I try to make a chatbot using springboot (websocket), i want to know if it's possible to push a dynamic message in Scheduler, and i need some help, i'can't fugure it out.
I want to push the message in the Scheduler Configure how could i do that:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
template.convertAndSend("/topic/user", new UserResponse("Fixed Delay Scheduler"));
}
}
in the sendAdhocMessages method i want to pass a message that will be displayed in an html page. in the Official doc it's impossible to pass a parameter to a method which is annotated by #Scheduled, is there any methd to do that?
The official documentation contains a hint to, how you could pass values to the scheduled method. Maybe you could provide a bean that acts as a message provider. In the scheduler class you autowire the message provider and request the messages.
A short code example:
#Componet
public class MessageProvider {
private String message;
// getter and setter ...
}
In the scheduler you could use the message provider like following:
#EnableScheduling
#Configuration
public class SchedulerConfig {
#Autowired
SimpMessagingTemplate template;
#Autowired
MessageProvider messageProvider;
#Scheduled(fixedDelay = 3000)
public void sendAdhocMessages() {
String currentMessage = messageProvider.getMessage();
template.convertAndSend("/topic/user", new UserResponse(currentMessage));
}
}

Apache Camel Spring Javaconfig Unit Test No consumers available on endpoint

I have the following route configuration:
#Component
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:in").to("direct:out");
}
}
When I try to test it:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyRouteTest.TestConfig.class }, loader = CamelSpringDelegatingTestContextLoader.class)
#MockEndpoints
public class MyRouteTest {
#EndpointInject(uri = "mock:direct:out")
private MockEndpoint mockEndpoint;
#Produce(uri = "direct:in")
private ProducerTemplate producerTemplate;
#Configuration
public static class TestConfig extends SingleRouteCamelConfiguration {
#Bean
#Override
public RouteBuilder route() {
return new MyRoute();
}
}
#Test
public void testRoute() throws Exception {
mockEndpoint.expectedBodiesReceived("Test Message");
producerTemplate.sendBody("Test Message");
mockEndpoint.assertIsSatisfied();
}
}
I get this exception:
org.apache.camel.component.direct.DirectConsumerNotAvailableException:
No consumers available on endpoint: Endpoint[direct://out].
Exchange[Message: Test Message]
It looks like the Mock is not picking up the message from the endpoint.
What am I doing wrong?
The problem is that mock endpoints just intercept the message before delegating to the actual endpoint. Quoted from the docs:
Important: The endpoints are still in action. What happens differently
is that a Mock endpoint is injected and receives the message first and
then delegates the message to the target endpoint. You can view this
as a kind of intercept and delegate or endpoint listener.
The solution to your problem is to tell certain endpoints (the ones that expect a consumer in your case) not to delegate to the actual endpoint. This can easily be done using #MockEndpointsAndSkip instead of #MockEndpoints:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyRouteTest.TestConfig.class }, loader = CamelSpringDelegatingTestContextLoader.class)
#MockEndpointsAndSkip("direct:out") // <-- turns unit test from red to green ;)
public class MyRouteTest {
// ....
}
This issue because, in your route configuration, there is no route with "direct:out" consumer endpoint.
add a line like some thing below,
from("direct:out").("Anything you want to log");
So that direct:out will consume the exchange and In your test, mock will be able check the received text without any issues. Hope this helps !!

Problems injecting a BayeuxService into another class with annotations

I have a web app that is using Bayeux to handle Comet connections. I initialize a BayeuxServer and tie it into Spring annotations and it all works fine, listening on selected channels and responding.
I have a Jersey annotated class and an annotated Bayeux service as shown below. The idea is I wanted to be able to control resources via Rest from an individual web app, and then right after the resource is changed, do a server push via Comet to all other applicable clients to tell them to update their information.
Here is the problem: A Bayeux Service is created when the webapp is deployed, setting up proper channels to listen on and monitoring clients. There should only be one instance of this. When Jersey attempts to use the Bayeux service it creates a whole new service, when it should be using the original one. This new service doesn't have the BayeuxServer properly injected so I can't access client information through it.
It makes since that this should be doable, but I don't seem to understand how to inject these things properly via annotations. Can anyone point me in the right direction?
Jersey Annotated Class:
#Path("JsonTest")
public class JsonTest {
#Context
Request request;
#Context
UriInfo uriInfo;
#Context
ResourceContext resourceContext;
protected final Logger log = Logger.getLogger(getClass());
public JsonTest() {
}
#DELETE
#Path("{id}")
public void deleteJson(#PathParam("id") String id) {
JsonTestDao.instance.getModel().remove(id);
log.info("Deleted Json..." + id);
log.info("New json: " + JsonTestDao.instance.getModel().toString());
JsonTestService jsonTestService = resourceContext.getResource(JsonTestService.class);
jsonTestService.sendUpdate();
}
}
BayeuxService:
#Named
// Singleton here didn't seem to make a difference
#Service
public class JsonTestService {
protected final Logger log = Logger.getLogger(getClass());
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#PostConstruct
public void init() {
log.info("Initializing JsonTest Bayeux HelloService...");
log.info("Current sessions are: " + bayeux.getSessions().toString());
}
#Listener("/cometd/JsonTest")
public void jsonTestHandler(ServerSession remote, ServerMessage.Mutable message) {
}
public void sendUpdate() {
//bayeux.newMessage(); // Need a method that the Jersey class can call to notify changes
log.info("Bayeux server should be sending an update now...");
}
#PreDestroy
public void destroy() {
log.info("Destroying JsonTest Bayeux HelloService...");
}
}
See Jersey and spring integration - bean Injections are null at runtime.
Another question I asked. Both of these stem from the same problem involving properly setting the Jersey dependency and integrating it with spring.

Resources