GlassFish выходят с цепочкой фильтра: java.lang. IllegalStateException: PWC3990: getWriter () уже назвали для этого ответа

Мы должны обновить пожилое веб-приложение для выполнения под GlassFish 3 вместо Tomcat для получения развертывания EAR (Glassfish был выбран, поскольку это - ссылочная реализация JEE 6),

К сожалению, очень быстро оказалось, что механизм, который гарантирует, что пользователь зарегистрирован, не работает правильно и жалуется, что getWriter () уже назвали (который, скорее всего, корректен), и я не могу выяснить почему.

Подход состоит в том, что у нас есть фильтр на полном наборе JSP-файлов, который проверяет, что пользователь зарегистрирован и в противном случае перенаправляет к использованию страницы входа в систему filterChain.doFilter(servletRequest, servletResponse);. Пользовательское состояние (включая учетные данные) хранится в так называемом объекте контроллера в объеме сессии, который установлен от проверки входа в систему код Java.


Отслеживание стека от Glassfish:

java.lang.IllegalStateException: PWC3990: getWriter() has already been called for this response
    at org.apache.catalina.connector.Response.getOutputStream(Response.java:676)
    at org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:205)
    at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:176)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at com.XXX.LoggedInToXXXFilter.doFilter(LoggedInToXXXFilter.java:61)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
....

Отрывок web.xml

<?xml version="1.0"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description>
    XXX provides a web interface for a given user.
</description>
<display-name>
XXX
</display-name>
<context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name> 
    <param-value>/WEB-INF/online-faces-config.xml</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
    <param-value>true</param-value>
</context-param> 

<listener>
    <listener-class>
        org.apache.myfaces.webapp.StartupServletContextListener
    </listener-class>
</listener>
<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>
    javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<session-config>
    <!-- idle time in minutes before user is automatically logged out by the container -->
    <session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <filter-class>
        org.apache.myfaces.webapp.filter.ExtensionsFilter
    </filter-class>
    <init-param>
        <param-name>maxFileSize</param-name>
        <param-value>1m</param-value>
        <!-- description>Set the size limit for uploaded files.
            Format: 10 - 10 bytes
            10k - 10 KB
            10m - 10 MB
            1g - 1 GB
            </description-->
    </init-param>
</filter>

<!-- extension mapping for adding <script/>, <link/>, and other resource tags to JSF-pages  -->
<filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <!-- servlet-name must match the name of your javax.faces.webapp.FacesServlet entry -->
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

<!-- extension mapping for serving page-independent resources (javascript, stylesheets, images, etc.)  -->
<filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
</filter-mapping>

<filter>
    <description>Ensure user is logged in</description>
    <filter-name>LoggedInToXXXFilter</filter-name>
    <filter-class>
        com.XXX.servlet.filters.LoggedInToXXXFilter
    </filter-class>
    <init-param>
        <param-name>signon_page</param-name>
        <param-value>/login.jsf</param-value>
    </init-param>
    <init-param>
        <param-name>autologout_page</param-name>
        <param-value>/autologout.jsp</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>LoggedInToXXXFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- filter>
    <filter-name>extensionsFilter</filter-name>
    <filter-class>org.apache.myfaces.component.html.util.ExtensionsFilter</filter-class>
    <init-param>
    <param-name>uploadMaxFileSize</param-name>
    <param-value>100m</param-value>
    </init-param>
    <init-param>
    <param-name>uploadThresholdSize</param-name>
    <param-value>100k</param-value>
    </init-param>
    </filter-->
