Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I handle HTTP Methods in Undertow?

So I've decided to start using Undertow, both as an experiment and due to the great results it achieved in benchmark tests. And while I think it's fantastic there's a feature which is either missing or I can't find.

I want to develop a RESTful web service so it's important for me to identify which HTTP method is being called. Now I can get this from RequestMethod in the HttpServerExchange parameter but if had to that for every handler that would become tedious.

My solution, which works but I know is wrong, is this:

Created an annotation interface called HTTPMethod:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) 
public @interface HTTPMethod {

public enum Method {

    OTHER, GET, PUT, POST, DELETE
}

Method method() default Method.OTHER;

an "abstract" class (which is not abstract):

public abstract class RESTfulHandler implements HttpHandler {

@Override
public void handleRequest(HttpServerExchange hse) throws Exception {

    for (Method method : this.getClass().getDeclaredMethods()) {

        // if method is annotated with @Test
        if (method.isAnnotationPresent(HTTPMethod.class)) {

            Annotation annotation = method.getAnnotation(HTTPMethod.class);
            HTTPMethod test = (HTTPMethod) annotation;

            switch (test.method()) {
                case PUT:
                    if (hse.getRequestMethod().toString().equals("PUT")) {
                        method.invoke(this);
                    }
                    break;

                case POST:
                    if (hse.getRequestMethod().toString().equals("POST")) {
                        method.invoke(this);
                    }
                    break;

                case GET:
                    if (hse.getRequestMethod().toString().equals("GET")) {
                        method.invoke(this);
                    }
                    break;

                case DELETE:
                    if (hse.getRequestMethod().toString().equals("DELETE")) {
                        method.invoke(this);
                    }
                    break;
                case OTHER:
                    if (hse.getRequestMethod().toString().equals("OTHER")) {
                        method.invoke(this);
                    }
                    break;
            }
            if (test.method() == HTTPMethod.Method.PUT) {
                method.invoke(this);
            }
        }
    }
}

}

and an implementation of both the above:

public class ItemHandler extends RESTfulHandler{

@HTTPMethod(method=GET)
public List<String> getAllItems()
{
    System.out.println("GET");
    return new ArrayList<>();
}

@HTTPMethod(method=POST)
public void addItem()
{      
    System.out.println("POST");        
}

@HTTPMethod
public void doNothing()
{   
    System.out.println("OTHERS");      
}

}

Now as I said, it works, but I'm sure that the abstract class and it's implementation have something missing so that they glue correctly. So my question is two fold:

1) Is there a better / proper way to filter HTTP requests in Undertow? 2) What is the correct way of using annotations correctly correctly in the above case?

like image 204
gryzlaw Avatar asked Sep 23 '14 19:09

gryzlaw


1 Answers

Managed to find several answers with the help of the Redhat team and Undertow contributors, hope this helps someone else:

1) The latest version of Undertow has a io.undertow.server.RoutingHandler class which does the exact same thing I propose, just without the need of annotations.

2) There's an adapter for RESTEasy by JBoss: resteasy-undertow or a custom framework hammock which includes RESTEasy + Undertow + Weld.

3) Undertow already supports Servlets 3, so they can be combined to use annotations if you prefer.

like image 190
gryzlaw Avatar answered Sep 29 '22 14:09

gryzlaw