Mocking bean endpoints with method option in uri - spring

I have an application build using Apache Camel 2.15.3. And I'm wiring the routes using spring-xml for dependency injection. I'm trying to write a test where I mock an endpoint that is a bean and has a method option in the uri.
My routes looks like this:
<onException id="Exception">
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<to uri="direct:fear"/>
</onException>
<route id="happyStory">
<from uri="direct:inTheBeginning"/>
<to uri="bean:enchantedKingdom?method=warn" />
<to uri="bean:fluffykins" />
</route>
<route id="scaryStory">
<from uri="direct:fear"/>
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
<to uri="bean:monster"/>
<choice>
<when>
<simple>${header.succesfullywarned}</simple>
<to uri="bean:enchantedKingdom?method=hide"/>
</when>
<otherwise>
<to uri="bean:enchantedKingdom?method=panic" />
</otherwise>
</choice>
</route>
And I wan't to be able to say that when the bean method warn is called then the header "succesfullywarned" should be set in the message and then when the bean fluffykins is called there should be a exception that causes the message to get sent to "scaryStory" and in this case I wan't to assert that the bean method 'panic' is called.
This is the test:
#RunWith(CamelSpringJUnit4ClassRunner.class)
#ContextConfiguration({"/META-INF/spring/route-stories.xml","/META-INF/spring/beans.xml"})
#MockEndpointsAndSkip("(bean:fluffykins|bean:monster|bean:enchantedKingdom?method=warn|bean:enchantedKingdom?method=hide|bean:enchantedKingdom?method=panic)")
public class StoryHappyRouteTest extends CamelSpringTestSupport {
private String url = "direct:inTheBeginning";
#Autowired
private ApplicationContext applicationContext;
#Override
protected AbstractApplicationContext createApplicationContext() {
return (AbstractApplicationContext)applicationContext;
}
#Test
public void test(){
MockEndpoint warn = getMockEndpoint("mock:bean:enchantedKingdom?method=warn");
MockEndpoint fluffy = getMockEndpoint("mock:bean:fluffykins");
MockEndpoint monster = getMockEndpoint("mock:bean:monster");
MockEndpoint hide = getMockEndpoint("mock:bean:enchantedKingdom?method=hide");
MockEndpoint panic =
getMockEndpoint("mock:bean:enchantedKingdom?method=panic");
fluffy.whenAnyExchangeReceived(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Bunny!");
throw new NullPointerException();
}
});
template.sendBody(url,"");
warn.assertExchangeReceived(0);
fluffy.assertExchangeReceived(0);
monster.assertExchangeReceived(0);
panic.assertExchangeReceived(0);
}
}
It works fine for all the beans except the enchantedKingdom bean, that contains multiple methods that are used in the route. A mock is not used in this case but the real bean method is called, which is not what I wan't. And the test fails since since it is not the mock that gets called in the route.
How can I get the test to use a mock for the endpoits with uri 'bean:enchantedKingdom?method=warn', 'bean:enchantedKingdom?method=hide' and 'bean:enchantedKingdom?method=panic'?

I would change the test approach and not try to mock calls to beans.
Instead, create a mocked bean instance and use that in your test.
Define a mocked bean (by code or mocking library)
public class MockEnchantedKingdom {
public boolean panicCalled = false;
public void panic() {
// do things
panicCalled = true;
}
}
Then declare this bean in spring files used for testing purposes
#ContextConfiguration(
{"/META-INF/spring/route-stories.xml",
"/META-INF/spring/beans-test1.xml"})
And in your test code get the bean and assert what you need
// context is CamelContext you should have access to it
MockEnchantedKingdom enchantedKingdom = (MockEnchantedKingdom) context.getRegistry().lookupByName("enchantedKingdom");
Assert.asserttrue(enchantedKingdom.panicCalled);
Create a different beans-test*.xml for different tests, and you may create the mocks using Mockito or any other library.
The route code is always the same and you can control behaviour of beans in each test.

Related

Apache Camel: set an object dependency before operation with Spring

