2015-11-18 1 views
2

Я использую следующий стек:ошибка с omnifaces 1,10 при OmniPartialViewContext # StartDocument выполняет прозрачное перенаправление

  • PrimeFaces 5.3.1
  • MyFaces 2.2.8
  • OpenWebBeans 1.6.2
  • OmniFaces 1.10
  • DeltaSpike 1.5.1
  • Tomcat 8.0.28

AFAI понимает, что там важны только MyFaces и OmniFaces.

У меня есть ошибка, когда запрос ajax выполняется клиентом, чей сеанс истек, и когда доступ к странице контролируется с помощью ограничения безопасности < > в webapp web.xml.

В этом случае OmniPartialViewContext # startDocument выполняет «прозрачный переадресацию», чтобы обеспечить лучшее объяснение (см. https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/context/OmniPartialViewContext.java#L275) (эта функция не изменяется от версии 1.10 до текущей 1.11).

@Override 
    public void startDocument() throws IOException { 
     wrapped.startDocument(); 
     String loginURL = WebXml.INSTANCE.getFormLoginPage(); 

     if (loginURL != null) { 
      FacesContext facesContext = FacesContext.getCurrentInstance(); 
      String loginViewId = normalizeViewId(facesContext, loginURL); 

      if (loginViewId.equals(getViewId(facesContext))) { 
       String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri"); 

       if (originalURL != null) { 
        redirect(originalURL); 
       } 
      } 
     } 
    } 

Это проблема, потому что, выше в стеке, org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartialRendering делает строки 466 и следующее:

{ 
     String currentEncoding = writer.getCharacterEncoding(); 
     writer.writePreamble("<?xml version=\"1.0\" encoding=\""+ 
      (currentEncoding == null ? "UTF-8" : currentEncoding) +"\"?>"); 
     writer.startDocument(); 

     writer.writeAttribute("id", viewRoot.getContainerClientId(_facesContext),"id"); 

Таким образом, исключение вроде следующее возникает при попытке записать идентификатор, потому что ни один элемент в данный момент не открыт.

16-Nov-2015 16:36:35.980 SEVERE [http-apr-8444-exec-10] org.omnifaces.exceptionhandler.FullAjaxExceptionHandler.logException FullAjaxExceptionHandler: An exception occurred during rendering JSF ajax response. Error page '/error.xhtml' will be shown. 
java.lang.IllegalStateException: Must be called before the start element is closed (attribute 'id') 
     at org.apache.myfaces.shared.renderkit.html.HtmlResponseWriterImpl.writeAttribute(HtmlResponseWriterImpl.java:816) 
     at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109) 
     at org.apache.myfaces.context.PartialResponseWriterImpl.writeAttribute(PartialResponseWriterImpl.java:407) 
     at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109) 
     at javax.faces.context.ResponseWriterWrapper.writeAttribute(ResponseWriterWrapper.java:109) 
     at org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartialRendering(PartialViewContextImpl.java:473) 
     at org.apache.myfaces.context.servlet.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:415) 
     at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:60) 
     at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:85) 
     at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:516) 
     at javax.faces.component.UIComponentBase.encodeAll(UIComponentBase.java:541) 
     at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.renderView(FaceletViewDeclarationLanguage.java:1891) 
     at org.apache.myfaces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:313) 
     at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58) 
     at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58) 
     at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58) 
     at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58) 
     at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:58) 
     at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:116) 
     at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:267) 
     at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:111) 
     at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:31) 
     at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160) 
     at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:111) 
     at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:31) 
     at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160) 
     at javax.faces.webapp.FacesServlet.service(FacesServlet.java:200) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) 
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) 
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
     at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:720) 
     at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466) 
     at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391) 
     at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318) 
     at org.apache.catalina.authenticator.FormAuthenticator.forwardToLoginPage(FormAuthenticator.java:384) 
     at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:229) 
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577) 
     at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) 
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) 
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 
     at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) 
     at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:291) 
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) 
     at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) 
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) 
     at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2503) 
     at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2492) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
     at java.lang.Thread.run(Thread.java:745) 

Как я могу исправить это (Appart уронить OmniFaces, что на самом деле здорово, и что я действительно хотел бы сохранить. :-))?

ответ

2

В конце концов, я использую следующее решение, которое можно рассматривать как произведение вокруг, а латание MyFaces или OmniFaces вне моей досягаемости ...

