2013-11-20 143 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; 
    } 
}