2012-07-18 114 views
2

我開發一個Tree組件,這可能會根據用戶輸入prunned。我將所有節點緩存起來,以便爲始終具有相同樹節點實例的primefaces組件模型提供緩存。Primefaces動態樹

但問題是,當我改變父子關係(刪除其中的一些),我總是得到併發修改例外......有什麼辦法來解決這個問題,還是我失去了一些東西。

在此先感謝。

/** 
* Recursively copy the hierarchy and prune not visible branches 
* @param originalNode node of the original hierarchy to be copied 
* @param parent parent node in the new hierarchy 
* @param visibleNodes set of nodes, which should be included in the new hierarchy 
* @param model model of the TreeAutompleteComponent 
* @return copy of the oroginal node in the new hierarchy 
*/ 
private TreeNode copyHierarchy(TreeNode originalNode, TreeNode parent, Set<TreeNode> visibleNodes, TreeAutocompleteModel model) { 
    if (!visibleNodes.contains(originalNode)) { 
     return null; 
    } 

    TreeNode newNode = model.getCompleteModelNodes().get(((NodeWrapper)originalNode.getData()).getIri());//new DefaultTreeNode(originalNode.getData(), parent); 
    for (int i = 0; i < originalNode.getChildCount(); i++) { 
     copyHierarchy((TreeNode) originalNode.getChildren().get(i), newNode, visibleNodes, model); 
    } 
    newNode.setParent(parent); //when removed, no exception occurs 
    return newNode; 
} 

例外

ava.util.ConcurrentModificationException 
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819) 
    at java.util.ArrayList$Itr.next(ArrayList.java:791) 
    at org.primefaces.component.tree.TreeRenderer.encodeTreeNodeChildren(TreeRenderer.java:284) 
    at org.primefaces.component.tree.TreeRenderer.encodeTreeNode(TreeRenderer.java:274) 
    at org.primefaces.component.tree.TreeRenderer.encodeMarkup(TreeRenderer.java:165) 
    at org.primefaces.component.tree.TreeRenderer.encodeEnd(TreeRenderer.java:96) 
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312) 
    at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304) 
    at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185) 
    at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304) 
    at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185) 
    at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304) 
    at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304) 
    at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:304) 
    at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779) 
    at com.sun.faces.renderkit.html_basic.CompositeRenderer.encodeChildren(CompositeRenderer.java:78) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779) 
    at javax.faces.render.Renderer.encodeChildren(Renderer.java:168) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845) 
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779) 
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) 
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782) 
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:424) 
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125) 
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121) 
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) 
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399) 
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317) 
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204) 
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:182) 
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
    at java.lang.Thread.run(Thread.java:722) 

回答

1

這是解決方案,工程。我還沒有本地化的實際問題,但我已經成功的解決方法一切......

public TreeNode constructActualModel(TreeAutocompleteMatcherIface matcher) { 
    if (prunedModel == null) { 
     eraseHierarchyStructure(); 
     prunedModel = copyHierarchy((TreeNode) completeModel, getVisibleNodes(matcher)); 
    } 
    return prunedModel; 
} 

/** 
* Recursively copy the hierarchy and prune not visible branches 
* @param originalNode node of the original hierarchy to be copied 
* @param visibleNodes set of nodes, which should be included in the new hierarchy 
* @param model model of the TreeAutompleteComponent 
* @return copy of the oroginal node in the new hierarchy 
*/ 
private TreeNode copyHierarchy(TreeNode originalNode, Set<TreeNode> visibleNodes) { 
    if (!visibleNodes.contains(originalNode)) { 
     return null; 
    } 

    TreeNode newNode = this.getCompleteModelNodes().get(((NodeWrapper) originalNode.getData()).getIri());//new DefaultTreeNode(originalNode.getData(), parent); 
    List<TreeNode> children = new ArrayList<TreeNode>(); 
    for (int i = 0; i < originalNode.getChildCount(); i++) { 
     TreeNode child = copyHierarchy((TreeNode) originalNode.getChildren().get(i), visibleNodes); 
     if(child != null){ 
      children.add(child); 
     } 
    } 
    ((DefaultTreeNode) newNode).setChildren(children); 
    return newNode; 
} 

private void eraseHierarchyStructure() { 
    for (TreeNode node : duplicateCompleteModelNodes.values()) { 
     node.setParent(null); 
    }  
} 

有必要做相反的方式 - 來獲得IMPL能夠調用setChildren方法,並在第一擦除等級...

2

您正在試圖修改當前正在iteratring在集合。
你有沒有嘗試過處理有關集合的副本而不是修改當前的副本?

http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

請注意,此異常不會始終指出對象已經 被同時被不同的線程修改。如果一個線程 發出方法調用的順序違反的 對象的合同,該對象可能拋出此異常。例如,如果一個線程 直接修改的集合,同時它遍歷 集合與快速失敗迭代器,迭代器都將拋出此 例外。

在您的遞歸函數,你有以下情形:

1步你來你的樹的葉子前:
比方說,你有一個父節點「5」中的獨子(葉)節點「11」。 (「11」具有「5」作爲其父項) 您開始遍歷子項(「11」),並對其調用copyHierarchy。
由於他沒有孩子,因此跳過循環,並且他的父母變爲newNode,例如「17」。
然後你返回一級。
你就應該要遍歷誰擁有「5」作爲它們的父節點,但是節點「11」其實已經有其父從「5」到「17」改變。

+0

我知道這個例外的含義。如果你看一下堆棧跟蹤,你會看到,異常不是由我的代碼觸發的,而是由primefaces觸發的。此外,這不能是多線程問題,因爲請求應該總是由一個線程處理... – malejpavouk 2012-07-18 11:31:48

+0

Hmz,有沒有其他代碼可以提供可以清除問題? – Lopina 2012-07-18 11:33:34

+0

我試圖用調試器來調查這個問題,但看起來,這個集合出於某種原因被JSF impl(在我的情況下是mojarra)修改,同時遍歷根節點的子節點。在EL解析(查找)表示子節點的組件期間發生修改。我真的認爲這是JSF的一個bug,但我試圖找出,如果我沒有做一些概念錯誤的事情。我可能會提供更多的代碼,只是評論你需要哪個部分(模板?),因爲這種方法似乎是唯一相關的部分... – malejpavouk 2012-07-18 11:40:50