понедельник, 2 сентября 2013 г.

Добавление спрингового HttpRequestHandlerServlet сервлета в Tapestry приложение

Недавно возникла небольшая проблема: как добавить свой спринговый сервлет в Tapestry приложение. Если просто прописать его в web.xml, например так:
    <servlet>
        <servlet-name>PaymentService</servlet-name>
        <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>PaymentService</servlet-name>
        <url-pattern>/PaymentService</url-pattern>
    </servlet-mapping>


то Tapestry filter перехватывает запрос к этому сервлету, из-за вот такой настройки:
    <filter>
        <filter-name>app</filter-name>
        <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>app</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


Как исключить что-то в url-pattern, я так и не понял, но, к счастью, тапестри позволяет настроить обработку HttpRequest и вручную определить, какие фильтры к нему применять. Нужно всего лишь добавить следующий код в AppModule
       @Contribute(HttpServletRequestHandler.class)
    public void сontributeFilter(OrderedConfiguration<HttpServletRequestFilter> config){
        config.add("httpInvoker", new HttpServletRequestFilter() {
            @Override
            public boolean service(HttpServletRequest request, HttpServletResponse response, HttpServletRequestHandler handler) throws IOException {
                if(request.getServletPath().equals("/PaymentService")){ // имя нашего сервлета
                    try{
                        AppContext.getHttpInvoker(StringUtils.removeStart(request.getServletPath(), "/")).handleRequest(request, response);
                    }catch (ServletException ex){
                        throw new IOException(ex);
                    }
                    return true; // мы обработали запрос сами, не нужно его обрабатывать другими фильтрами.
                }
                return handler.service(request, response); // передаем запрос тапестри
            }
        });
    }


AppContext.getHttpInvoker - это хелпер, который возвращает spring bean по его имени, приведя его к нужному типу.
    public static HttpInvokerServiceExporter getHttpInvoker(String name){
        if(context == null){
            throw new ApplicationNotInitializedException();
        }
        return (HttpInvokerServiceExporter) context.getBean(name);
    }

 
И, для полноты картины, кусочек конфига спринга:
    <bean name="PaymentService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
        <property name="service" ref="PaymentServiceImpl"/>
        <property name="serviceInterface" value="com.example.httpInvoker.PaymentService"/>
    </bean>