2013-11-20 74 views
0

我有一個JSF應用程序,它使用幾個java類來執行java代碼的動態編譯。JSF 2.2應用程序ViewExpiredException

代碼寫入文本區域,並通過經由Ajax按h:commandButton進行編譯。

問題發生時,我按了2或3次以上編譯不同的代碼。

這裏是堆棧跟蹤:

javax.faces.application.ViewExpiredException: viewId:/home.xhtml - View /home.xhtml could not be restored. 
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:210) 
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:121) 
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) 
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) 
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) 
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) 
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) 
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260) 
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188) 
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) 
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) 
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) 
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) 
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) 
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) 
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) 
    at java.lang.Thread.run(Unknown Source) 

如果我的屬性transient=true設置爲f:view,問題停止,因爲狀態不保存,但限制我使用其他功能,例如保存我的源文件中數據庫供用戶稍後檢索。

home.xhtml

<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://xmlns.jcp.org/jsf/html" 
     xmlns:f="http://xmlns.jcp.org/jsf/core"> 
    <h:head> 
     <title>Home Page</title> 
    </h:head> 
    <h:body> 
     <f:view transient="true"> 
      <h:form prependId="false"> 
       <h:panelGrid columns="1"> 
        <h:inputTextarea id="codeArea" rows="25" cols="70" value="#{user.userInputCode}" /> 
        <h:outputText id="messages" value="#{user.compilationMessages}"/> 

       </h:panelGrid> 
       <h:commandButton value="Compile"> 
        <f:ajax execute="codeArea" render="messages" listener="#{user.compileCode()}"/> 
       </h:commandButton> 
      </h:form> 
     </f:view> 
    </h:body> 
</html> 

的UserBean

@Named(value = "user") 
@SessionScoped 
public class UserBean implements Serializable { 

    private String userInputCode; 
    private String compilationMessages; 
    private CompilerBean compiler; 

    public UserBean() { 
     compiler = new CompilerBean(); 
     userInputCode = compiler.getDefaultCodeModel(); 
    } 

    public String getUserInputCode() { 
     return userInputCode; 
    } 

    public void setUserInputCode(String userInputCode) { 
     this.userInputCode = userInputCode; 
    } 

    public String getCompilationMessages() { 
     return compilationMessages; 
    } 

    public void compileCode() throws Exception { 
     if (!compiler.isValidClass(userInputCode)) { 
      compilationMessages = "Please provide a correct class format"; 
     } else { 
      if (compiler.compile(userInputCode)) { 
       compilationMessages = "Compilation Success!"; 
      } else { 
       compilationMessages = compiler.getDiagnosticMessages(); 
      } 
     } 
    } 

編譯

public class CompilerBean implements CompilationInterface { 

    private JavaCompiler compiler; 
    private DiagnosticCollector diagCollector; 
    private StandardJavaFileManager fileManager; 
    private String sourceFile; 

    public CompilerBean() { 
     sourceFile = DEFAULT_SOURCEFILE; 
    } 