In this example, I am trying to set the object dependency before calling businessLogic. I am receiving a nullpointer because that 'consumer' object is not set.
Here is the basis of the example and mostly trying to use the Spring DSL.
http://camel.apache.org/polling-consumer
Section: Timer based polling consumer
Here is my camel/spring config:
<bean id="simpleOutboxMessageConsumer" class="org.berlin.camel.esb.logs.mq.SimplePrintMessageConsumer"/>
<!-- Continue with spring dsl for ESB -->
<camelContext id="myCamel" xmlns="http://camel.apache.org/schema/spring">
<!-- Define a MQ consumer template -->
<consumerTemplate id="consumer" />
....
</camelContext>
<route id="fromOutboxAndConsume">
<from uri="timer://foo?period=30000" />
<to uri="bean:simpleOutboxMessageConsumer?method=businessLogic" />
</route>
Java code
#Component
public class SimplePrintMessageConsumer {
private static final Logger logger = Logger.getLogger(SimplePrintMessageConsumer.class);
private int count;
#Autowired
private ConsumerTemplate consumer;
public void setConsumer(final ConsumerTemplate consumer) {
this.consumer = consumer;
}
public void businessLogic() {
logger.info("Launching business logic to consume outbox, blocking until we get a message >>>");
while (true) {
// Consume the message
final String msg = consumer.receiveBody("activemq:queue.outbox", 3000, String.class);
logger.info("Printing message found from queue: " + msg);
if (msg == null) {
// no more messages in queue
break;
}
}
}
}
There is a nullpointer at the usage of the consume object. I am thinking that spring is not just autowiring that bean properly. Even if I didn't use spring, how would I pass the consumer template object to this bean?
This should work
<bean id="simpleOutboxMessageConsumer" class="....SimplePrintMessageConsumer">
<property name="consumer" ref="consumer"/>
</bean>
Remove the #AutoWire , I am checking on why the #Autowire is not working by the way

Camel, Spring, OSGI: Is there a way to specify the stop method?

I'm running a Camel Spring OSGI application. The Camel context is initialized through Spring.
When the bundle stops, I need to do some clean-up activities, like de-registering the message listener. How do I do that? Is there a method I can override? I understand that an OSGI bundle must provide the activator start and stop methods but my understanding also is that the Camel/Spring/OSGI framework overrides these methods.
My beanx.xml:
<beans>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="outboundBuilder" />
</camelContext>
</beans>
My java code:
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
.....
}
}
Just to expand a little on the answer of Bilgin Ibryam which is correct.
Camel has the ability to apply a policy to a route. This Policy controls routes at runtime. This will allow you to do custom logic at certain events of the route life time.
Implementing a route policy.
It is rather simple declare a new class which extends RoutePolicySupport then override the methods you are interested in.
public class MyRoutePolicy extends RoutePolicySupport{
#Override
public void onStart(Route route) {
// TODO Auto-generated method stub
super.onStart(route);
}
#Override
public void onStop(Route route) {
// TODO Auto-generated method stub
super.onStop(route);
}
#Override
public void onExchangeBegin(Route route, Exchange exchange) {
// TODO Auto-generated method stub
super.onExchangeBegin(route, exchange);
}
}
Now use the route in your routebuilder configure() method like this:
RoutePolicy policy = new MyRoutePolicy();
from("timer://blah")
.routeId("Test1").routePolicy(policy)
.setBody().constant("A Message Like Hello World")
.to("mock:meh");
If you were just using a Spring XML with a route then add the following:
<bean id="policy" class="MyRoutePolicy"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="foo" routePolicyRef="MyRoutePolicy">
<from uri="timer://blah"/>
<setBody><constant>A Message Like Hello World</constant></setBody>
<to uri="mock:meh"/>
</route>
</camelContext>
You can use Camel Route policy and write your code to cleanup resource when the route is about to stop or be removed from the context.

Spring 3.0 MVC Handler Interceptors not working

