Мы должны обновить пожилое веб-приложение для выполнения под 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, который, кажется, решил вопрос (без веб-приложения солнца вообще).
У меня нет полного объяснения (т.е. я не знаю, откуда вызывается getWriter
), но это может быть ошибкой в Tomahawk 1.1.3 / MyFaces 1.1.4, о чем сообщалось в проблемах Jira, например TOMAHAWK-579 или MYFACES-1310 (с тем же исключением IllegalStateException
согласно спецификации сервлета). Обратите внимание, что эта ошибка, похоже, зависит от контейнера, как и вы.
Итак, попробуйте либо более свежие версии Tomahawk / MyFaces (см. Матрицу совместимости ), либо получите патч , соответствующий исправлению в r442340 и примените его к ветке 1.1.3 Томагавка. Более поздний вариант, возможно, самый простой. По крайней мере, это то, что я бы попробовал.
Один начальный вопрос - если вы запускаете это на GlassFish, почему трассировка стека имеет ссылки на Catalina? Могу ошибиться, но Каталина - это ядро Tomcat, а Grizzly - ядро GlassFish.
Вы, вероятно, уже знаете это, но проблема в том, что getWriter () и getOutputStream () нельзя одновременно вызывать в одном ответе. Если вы оставите такие вещи в контейнере, все должно быть правильно.
Итак, один вопрос: вызывает ли ваш код getWriter ()? Этого кода нет. Я не вижу в этом ничего подозрительного, поэтому я бы покопался в любом коде выше этого фильтра, если он есть?
Попробуйте определить ваш фильтр перед всеми другими фильтрами в web.xml
.
Если это не сработает, вот как я бы продолжил отладку:
Вариант 1:
getWriter()
из org.apache.catalina.connector. Response
getWriter()
Вариант 2:
web. xml
HttpServletResponse
, и поставьте точку останова в getWriter()
или new Exception().printStackTrace();
Оба варианта имеют по сути одну и ту же идею. В обоих случаях дайте обратную связь, чтобы мы могли продолжить мозговой штурм.
Вам нужно прочитать эту запись в блоге .
Также, вот очень минимальный скелет «канала» для связи между потоками:
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 и мне они очень нравятся, но я склонен избегать IoC, когда это возможно, потому что это превращает ваше программное обеспечение в набор классов, которые больше не составляют «реальная» программа, но только то, что нужно собрать вместе с помощью XML-конфигурации или метаданных аннотаций и будет падать (и разваливаться) без нее.
-121--1747331-Это может быть две причины:
Фильтр
в цепочке перед Фильтр
, который (косвенно) вызывает getWriter ()
. В этом конкретном случае выглядит как , что и 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 .