Camel REST Bean Chaining - java

I currently have a REST route builder that looks as follows:
rest("/v1")
.post("/create")
.to("bean:myAssembler?method=assemble(${in.header.content})")
.to("bean:myService?method=create(?)");
The bean myAssembler takes raw JSON and transforms this into MyObject. This object is then returned and I want it forwarded onto myService as a parameter for its create method.
How can I do this using Camel?

Your beans will bind automatically to specific parameters like Exchange if you put it as a parameter to a method (see complete list Parameter binding).
One solution would be to define your route and beans like this:
restConfiguration()
.component("restlet")
.bindingMode(RestBindingMode.json)
.skipBindingOnErrorCode(false)
.port(port);
rest("/v1")
.post("/create")
.route()
.to("bean:myAssembler?method=assemble")
.to("bean:myService?method=create");
with beans like this
public class MyAssembler {
public void assemble(Exchange exchange) {
String content = exchange.getIn().getHeader("content", String.class);
// Create MyObject here.
MyObject object; // ...transformation here.
exchange.getOut().setBody(object);
}
}
and this
public class MyService {
public void create(MyObject body) {
// Do what ever you want with the content.
// Here it's just log.
LOG.info("MyObject is: " + body.toString());
}
}
The dependencies for shown configuration are
org.apache.camel/camel-core/2.15.3
org.apache.camel/camel-spring/2.15.3
org.apache.camel/camel-restlet/2.15.3
javax.servlet/javax.servlet-api/3.1.0
org.apache.camel/camel-jackson/2.15.3
org.apache.camel/camel-xmljson/2.15.3
xom/xom/1.2.5

Actually, if last bean returns MyObject, next bean can accept and bind MyObject as first arg. You don't need to put it into Exchange body or anything.

Related

Dynamic Queues on RabbitListener Annotation

I'd like to use queue names using a specific pattern, like project.{queue-name}.queue. And to keep this pattern solid, I wrote a helper class to generate this name from a simple identifier. So, foo would generate a queue called project.foo.queue. Simple.
But, the annotation RabbitListener demands a constant string and gives me an error using my helper class. How can I achieve this (or maybe another approach) using RabbitListener annotation?
#Component
public class FooListener {
// it doesn't work
#RabbitListener(queues = QueueName.for("foo"))
// it works
#RabbitListener(queues = "project.foo.queue")
void receive(final FooMessage message) {
// ...
}
}
To create and listen to a queue name constructed from a dynamic UUID, you could use random.uuid.
The problem is that this must be captured to a Java variable in only one place because a new random value would be generated each time the property is referenced.
The solution is to use Spring Expression Language (SpEL) to call a function that provides the configured value, something like:
#RabbitListener(queues = "#{configureAMQP.getControlQueueName()}")
void receive(final FooMessage message) {
// ...
}
Create the queue with something like this:
#Configuration
public class ConfigureAMQP {
#Value("${controlQueuePrefix}-${random.uuid}")
private String controlQueueName;
public String getControlQueueName() {
return controlQueueName;
}
#Bean
public Queue controlQueue() {
System.out.println("controlQueue(): controlQueueName=" + controlQueueName);
return new Queue(controlQueueName, true, true, true);
}
}
Notice that the necessary bean used in the SpEL was created implicitly based on the #Configuration class (with a slight alteration of the spelling ConfigureAMQP -> configureAMQP).
Declare a magic bean, in this case implicitly named queueName:
#Component
public class QueueName {
public String buildFor(String name) {
return "project."+name+".queue";
}
}
Access this using a "constant string" that will be evaluated at runtime:
#RabbitListener(queues = "#{queueName.buildFor(\"foo\")}")
If {queue-name} would came from yml file - it should work:
#RabbitListener(queues = "${queue-name}")
public void receiveMessage(FooMessage message) {
}
Spring will inject value from application.yml.

How to propagate same instance using CDI