    public boolean compile(String inputCode) throws Exception { 
     compiler = ToolProvider.getSystemJavaCompiler(); 
     diagCollector = new DiagnosticCollector(); 
     fileManager = compiler.getStandardFileManager(diagCollector, null, null); 
     File outputFile = new File(CLASS_FILES_PATH); 
     fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputFile)); 
     String className = extractClassName(inputCode); 
     sourceFile = className + JAVA_POSTFIX; 
     JavaFileObject sourceObject = new CompilerJavaObject(sourceFile, inputCode); 
     Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject); 
     JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagCollector, null, null, fileObjects); 
     deleteCompiledFiles(); 
     return task.call(); 
    } 

    public String getDiagnosticMessages() { 
     String message = ""; 
     List<Diagnostic> diagErrors = diagCollector.getDiagnostics(); 
     for (Diagnostic d : diagErrors) { 
      message = ("Error: " + d.getLineNumber() + " Cause: " + d.getMessage(null)); 
     } 
     return message; 
    } 

    private void deleteCompiledFiles() { 
     File f = new File(CLASS_FILES_PATH); 
     for (File classFile : f.listFiles()) { 
      classFile.delete(); 
     } 
    } 

    public String getDefaultCodeModel() { 
     return DEFAULT_CLASS_MODEL; 
    } 

    public String getSourceFile() { 
     return sourceFile; 
    } 

    /* 
    * Extracts the class name from the input code 
    */ 
    private String extractClassName(String input) { 

     String className = input.replaceAll(COMMENTS_REGEX, ""); 
     className = className.replaceAll(IMPORTS_REGEX, ""); 
     className = className.replaceAll(CLASS_BODY, ""); 
     className = className.replaceAll(CLASS_REGEX, "").trim(); 
     return className; 
    } 

    /* 
    * Checks if the input code is in a valid class format 
    */ 
    public boolean isValidClass(String input) { 
     Pattern pat1 = Pattern.compile(COMMENTS_REGEX); 
     Pattern pat2 = Pattern.compile(IMPORTS_REGEX); 
     Pattern pat3 = Pattern.compile(CLASS_REGEX); 
     Matcher m1 = pat1.matcher(input); 
     Matcher m2 = pat2.matcher(input); 
     Matcher m3 = pat3.matcher(input); 
     return m3.lookingAt() || m1.lookingAt() || m2.lookingAt(); 
    } 
} 

編譯器使用2多個類一些字符串常量和擴展SimpleJavaFileObject一類的接口

+0

你能發佈home.xhtml的內容,它使用任何支持bean? – 8bitjunkie

+2

[javax.faces.application.ViewExpiredException:View無法恢復]的可能重複(http://stackoverflow.com/questions/3642919/javax-faces-application-viewexpiredexception-view-could-not-be-restored) –

+0

你是什麼意思'編譯java代碼'? – erencan

回答

0

有,你可以採取一些辦法:

  • 打開部分狀態在web.xml
<context-param> 
    <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name> 
    <param-value>true</param-value> 
</context-param> 
真正的節約
  • 增加會話中邏輯視圖的數量。請注意,JSF會緩存您的視圖,並且對該緩存有限制。
<context-param> 
    <param-name>com.sun.faces.NUMBER_OF_LOGICAL_VIEWS_IN_SESSION</param-name> 
    <param-value>50</param-value> 
</context-param> 
  • 在上面沒有解決您的問題,寫一個處理程序ViewExpiredException和編程恢復視圖的情況。這將刷新您的客戶端上的視圖(可能不是最佳的用戶體驗,雖然)
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 

import javax.faces.FacesException; 
import javax.faces.application.ViewHandler; 
import javax.faces.application.ViewHandlerWrapper; 
import javax.faces.component.UIViewRoot; 
import javax.faces.context.FacesContext; 



public class MyViewExpiredHandler extends ViewHandlerWrapper { 

    private ViewHandler wrapped; 

    private static Map<String, Boolean> viewsToProcess = new HashMap<String, Boolean>(); 
    //assuming these xhtmls throw ViewExpiredException 
    static {   
     viewsToProcess.put("/view/xxxx.xhtml", true); 
     viewsToProcess.put("/view/aaa.xhtml", true); 
     viewsToProcess.put("/view/yyy.xhtml", true); 
    } 

    public MyViewExpiredHandler(ViewHandler parent) { 
     this.wrapped = parent; 
    } 

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

    @Override 
    public UIViewRoot restoreView(FacesContext context, String viewId) { 
     UIViewRoot viewRoot = super.restoreView(context, viewId); 
     if(viewsToProcess.containsKey(viewId) && viewRoot == null) { 
      viewRoot = super.createView(context, viewId); 
      super.initView(context); 
      try { 
       super.renderView(context, viewRoot); 
      } catch (FacesException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     return viewRoot; 
    } 
}