Search code examples
javarestservletsapache-camelundertow

Using rest Servlet in Camel with Guice and Undertow


I'm setting up and application using Undertow, I've set up a ResourceHandler for static files, and Servlet to be used by apache-camel to expose rest services.

I've done this using spring and servlet3.0 in an app container.

In a class extending org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer

@Override
public void onStartup(ServletContext servletContext) throws ServletException
{
    super.onStartup(servletContext);
    ServletRegistration.Dynamic servlet = servletContext.addServlet("RestServlet", new CamelHttpTransportServlet());
    servlet.setLoadOnStartup(1);
    servlet.addMapping("/rest/*");
}

And in camel route

restConfiguration()
            .component("RestServlet")
            .bindingMode(RestBindingMode.json)
            .dataFormatProperty("prettyPrint", "true");

Pretty close to whats described in http://camel.apache.org/servlet.html

But if I do this in Undertow as an embedded I get org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: RestServlet of type: org.apache.camel.spi.RestConsumerFactory as I guess Guice never finds the servlets created by Undertow. I tried to manually expose the CamelHttpTransportServlet as a Guice Binding but that doesn't seem to change things.

ClassLoader classLoader = getClass().getClassLoader();
    ResourceHandler staticHandler = new ResourceHandler(new ClassPathResourceManager(classLoader, STATIC_RESOURCE_ROOT))
            .addWelcomeFiles(INDEX_HTML);

    DeploymentInfo deploymentInfo = Servlets.deployment()
            .setClassLoader(classLoader)
            .setContextPath(ROOT_MAPPING)
            .setDeploymentName(DEPLOYMENT_NAME)
            .addServlet(
                    Servlets.servlet("RestServlet", CamelHttpTransportServlet.class)
                            .addMapping(REST_MAPPING)
                            .setLoadOnStartup(1)
            );

    DeploymentManager manager = Servlets.defaultContainer().addDeployment(deploymentInfo);
    manager.deploy();

    PathHandler path = Handlers.path()
            .addPrefixPath(REST_MAPPING, manager.start())
            .addPrefixPath(ROOT_MAPPING, staticHandler);

    undertow = Undertow.builder()
            .addHttpListener(port, LOCALHOST)
            .setHandler(path)
            .build();
    undertow.start();

The static resource work as expected, and it also seems the rest servlet is running and getting the responses but CamelContext won't start up.

I can't use restlet or anything in camel as then the port will be in use so I need to use different port for static files and rest. Is there any way to have camel identify the Servlet initiated by Undertow?


Solution

  • Ok I finally found out where it went wrong.

    I suspect I always used .component("servlet") and not .component("RestServlet"), but Camel wouldn't link this automatically before.

    I changed this section to

    restConfiguration()
                .bindingMode(RestBindingMode.json)
                .component("servlet")
                .dataFormatProperty("prettyPrint", "true")
                .endpointProperty("servletName", "RestServlet);
    

    And the deployment I changed the servlets mapping to /* or else request.getPathInfo() would return null inside CamelHttpTransportServlet. NB I encountered a problem beause I initially set contextPath to /rest/* which messed up sessions and cookies

    DeploymentInfo deploymentInfo = Servlets.deployment()
                .setClassLoader(classLoader)
                .setContextPath("/rest/")
                .setDeploymentName(DEPLOYMENT_NAME)
                .addServlet(
                        Servlets.servlet("RestServlet", CamelHttpTransportServlet.class)
                                .addMapping("/*")
                                .setLoadOnStartup(1)
                );