I have a web application with JAX-RS, CDI and EJB. In each resource I inject a Stateless SessionBean, and my question is whether it is possible to inject the same instances into a provider of JAX-RS and the Stateless SesionBean. I am trying to pass some data that come in each request to the Stateless SesionBean from a ContainerRequestFilter. All EJB components are accessed only by jax rs resources.
Example:
public class Bean {
private String attr;
// getter and setter
}
#Stateless
public class BeanService {
#Inject
Bean bean;
public void doStuff() {
bean.getAttr();
// do something with bean.attr
}
}
#Path("/bean")
public class BeanResource {
#Inject
BeanService service;
#GET
public void doStuff() {
service.doStuff():
}
}
#Provider
public class BeanRequestFilter implements ContainerRequestFilter {
#Inject
Bean bean;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String data = null; // <- get data from request
bean.setAttr(data);
}
}
Update
Change the Bean for Pojo, my only intention is use a class that hold some state that come in every request and can be transmited in each invocation, since the PojoResource to PojoService. I want to do it in this way because all the services retrive this data and I don't want to pass this as parameter on every method.
This looks like your Bean class is essentially request scoped, so changing it to:
#RequestScoped
public class Bean {
...
}
should have the desired effect. The same instance will be injected in both the BeanRequestFilter and the BeanService.
However, I think you may also get what you're looking for by injecting the ContainerRequestContext directly into the BeanService and forgetting about Bean altogether.
#Stateless
public class BeanService {
#Context
ContainerRequestContext containerRequestContext;
public void doStuff() {
// <- get data from request
}
}
If you want the Bean to be a kind of singleton using CDI see the #ApplicationScoped annotation (in that case Bean should be Sersializable)
Or if you want the EJB BeanService to be a singleton see the #Singleton annotation
Before answering the question, Bean should never be updated. A concept of bean is that which provides a service, and uses data to process a request.
That said, you can of course provide data as bean, but then the data needs to be produced at one point to be used, and not to be updated.
I would therefore use the BeanRequestFilter to produce the bean, and let the BeanService inject the produced bean.
This notwithstanding however, i see that this is a request based data? is it a header data?, request parameter? Then i would suggest that you use the jax-rs #QueryParam or #HeaderParam or #PathParam or #FormParam or #CookieParam within the jax-rs resource class, and then provide the data as a domain object parameter to your BeanService thus:
#Path("/api/resource-path")
public class MyResource {
public void processSomething(#QueryParam("qparam") String param, #HeaderParam("hparam") String hParam) {
MyDomain domain = new MyDomain(qParam, hParam);
myService.process(domain);
}
}

Restlet: How can I retrieve DTO with setting custom MediaType?

How can I send GET request for entity with custom MediaType?
For example I want to retrieve MyUserDTO and set MediaType to application/user+yml.
For now I have two separated actions. I can retrieve entity:
resource.get(MyUserDTO.class);
and can retrieve string:
resource.get(new MediaType("application", "user+yml");
But how to combine them? Or maybe there is some trick to configure Restlet to teach him how to work with custom MediaTypes.
In fact, you have the right approach but you don't use the right constructor of the class MediaType (new MediaType(name, description)).
To make your code work, you need to change it to this:
resource.get(new MediaType("application/user+yml"));
On the server side, you will get this:
#Get
public Representation getSomething() {
System.out.println(">> media types = " +
getRequest().getClientInfo().getAcceptedMediaTypes());
// Display this: media types = [application/user+yml:1.0]
(...)
}
You can leverage the extension support of Restlet by adding a value within the annotation Get. In your case, you need to add a custom extension as described below:
public class MyApplication extends Application {
public MyApplication() {
getMetadataService().addExtension(
"myextension", new MediaType("application/user+yml"));
(...)
}
#Override
public Restlet createInboundRoot() {
(...)
}
}
Now you can use the extension within your server resource:
#Get("myextension")
public Representation getSomething() {
(...)
}
This method will be used with the expected media type is application/user+yml.
Hope it helps you,
Thierry

Java library for converting rest urls to jax-rs methods

I have a collection of jax-rs resources, such as
#Path("/api/v1/ping")
public class PingResource {
#GET
public String ping(#QueryParam("name") String name) {
return "pong: " + name;
}
}
I want figure out how urls map into resource methods, e.g.
public class ResourceMethod {
Method method;
Object[] arguments;
}
public interface UrlToResourceMapper {
ResourceMethod mapToResource(HttpServletRequest request);
}
UrlToResourceMapper mapper = new UrlToResourceMapperImpl(Arrays.asList(PingResource.class));
ResourceMethod resourceMethod = mapper.mapToResource(new RequestImpl("GET", "http://host/api/v1/ping?name=josh", ...));
assertEquals(PingResource.class.getMethod("ping"), resourceMethod.method);
assertEquals(1, resourceMethod.arguments.length);
assertEquals("josh", (String)resourceMethod.arguments[0]);
Is there a library that implements something like the UrlToResourceMapper interface? e.g. Is there a class within Jersey that does this? Everything I've found so far either invokes the method, or only makes the method accessible from within the context of an executing request. I don't want to invoke the method, and I don't want to submit a request (I don't want filters to be invoked, for instance). I just want a library that tells me what invocation results from a given request.