I am trying out the HandlerInterceptors from Spring MVC 3.0.
Below is my interceptor
public class SessionInterceptor extends HandlerInterceptorAdapter {
#Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("inside preHandle");
if(request.getSession().getAttribute(SessionConsta nts.USER_SESSION_NAME) == null) {
response.sendRedirect("welcome");
return false;
}
return true;
}
}
Below is my configuration in my xml
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/services/*"/>
<bean class="com.ca.myca.interceptors.SessionInterceptor " />
</mvc:interceptor>
</mvc:interceptors>
But the interceptor is not getting called.
Please let me know if I am missing any thing.
In our application we are using double ** for any service sub-path match, so try changing it and check if it helps:
<mvc:mapping path="/services/**"/>
You are using <mvc:annotation-driven/> with mvc interceptor.
Please check on Spring reference:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/DispatcherServlet.html
"When running in a Java 5+ environment, a default AnnotationMethodHandlerAdapter will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type)."
<mvc:annotation-driven/> is supposed to be used for annotation-driven MVC controllers like #RequestMapping, #Controller etc, but I have seen there is no need to define "<mvc:annotation-driven/>" for supporting it.
Unless you are using jackson (for json support), you can try to remove <mvc:annotation-driven/> and use "<context:annotation-config>" instead for common use like autowiring etc.
try what is suggested in Configuration of Spring MVC and JSON using Jackson.
Put you interceptor in <mvc:interceptors> tag
<mvc:interceptors>
<bean class="xx.x..x..x...UserSessionInterceptor" />
</mvc:interceptors>
you can keep <mvc:annotation-driven/> and <context:annotation-config>
In reference to the post above by arviarya, <mvc:annotation-driven /> in the config XML results in a different handler Object being passed to the interceptor. In our interceptor method we had:
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) throws Exception {
if (mav != null && handler instanceof HandlerMethod) {
// something we want to have happen
}
This was being called with the #Controller-derived object without the <mvc:annotation-driven />, but was called with the HandlerMethod-derivedobject when it was present. For our if block to work, I needed the tag in our config XML.

How to access Spring RequestContext from a Freemarker TemplateDirectiveModel

I'm using Spring MVC with Freemarker as view technologie. I have a TemplateDirectiveModel object which needs to access Spring's RequestContext within the execute method. Currently I do it like this:
public class MyDirective implements TemplateDirectiveModel
{
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException
{
StringModel model = (StringModel) env.getGlobalVariable("springMacroRequestContext");
RequestContext requestContext = (RequestContext) model.getWrappedObject();
}
}
But I can't believe that this is the right way to do it. I have the feeling I missed something important. Maybe there are special classes and annotations for handling Freemarker direcives in Spring? Maybe I can let Spring inject something into the directive class with which I can access Springs request scope?
You could subclass FreeMarkerConfigurer, overriding its postProcessConfiguration(Configuration config)method.
Your implementation would just put a request-aware dependency in the configuration, as a shared variable for example (as preconised by the FM documentation).
Should do the trick, Spring-style...
There is an easier way to do this. If you are already using spring's FreeMarkerConfigurer, you can hand it a map of variables:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
p:templateLoaderPath="/some_path_here">
<property name="freemarkerVariables">
<map>
<entry key='macroName' value-ref="templateModelRef" />
</map>
</property>
</bean>
<bean id="templateModelRef" class="...class..extends TemplateModel">
<property name="someResource" value-ref="resourceRef"/>
</bean>
Now at least in a class that extends TemplateDirectiveModel's execute method you have access to that injected property.
public class MyDirective extends TemplateDirectiveModel {
private MyResource someResource;
#Override
public void execute(Environment env, Map params, TemplateModel[] loopVars,TemplateDirectiveBody body) throws TemplateException, IOException {
StringModel sharedVariable = (StringModel)env.getConfiguration().getSharedVariable("beanName");
MyClass sweetness = (MyClass)sharedVariable.getWrappedObject();
}
}
Now in your .ftl you can use:
<#macroName />
and it will have spring dependencies auto injected.

Spring #Autowiring with generic factory-built beans

I have a set of classes with a complex initialization scheme. Basically, I start with the interface I need to get a hold of, and then make a bunch of calls, and I end up with an object that implements that interface.
In order to handle this, I made a factory class that can, given an interface, produce the final object. I made this factory into a bean, and in XML I specified my various service beans as being instantiated via this factory object with a parameter of the interface that they will implement.
This works great, and I totally get exactly the beans I need. Unfortunately, I would like to access them from my controller classes, which are discovered via component scanning. I use #Autowired here, and it appears that Spring has no idea what type of object these are, and since #Autowired works by type, I'm SOL.
Using #Resource(name="beanName") here would work perfectly, however it seems odd to use #Resource for some beans and #Autowired for others.
Is there a way to get Spring to know what interface the factory will be creating for each of these beans without having a different factory method for each type?
I'm using Spring 2.5.6, by the way, otherwise I'd just JavaConfig the whole thing and forget about it.
Factory class:
<T extends Client> T buildService(Class<T> clientClass) {
//Do lots of stuff with client class and return an object of clientClass.
}
app context:
<bean id="serviceFactoryBean" class="com.captainAwesomePants.FancyFactory" />
<bean id="userService" factory-bean="serviceFactoryBean" factory-method="buildService">
<constructor-arg value="com.captain.services.UserServiceInterface" />
</bean>
<bean id="scoreService" factory-bean="serviceFactoryBean" factory-method="buildService">
<constructor-arg value="com.captain.services.ScoreServiceInterface" />
</bean>
my controller:
public class HomepageController {
//This doesn't work
#Autowired #Qualifier("userService") UserServiceInterface userService;
//This does
#Resource(name="scoreService") ScoreServiceInterface scoreService;
}
I suggest you take the factory pattern one step further and implement your factories as Spring FactoryBean classes. The FactoryBean interface has a getObjectType() method which the contain calls to discover what type the factory will return. This gives your autowiring something to get its teeth into, as long as your factory returns a sensible value.
I had a similar problem, but for me I wanted to use a single factory for creating mocked-out implementations of my auto-wired dependencies using JMockit (the testing framework that I am required to use).
After finding no satisfactory solution on the interwebs, I threw together a simple solution that is working really well for me.
My solution uses a Spring FactoryBean as well, but it only uses a single factory bean for creating all my beans (which the original asker seems to have wished to do).
My solution was to implement a factory-of-factories meta-factory that serves-up FactoryBean wrappers around the real, single factory.
Here is the Java for my JMockit mock bean factory:
public class MockBeanFactory<C> implements FactoryBean<C> {
private Class<C> mockBeanType;
protected MockBeanFactory(){}
protected <C> C create(Class<C> mockClass) {
return Mockit.newEmptyProxy(mockClass);
}
#Override
public C getObject() throws Exception {
return create(mockBeanType);
}
#Override
public Class<C> getObjectType() {
return mockBeanType;
}
#Override
public boolean isSingleton() {
return true;
}
public static class MetaFactory {
public <C> MockBeanFactory<C> createFactory(Class<C> mockBeanType) {
MockBeanFactory<C> factory = new MockBeanFactory<C>();
factory.mockBeanType = mockBeanType;
return factory;
}
}
}
And then in the Spring context XML file, you just can simply create the meta factory that creates the specific bean-type factories:
<bean id="metaFactory" class="com.stackoverflow.MockBeanFactory$MetaFactory"/>
<bean factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="mockBeanType" value="com.stackoverflow.YourService"/>
</bean>
To make this work for the original asker's situation, it could be tweaked to make the FactoryBeans into wrappers/adapter for the serviceFactoryBean:
public class FancyFactoryAdapter<C> implements FactoryBean<C> {
private Class<C> clientClass;
private FancyFactory serviceFactoryBean;
protected FancyFactoryAdapter(){}
#Override
public C getObject() throws Exception {
return serviceFactoryBean.buildService(clientClass);
}
#Override
public Class<C> getObjectType() {
return clientClass;
}
#Override
public boolean isSingleton() {
return true;
}
public static class MetaFactory {
#Autowired FancyFactory serviceFactoryBean;
public <C> FancyFactoryAdapter<C> createFactory(Class<C> clientClass) {
FancyFactoryAdapter<C> factory = new FancyFactoryAdapter<C>();
factory.clientClass = clientClass;
factory.serviceFactoryBean = serviceFactoryBean;
return factory;
}
}
}
Then in the XML (notice the userServiceFactory id and the userService bean id are necessary only to work with the #Qualifier annotation):
<bean id="metaFactory" class="com.stackoverflow.FancyFactoryAdapter$MetaFactory"/>
<bean id="userServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="clientClass" value="com.captain.services.UserServiceInterface"/>
</bean>
<bean id="userService" factory-bean="userServiceFactory"/>
<bean id="scoreServiceFactory" factory-bean="metaFactory" factory-method="createFactory">
<constructor-arg name="clientClass" value="com.captain.services.ScoreServiceInterface"/>
</bean>
<bean id="scoreService" factory-bean="scoreServiceFactory"/>
And that's it, just one little Java class and a smidge of boiler-plate configuration and your custom bean factory can create all of your beans and have Spring resolve them successfully.
You should be able to achieve this using:
<bean id="myCreatedObjectBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass">
<value>com.mycompany.MyFactoryClass</value>
</property>
<property name="targetMethod">
<value>myFactoryMethod</value>
</property>
</bean>
Then you can use either #Resource or #Autowired + #Qualifier to inject into your object directly.

Resources