Я добавляю свой собственный PartialViewContext в верхней части цепочки обработки. Таким образом, я могу выполнить чистое перенаправление по запросу ajax, когда вижу, что пытается получить страницу входа в систему.

Для этого нужно:

  • реализовать PartialViewContextFactory
  • Реализовать в PartialViewContext
  • объявить PartialViewContextFactory в файле лица-config.xml

Таким образом, в мой webapp faces-config.XML, я поставил:

<factory> 
    <partial-view-context-factory>fr.senat.context.SenatPartialViewContextFactory</partial-view-context-factory> 
</factory>  

Мой PartialViewContextFactory мертв прост:

package fr.senat.context; 

import javax.faces.context.FacesContext; 
import javax.faces.context.PartialViewContext; 
import javax.faces.context.PartialViewContextFactory; 
import lombok.Getter; 

/** 
* 
* @author lpenet 
*/ 
public class SenatPartialViewContextFactory extends PartialViewContextFactory { 
    @Getter 
    private final PartialViewContextFactory wrapped; 

    public SenatPartialViewContextFactory(PartialViewContextFactory wrapped) { 
      this.wrapped = wrapped; 
    } 

    @Override 
    public PartialViewContext getPartialViewContext(FacesContext context) { 
      return new SenatPartialViewContext(wrapped.getPartialViewContext(context)); 
    } 
} 

и PartialViewContext довольно просто тоже:

package fr.senat.context; 

import java.io.IOException; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.faces.component.UIViewRoot; 
import javax.faces.context.FacesContext; 
import javax.faces.context.PartialResponseWriter; 
import javax.faces.context.PartialViewContext; 
import javax.faces.context.PartialViewContextWrapper; 
import javax.faces.event.PhaseId; 
import javax.servlet.http.HttpServletRequest; 
import lombok.Getter; 
import org.apache.myfaces.context.servlet.PartialViewContextImpl; 
import org.omnifaces.config.WebXml; 
import static org.omnifaces.util.FacesLocal.getRequestAttribute; 
import static org.omnifaces.util.FacesLocal.getViewId; 
import static org.omnifaces.util.FacesLocal.normalizeViewId; 

/** 
* 
* @author lpenet 
*/ 
public class SenatPartialViewContext extends PartialViewContextWrapper { 

    @Getter 
    private final PartialViewContext wrapped; 

    public SenatPartialViewContext(PartialViewContext wrapped) { 
      this.wrapped = wrapped; 
    } 

    private void processPartialRendering() throws IOException 
    { 
     FacesContext facesContext = FacesContext.getCurrentInstance(); 
     UIViewRoot viewRoot = facesContext.getViewRoot(); 

     String loginURL = WebXml.INSTANCE.getFormLoginPage(); 
     if (loginURL != null) { 
      String loginViewId = normalizeViewId(facesContext, loginURL); 

      if (loginViewId.equals(getViewId(facesContext))) { 
        String originalURL = getRequestAttribute(facesContext, "javax.servlet.forward.request_uri"); 

        if (originalURL != null) { 
         PartialResponseWriter writer = facesContext.getPartialViewContext().getPartialResponseWriter(); 
         writer.startDocument(); 
         HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest(); 
         writer.redirect(request.getContextPath() + loginURL); 
         writer.endDocument(); 
         return; 
        } 
      } 
     } 

     wrapped.processPartial(PhaseId.RENDER_RESPONSE); 
    } 

    @Override 
    public void processPartial(PhaseId phaseId) 
    { 
     if (phaseId == PhaseId.RENDER_RESPONSE) 
     { 
      try { 
       processPartialRendering(); 
      } 
     catch (IOException ex) 
     { 
      Logger log = Logger.getLogger(PartialViewContextImpl.class.getName()); 
      if (log.isLoggable(Level.SEVERE)) 
      { 
       log.log(Level.SEVERE, "", ex); 
      } 

     } 
     } else { 
      wrapped.processPartial(phaseId); 
     } 
    } 

} 
+1

Круто, спасибо за решение! Я случайно воспроизвел проблему в тот же момент, когда вы отправили ответ. Сначала я проверю, работает ли это на Mojarra, и если да, то интегрируйте в OmniFaces 2.2. – BalusC

+1

Да, работает и в Мохарре. Это закончится с моментальным снимком 2.2. – BalusC

+0

В соответствующем билете https://github.com/omnifaces/omnifaces/issues/183#issuecomment-158347582, BalusC указал, что он будет в 1.12 тоже. –

Смежные вопросы