Implementing dynamic menu for Spring MVC/AOP application

I wish to implement dynamically changeable menu (updating whenever annotated method or controller added) for my Spring MVC application.
What i want is to introduce new annotation (#RequestMenuMapping) which will go to #Controller beans and their methods (just like #RequestMapping works).
Heres is what i want, User class, producing menu like
Users
Index | List | Signup | Login
with following code:
#Controller
#RequestMapping("user")
#RequestMenuMapping("Users")
public class User {
#RequestMapping("")
#RequestMenuMapping("Index")
public String index(/* no model here - just show almost static page (yet with JSP checks for authority)*/) {
return "user/index.tile";
}
#RequestMapping("list")
#RequestMenuMapping("List")
public String list(Model model) {
model.addAttribute("userList",/* get userlist from DAO/Service */);
return "user/list.tile";
}
#RequestMapping("signup")
#RequestMenuMapping("Signup")
public String signup(Model model) {
model.addAttribute("user",/* create new UserModel instance to be populated by user via html form */);
return "user/signup.tile";
}
#RequestMapping("login")
#RequestMenuMapping("Login")
public String login(Model model) {
model.addAttribute("userCreds",/* create new UserCreds instance to be populated via html form with login and pssword*/);
return "user/login.tile";
}
}
I think that Spring AOP may help me to pointcut methods with #RequestMenuMapping annotation and via #AfterReturning add something representing web-site menu to model.
But this raises two questions:
How do i get Model instance in #AfterReturning advice method in case it is missing in adviced method (as in .index())?
How do i get all methods (as in java reflection Method) and classes (as in java reflection Class) annotated with #RequestMenuMapping in order to build complete menu index?
I think a better soultion would be a bean post processor to scan all controller classes for the #RequestMenuMapping and a HandlerInterceptor to add the menu items to every model map.
InterceptorDemo:
#Aspect
#Component
public class InterceptorDemo {
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMapping() {
}
#Pointcut("#annotation(you.package.RequestMenuMapping)")
public void requestMenuMapping() {
}
#AfterReturning("requestMapping() && equestMenuMapping()")
public void checkServer(JoinPoint joinPoint,Object returnObj) throws Throwable {
Object[] args = joinPoint.getArgs();
Model m = (Model)args[0];
// use joinPoint get class or methd...
}
}
If you want to intercept Contoller with you own, you can wirte another pointcut and ProceedingJoinPoint object can get what you want.
Q1:
ModelAndView object create at org.springframework.web.servlet.DispatcherServlet.doDispatch()
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
So, you can intercept handle method after returing or override the method.
Q2:As far as i know, there are two ways getting annotation methods.
1.Use AOP:
You can declare a pointcut like this:
#Pointcut("#annotation(you.package.RequestMenuMapping)")
public void requestMenuMappingPountcut() {
}
2.Use reflection.
Class clazz = Class.forName(classStr);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(RequestMapping.class)
&& method.isAnnotationPresent(RequestMenuMapping.class)) {
// do something
}
}

Categories

Resources