<!-- filter-mapping>
    <filter-name>extensionsFilter</filter-name>
    <url-pattern>*.jsf</url-pattern>
    </filter-mapping>
    <filter-mapping>
    <filter-name>extensionsFilter</filter-name>
    <url-pattern>/faces/*</url-pattern>
    </filter-mapping-->
<!-- error-page>
    <exception-type>java.lang.IllegalArgumentException</exception-type>
    <location>/WEB-INF/jsp/IllegalArgumentException.jsp</location>
    </error-page-->
<error-page>
    <exception-type>java.lang.RuntimeException</exception-type>
    <location>/WEB-INF/jsp/RuntimeException.jsp</location>
</error-page>
<!-- error-page>
    <exception-type>com.transaxiom.axsWHSweb.struts.action.UserIsNotLoggedInException</exception-type>
    <location>/WEB-INF/jsp/UserIsNotLoggedInException.jsp</location>
    </error-page-->
<error-page>
    <exception-type>
        com.XXX.struts.action.SecurityViolationException
    </exception-type>
    <location>/WEB-INF/jsp/SecurityViolationException.jsp</location>
</error-page>
<error-page>
    <exception-type>
        com.XXX.logic.UncheckedCommunicationException
    </exception-type>
    <location>/WEB-INF/jsp/CommunicationException.jsp</location>
</error-page>
<error-page>
    <exception-type>
        com.XXX.logic.ConnectionNotCreatedException
    </exception-type>
    <location>
        /WEB-INF/jsp/ConnectionNotCreatedException.jsp
    </location>
</error-page>
<!-- error-page>
    <exception-type>com.XXX.logic.UncheckedConnectionNotCreatedException</exception-type>
    <location>/WEB-INF/jsp/ConnectionNotCreatedException.jsp</location>
    </error-page-->
<!-- filter>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <filter-class>org.apache.myfaces.component.html.util.ExtensionsFilter</filter-class>
    <init-param>
    <param-name>maxFileSize</param-name>
    <param-value>20m</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>MyFacesExtensionsFilter</filter-name>
    <url-pattern>*.faces</url-pattern>
    </filter-mapping-->
</web-app>

Код фильтра от LoggedInToXXXFilter.java:

(stacktrace происходит в filterChain.doFilter(servletRequest, servletResponse) строка.

public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
        final FilterChain filterChain) throws IOException, ServletException {
    boolean ok = false;
    if (servletRequest instanceof HttpServletRequest) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        String servletPath = request.getServletPath();
        if ((servletPath.equals(signOnPage) == true) || servletPath.endsWith(".css") || servletPath.equals(autologoutPage)) {
            ok = true;
        } else {
            Controller controller = Controller.getControllerFromSession(request.getSession(false));
            if ((controller != null) && controller.isSignedOn()) {
                ok = true;
            }

        }
        if (ok) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            // Hop to the sign on page.
            // http://forum.java.sun.com/thread.jspa?threadID=548967&messageID=2676856
            ServletContext servletContext = filterConfig.getServletContext();

            URL url = new URL(new URL(request.getRequestURL().toString()), (request.getContextPath() + signOnPage));
            ((HttpServletResponse) servletResponse).sendRedirect(url.toString());
        }
    } else {
        // Only for http requests
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

Возможная причина могла быть то, что мы все еще приводим наши собственные библиотеки JSF (MyFaces 1.1.4 с Томагавком)?


Править: Обновленный вопрос с полным (но анонимизированный) web.xml. Примечание там является большим количеством прокомментированных материал. Я оставил его внутри для не случайного удаления важной информации


Править: Опытный с конфигурационным файлом веб-приложения солнца и найденный им не имел значения. То, что интересно, - то, что после входа в систему, страница входа в систему выдает исключение, но я могу вручную перейти к основной странице (также JSF) и видеть еще две страницы с прекрасной функциональностью. Существует три страницы в дополнение к странице входа в систему, которая выдает исключение.

Моя начальная буква думала, был то, что отделяющейся функцией будет t-taglib (для Томагавка), но что после того, как быстрое расследование, кажется, не имеет место, поскольку некоторые рабочие страницы применяют Томагавк, и некоторые не делают.


Править: Сравнивая две jsp-страницы, та, которая перестала работать, другой, который не сделал, не показал заметного отличия, которое должно вызвать это. Поскольку было указано, что там был сообщен эта самая ошибка с Томагавком 1.1, и мы использовали 1.1.3, я теперь обновил до последнего Apache Томагавк Myfaces 1.1.9, который, кажется, решил вопрос (без веб-приложения солнца вообще).

6
задан Cœur 6 August 2017 в 15:04
поделиться

4 ответа

У меня нет полного объяснения (т.е. я не знаю, откуда вызывается getWriter ), но это может быть ошибкой в ​​Tomahawk 1.1.3 / MyFaces 1.1.4, о чем сообщалось в проблемах Jira, например TOMAHAWK-579 или MYFACES-1310 (с тем же исключением IllegalStateException согласно спецификации сервлета). Обратите внимание, что эта ошибка, похоже, зависит от контейнера, как и вы.

Итак, попробуйте либо более свежие версии Tomahawk / MyFaces (см. Матрицу совместимости ), либо получите патч , соответствующий исправлению в r442340 и примените его к ветке 1.1.3 Томагавка. Более поздний вариант, возможно, самый простой. По крайней мере, это то, что я бы попробовал.

5
ответ дан 8 December 2019 в 16:02
поделиться

Один начальный вопрос - если вы запускаете это на GlassFish, почему трассировка стека имеет ссылки на Catalina? Могу ошибиться, но Каталина - это ядро ​​Tomcat, а Grizzly - ядро ​​GlassFish.

Вы, вероятно, уже знаете это, но проблема в том, что getWriter () и getOutputStream () нельзя одновременно вызывать в одном ответе. Если вы оставите такие вещи в контейнере, все должно быть правильно.

Итак, один вопрос: вызывает ли ваш код getWriter ()? Этого кода нет. Я не вижу в этом ничего подозрительного, поэтому я бы покопался в любом коде выше этого фильтра, если он есть?

2
ответ дан 8 December 2019 в 16:02
поделиться

Попробуйте определить ваш фильтр перед всеми другими фильтрами в web.xml.

Если это не сработает, вот как я бы продолжил отладку:

Вариант 1:

  1. Скачайте исходники Glassfish (или исходники соответствующей версии Tomcat)
  2. Включите эти исходники в каталог поиска исходников (для отладчика)
  3. Поставьте точку останова в getWriter() из org.apache.catalina.connector. Response
  4. Проверьте стек, чтобы увидеть, кто вызывает getWriter()

Вариант 2:

  1. Определите новый фильтр поверх всех остальных фильтров в web. xml
  2. Создайте обертку вокруг поставляемого HttpServletResponse, и поставьте точку останова в getWriter() или new Exception().printStackTrace();

Оба варианта имеют по сути одну и ту же идею. В обоих случаях дайте обратную связь, чтобы мы могли продолжить мозговой штурм.

2
ответ дан 8 December 2019 в 16:02
поделиться

Вам нужно прочитать эту запись в блоге .

Также, вот очень минимальный скелет «канала» для связи между потоками:

public class Channel<T>
{
    private readonly Queue<T> _queue = new Queue<T>();

    public void Enqueue(T item)
    {
        lock (_queue)
        {
            _queue.Enqueue(item);
            if (_queue.Count == 1)
                Monitor.PulseAll(_queue);
        }
    }

    public T Dequeue()
    {
        lock (_queue)
        {
            while (_queue.Count == 0)
                Monitor.Wait(_queue);

            return _queue.Dequeue();
        }
    }
}
-121--3772230-

Прежде чем использовать инверсию управления, вы должны быть хорошо осведомлены о том, что она имеет свои достоинства и недостатки, и вы должны знать, почему вы используете ее, если вы делаете это.

Достоинства:

  • Ваш код разъединяется, так что вы можете легко обмениваться реализациями интерфейса с альтернативными реализациями
  • Он является сильным мотиватором для кодирования по интерфейсам вместо реализаций
  • Очень легко написать единичные тесты для вашего кода, потому что это зависит ни от чего другого, как от объектов, которые он принимает в своем конструкторе/установщике, и вы можете легко инициализировать их с правильными объектами в изоляции.

Недостатки:

  • IoC не только инвертирует поток управления в программе, но и значительно затуманивает его. Это означает, что вы больше не можете просто читать код и переходить из одного места в другое, потому что соединения, которые обычно находятся в вашем коде, больше не находятся в коде. Вместо этого эти метаданные интерпретируются в файлах конфигурации XML или аннотациях, а также в коде контейнера IoC.
  • Возникает новый класс ошибок, когда вы ошибаетесь в конфигурации XML или аннотациях, и вы можете потратить много времени на то, чтобы выяснить, почему контейнер IoC вводит нулевую ссылку в один из объектов при определенных условиях.

Лично я вижу сильные точки IoC и мне они очень нравятся, но я склонен избегать IoC, когда это возможно, потому что это превращает ваше программное обеспечение в набор классов, которые больше не составляют «реальная» программа, но только то, что нужно собрать вместе с помощью XML-конфигурации или метаданных аннотаций и будет падать (и разваливаться) без нее.

-121--1747331-

Это может быть две причины:

  1. Существует еще один Фильтр в цепочке перед Фильтр , который (косвенно) вызывает getWriter () .
  2. Этот запрос был передан из JSP-файла вместо класса Servlet.

В этом конкретном случае выглядит как , что и sendRedirect () , и doFilter () были вызваны в одной цепочке запрос-ответ (поскольку sendRedirect () может неявно вызывать getWriter () ). Когда фильтр вызывает sendRedirect () , он должен не выполнять doFilter () после этого. Опубликованный код не доказывает этого, но, возможно, из него были удалены некоторые строки для очистки, или есть другой фильтр перед в цепочке, который делает именно это.

Обновление: после повторного рассмотрения этого вопроса и поиска в источнике фильтра фильтр фактически получает OutputStream после фильтрации запроса/ответа. Итак, страница,сервлет или любой другой Javacode, который был вызван/выполнен данным URL, (неявно) вызвал getWriter () .

Обновление 2: Glassfish v3 поставляется по умолчанию с эталонной реализацией Sun Mojarra JSF 2,0. Возможно, он каким-то образом столкнулся с реализацией MyFaces 1.x, поставляемой в веб-проекте. Вы можете указать Glassfish v3, что предпочитаете использовать MyFaces, установив для свойства useMyFaces или (более нового) useBundledJsf значение true в /WEB-INF/sun-web.xml . Вы его использовали? Попробуйте.

<sun-web-app>
    <class-loader delegate="false"/>
    <property name="useBundledJsf" value="true"/>
</sun-web-app>

См. также Альтернативные реализации JSF на GlassFish - MyFaces и Tomahawk .

5
ответ дан 8 December 2019 в 16:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: