Программно получить экземпляр сервлета для реализации JAX-WS WebService?

Я работаю над веб-службой, используя нисходящий подход, создавая типы служб и интерфейсы из WSDL, используя wsimport JAX-WS. Это обеспечивает следующий интерфейс типа порта, который я реализую.

/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.4-b01
 * Generated source version: 2.2
 */
@WebService(name = "ExamplePortType", targetNamespace = "http://example.com")
public interface ExamplePortType {

    /**
     * @param example
     * @return java.lang.String
     * @throws ExampleException
     */
    @WebMethod
    @WebResult(name = "exampleResponse", targetNamespace = "http://example.com")
    @RequestWrapper(localName = "sendExample", targetNamespace = "http://example.com", className = "com.example.SendExample")
    @ResponseWrapper(localName = "sendExampleResponse", targetNamespace = "http://example.com", className = "com.example.SendExampleResponse")
    public String sendExample(
        @WebParam(name = "example", targetNamespace = "http://example.com")
        ExampleRequest example)
        throws ExampleException
    ;
}

Кажется, что обычный способ добавить эту службу на ваш сервер приложений (в моем случае, Tomcat) — это добавить класс реализации в web.xml в качестве сервлета и добавить WSServletContextListener в качестве слушателя. Очень грубо кажется, что при инициализации контекста слушатель создает ServletAdapters, которые обертывают bean-компонент реализации и добавляют их в WSServletDelegate, который вызывается тонким WSServlet. Запросы к вашей реализации затем обрабатываются WSServlet и передаются вашему bean-компоненту делегатом на основе любых настроенных вами шаблонов URL.

Есть ли способ сделать вышеописанное программно? Мне нужен метод, который принимает экземпляр вышеуказанного интерфейса и возвращает мне экземпляр сервлета, который, если он зарегистрирован в ServletContext, будет направлять соответствующие запросы в обернутую реализацию. Что-то типа:

Servlet exampleServlet = new ServletAdapter().wrap(new ExamplePortTypeImpl());

Одним из требований является то, что я не могу полагаться на статические файлы конфигурации (такие как web.xml или sun-jaxws.xml). Предоставляет ли JAX-WS или родственная библиотека (например, Axis2 и т. д.) такую ​​функциональность?

Извиняюсь, если что-то не понятно; я здесь впервые :). Любые указатели приветствуются.

В настоящее время используется JAX-WS 2.1, Tomcat 7, Servlet 3.0.


person Anthop    schedule 24.08.2012    source источник


Ответы (2)


Основываясь на ответе Anthop, это код, который я придумал, который работает для меня.

// Main code:

final ServletContextHandler soapContextHandler = createSoapServletContextHandler();

final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { soapContextHandler });

server = createServer(port);
server.setHandler(handlers);
server.start();
// Function:
    private ServletContextHandler createSoapServletContextHandler()
    {
        final ServletContextHandler soapContextHandler =
                new ServletContextHandler(ServletContextHandler.SESSIONS);

        WSEndpoint<SoapServiceImpl> endpoint =
                WSEndpoint.create(SoapServiceImpl.class, false, null, null, null, null,
                        BindingImpl.getDefaultBinding(), null, null, null, false);

        ServletAdapter servletAdapter = new ServletAdapterList().createAdapter("soap", "/soap", endpoint);

        SoapServlet soapServlet = new SoapServlet(
                new WSServletDelegate(Collections.singletonList(servletAdapter), new EmptyServletContext()));

        soapContextHandler.addServlet(new ServletHolder(soapServlet), "/soap");
        return soapContextHandler;
    }
// Servlet:
    private static class SoapServlet extends HttpServlet
    {
        private final WSServletDelegate delegate;

        SoapServlet(WSServletDelegate delegate)
        {
            this.delegate = delegate;
        }

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            delegate.doGet(req, resp, getServletContext());
        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            delegate.doPost(req, resp, getServletContext());
        }
    }

Где SoapServiceImpl — это реализация вашего мыльного сервиса, а EmptyServletContext — это просто полностью пустая реализация ServletContext, которая просто возвращает нуль или значения по умолчанию для всех методов.

Это должно обслуживать запросы мыла по пути /soap с использованием Jetty. Вы можете добавить в список другие обработчики контекста, и они также будут работать вместе с обработчиком мыла. Я протестировал его вместе с обработчиком контекста Джерси, поэтому моя служба обрабатывает запросы REST и SOAP на одном порту с Jetty.

person Colin    schedule 14.01.2021

Хорошо, после долгих экспериментов я смог собрать что-то, что работает. Я опубликую его здесь ради документации.

По сути, я пришел к этому путем эмуляции или повторной реализации того, как JAX-WS создает свой WSServlet из своего WSServletContextListener. К сожалению, я не смог найти более простой или лучшей поддержки и простого способа сделать это.

По сути, моя фабрика создает WSEndpoint, используя метод WSEndpoint.create(). create() принимает в качестве входных данных класс реализации WebService, который я пытаюсь обернуть. Большинство других входных данных имеют значение null, чтобы побудить WSEndpoint использовать значение по умолчанию или попытаться извлечь некоторую конфигурацию из аннотаций в классе реализации.

Затем я использую новый ServletAdapterList() для создания ServletAdapter, используя ранее созданную WSEndpoint. Для этого, поскольку я создаю один сервлет для каждого класса реализации, имя адаптера не имеет значения, и его можно настроить для отправки всего трафика в реализацию независимо от URL-адреса.

Затем я создаю один новый WSServletDelegate(), используя одноэлементный список предыдущего ServletAdapter. Единственная хитрость здесь заключается в том, что JAX-WS имеет, по крайней мере, для этого и следующего шага, плохую привычку сохранять некоторые значения в параметрах инициализации ServletContext. Он также не выполняет проверку на нуль должным образом, хотя у него есть значения по умолчанию, которые можно использовать, если параметры не находятся в контексте. Поэтому я также создал фиктивную реализацию ServletContext, которую я передаю в конструктор WSServletDelegate, чтобы он чувствовал, что он просматривает параметры инициализации.

Наконец, я создал реализацию HttpServlet, которая перенаправляет запросы WSServletDelegate аналогично тому, как это делает WSServlet. Поскольку WSServlet снова сохраняет объект делегата в параметрах инициализации ServletContext, мне было проще просто повторно реализовать его функциональность, чем возиться с существующим WSServlet. Затем эту реализацию HttpServlet можно рассматривать как любой обычный сервлет, который будет принимать и обрабатывать вызовы веб-службы SOAP.

person Anthop    schedule 30.08.2012