JSF ViewExpiredExceptionHandler NullPointerException

Я использую Apache MyFaces 2 на WebSphere Application Server 8. Я хочу реализовать собственный ExceptionHandler, который обрабатывает ViewExpiredException.

Я использую код, который BalusC опубликовал. Factory вызывается в нужное время, но я получаю исключение NullPointerException, когда здесь вызывается handleNavigation:

public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }


    @Override
    public void handle() throws FacesException {
        FacesContext facesContext = FacesContext.getCurrentInstance();

        for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents()
                .iterator(); iter.hasNext();) {
            Throwable exception = iter.next().getContext().getException();

            if (exception instanceof ViewExpiredException) {
                facesContext
                        .getApplication()
                        .getNavigationHandler()
                        .handleNavigation(facesContext, null,
                                "/content/home?faces-redirect=true&expired=true");
                facesContext.renderResponse();
                iter.remove();
            }
        }

        getWrapped().handle();
    }

    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

}

Исключение:

com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0068E: An exception was thrown by one of the service methods of the servlet [Faces Servlet] in application [My_App]. Exception created : [java.lang.NullPointerException
    at org.apache.myfaces.application.NavigationHandlerImpl.getNavigationCase(NavigationHandlerImpl.java:203)
    at org.apache.myfaces.application.NavigationHandlerImpl.handleNavigation(NavigationHandlerImpl.java:77)
    at myapp.ViewExpiredExceptionHandler.handle(ViewExpiredExceptionHandler.java:33)
    at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:191)
    at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1147)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:722)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:449)
    at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:178)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:125)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:92)
    at myapp.auth.RequestFilter.doFilter(RequestFilter.java:35)
    at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:192)
    at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:89)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:919)
    at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1016)
    at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:87)
    at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:886)
    at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1655)
    at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:195)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:452)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:511)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:305)
    at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:276)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
    at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
    at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
    at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
    at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1650)
]

EDIT: Во-первых, /content — это каталог в моем WebContent. Это не контекстный путь. Я изменил свой код и использовал внешнее перенаправление следующим образом:

if (exception instanceof ViewExpiredException) {
        String loc = facesContext.getExternalContext()
            .getRequestServletPath();
        try {
            facesContext.getExternalContext().redirect(loc);
            //facesContext.getExternalContext().redirect("/content/home.xhtml");
            //facesContext.getExternalContext().redirect("/");
        } catch (IOException e) {
            e.printStackTrace();
        }
}

Но все равно получите то же исключение NullPointerException для FaceContext.getExternalContext().redirect. Но ExternalContext не является нулевым. Я получил RequestServletPath.

Так что не так с моим кодом здесь?

С уважением - veote


person veote    schedule 26.07.2012    source источник


Ответы (2)


"/content/home?faces-redirect=true&expired=true", по-видимому, не распознается как допустимый навигационный вариант. Невозможно сказать, что там не так, поскольку детали вашей среды неясны. Является ли /content контекстным путем или нет? Если это так, то его следует опустить. Действительно ли существует файл /home.xhtml? И так далее.

Если вы все еще не можете понять это, то, вероятно, проще просто отправить перенаправление, как вы, кажется, после перенаправления в любом случае.

externalContext.redirect("/content/home.xhtml?expired=true");

Обратите внимание, что это по-прежнему приведет к ошибке 404, если URL-адрес недействителен, но вам, вероятно, будет легче понять это.

person BalusC    schedule 26.07.2012
comment
Я пытался использовать это, но все равно получаю то же исключение. (см. мой отредактированный вопрос) - person veote; 27.07.2012
comment
Вы можете получить тот же самый NPE. Или вы вообще не обращали внимания на stacktrace? - person BalusC; 27.07.2012

Я получаю аналогичный набор ошибок. Следуя описанному выше подходу, моя ручка навигации

nav.handleNavigation(fc, null, "/error");

Возвращает NPE, как указано выше (даже те же номера строк).

Если я изменю, чтобы просто сделать перенаправление, я получаю:

java.lang.NullPointerException
at org.apache.myfaces.context.servlet.PartialViewContextImpl.getPartialResponseWriter(PartialViewContextImpl.java:303)
at org.primefaces.context.PrimePartialViewContext.getPartialResponseWriter(PrimePartialViewContext.java:45)
at org.apache.myfaces.context.servlet.ServletExternalContextImpl.redirect(ServletExternalContextImpl.java:452)
at my.package.CustomExceptionHandler.handle(CustomExceptionHandler.java:134)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:191)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1235)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:758)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:441)

В обоих случаях я считаю, что причина в том, что getViewRoot() имеет значение null, чего, по-видимому, не ожидают "getNavigationCase" или getPartialResponseWriter.

Я смог исправить это, используя пример в этом сообщении в блоге (http://ovaraksin.blogspot.com/2010/10/jsf-ajax-redirect-after-session-timeout.html). Кажется, что у Mojarra и PrimeFaces (я использую PrimeFaces 3.5 с MyFaces) есть проблемы со стандартным перенаправлением в случае этой ошибки. Исправление в том случае, если

facescontext.getResponseWriter() == null && facescontext.getRenderKit() == null

и это частичный запрос и запрос ajax, затем используйте RenderKit для создания ResponseWriter и установите его на facescontext.

Затем работает externalContext.redirect().

Изменить: более конкретно, в сообщении блога SecurityPhaseListener есть метод doRedirect(FacesContext fc, String redirectPage), который включает раздел под названием:

 // fix for renderer kit (Mojarra's and PrimeFaces's ajax redirect)

Я поднял этот раздел в метод ответа перенаправления, который я вызываю из блока if (exception instanceof ViewExpiredException).

ИЗМЕНИТЬ ОК, окончательное решение. С помощью фрагмента кода с сайта http://jira.icesoft.org/browse/ICE-4251 Я смог реализовать это с помощью handlenavigation. Вот вызов, который я добавил из задачи JIRA, которая выполняется в дескрипторе().

checkViewRoot(facesContext,"/error.jsf");

... Вот метод

    public static void checkViewRoot( FacesContext ctx, String viewId) {
    if (ctx.getViewRoot() == null) {
        UIViewRoot viewRoot = ctx.getApplication().getViewHandler().createView(ctx, viewId);
        if (viewRoot != null) {
            ctx.setViewRoot(viewRoot);
        }
    }
}

... И после этого в методе handle() вызывается handlenavigation.

    facesContext
            .getApplication()
            .getNavigationHandler()
            .handleNavigation(facesContext, null,
                    (redirectPage != null ? redirectPage : ""));
    facesContext.renderResponse();

Обратите внимание, что, по моему опыту, viewId должна быть существующей страницей, отличной от той, на которую вам нужно перенаправить.

Приятно то, что facesmessage, который я установил с сообщением viewexpiredexception, теперь отображается на новой странице, с которой у меня раньше были всевозможные проблемы с перенаправлением.

person peater    schedule 15.02.2013