2012-01-31 2 views
3

오랜 시간 사과 드리지만 정말 도움이 필요합니다. 프로젝트의 일환으로 현재 사용자가 처음 4 자 이상을 입력하고 결과를 입력하면 검색 결과 목록이 업데이트되는 검색 엔진을 만들고 있습니다. 검색 값은 텍스트 상자에 입력되지만 결과는 Richfaces 구성 요소 rich : extendedDataTable에 표시됩니다. 검색 값이 제거되면 결과 목록은 비어 있습니다. 그러나 몇 번 시도한 후에 컴포넌트 자체에 의해 throw 된 ConcurrentModificationException을 얻었습니다. 내가 찾고있는 초기 목록은 속성 파일에서옵니다 (사용자가 무언가를 입력 할 때마다 검색이 데이터베이스에 저장되는 것을 원하지 않기 때문에). 나는 몇 달 동안 머리를 두드렸다. 내가 뭘 놓치고 있니? 내가 한 일을 보여 드리겠습니다.Richfaces ExtendedDataTable을 사용하는 ConcurrentModificationException

검색 논리를 트리거해야하는 입력 텍스트입니다 (값이 4 자 미만이거나 사용자가 키를 누르면 테이블이 업데이트되지 않도록해야합니다.

<h:inputText id="firmname" value="#{ExtendedTableBean.searchValue}"> 
     <a4j:support reRender="resultsTable" onsubmit=" 
      if ((this.value.length<4 && this.value.length>0) || !returnunicode(event)) { 
       return false; 
      }" actionListener="#{ExtendedTableBean.searchForResults}" event="onkeyup" /> 
    </h:inputText> 

액션 리스너 목록을 갱신해야하는지이다 -, 화살표, 시프트 및 CTRL 같이이 함수는 "returnunicode (이벤트)")이다. 여기에 바로 InputText]를 아래 extendedDataTable은 다음과 같습니다

이제
<rich:extendedDataTable tableState="#{ExtendedTableBean.tableState}" var="item" 
          id="resultsTable" value="#{ExtendedTableBean.dataModel}"> 

      ... <%-- I'm listing columns here --%> 

    </rich:extendedDataTable> 

가 괜찮은지 어떤지, 내가 당신에게 백엔드 코드를 보여 드리고자합니다. 나는 내 문제에 중요한 논리 만 남겼다.

/* 
    * To change this template, choose Tools | Templates 
    * and open the template in the editor. 
    */ 

package com.beans; 

import java.io.FileInputStream; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.ConcurrentModificationException; 
import java.util.List; 
import java.util.Properties; 
import java.util.concurrent.CopyOnWriteArrayList; 
import javax.faces.context.FacesContext; 
import javax.faces.event.ActionEvent; 
import org.richfaces.model.DataProvider; 
import org.richfaces.model.ExtendedTableDataModel; 

public class ExtendedTableBean {  
    private String sortMode="single"; 
    private ExtendedTableDataModel<ResultObject> dataModel; 
    //ResultObject is a simple pojo and getResultsPerValue is a method that 
    //read the data from the properties file, assigns it to this pojo, and 
    //adds a pojo to the list 

    private Object tableState; 
    private List<ResultObject> results = new CopyOnWriteArrayList<ResultObject>(); 
    private List<ResultObject> selectedResults = 
              new CopyOnWriteArrayList<ResultObject>(); 

    private String searchValue; 

    /** 
     * This is the action listener that the user triggers, by typing the search value 
     */ 
    public void searchForResults(ActionEvent e) { 
     synchronized(results) { 
      results.clear(); 
     }   

     //I don't think it's necessary to clear results list all the time, but here 
     //I also make sure that we start searching if the value is at least 4 
     //characters long 
     if (this.searchValue.length() > 3) { 
      results.clear(); 
      updateTableList(); 
     } else { 
      results.clear(); 
     } 

     dataModel = null; // to force the dataModel to be updated. 
    } 

    public List<ResultObject> getResultsPerValue(String searchValue) { 
     List<ResultObject> resultsList = new CopyOnWriteArrayList<ResultObject>(); 

     //Logic for reading data from the properties file, populating ResultObject 
     //and adding it to the list 

     return resultsList; 
    } 

    /** 
     * This method updates a firm list, based on a search value 
     */ 
    public void updateTableList() { 
     try {    
      List<ResultObject> searchedResults = getResultsPerValue(searchValue); 

      //Once the results have been retrieved from the properties, empty 
      //current firm list and replace it with what was found. 

      synchronized(firms) { 
       firms.clear(); 
       firms.addAll(searchedFirms); 
      } 
     } catch(Throwable xcpt) { 
      //Exception handling 
     } 
    } 

    /** 
     * This is a recursive method, that's used to constantly keep updating the 
     * table list. 
     */ 
    public synchronized ExtendedTableDataModel<ResultObject> getDataModel() { 
     try { 
      if (dataModel == null) { 
       dataModel = new ExtendedTableDataModel<ResultObject>(
          new DataProvider<ResultObject>() { 
           public ResultObject getItemByKey(Object key) { 
            try { 
            for(ResultObject c : results) { 
             if (key.equals(getKey(c))){ 
              return c; 
             } 
            } 
            } catch (Exception ex) { 
            //Exception handling 
            } 
            return null; 
           } 

           public List<ResultObject> getItemsByRange(
                int firstRow, int endRow) { 
            return Collections.unmodifiableList(results.subList(firstRow, endRow)); 
           } 

           public Object getKey(ResultObject item) { 
            return item.getResultName(); 
           } 

           public int getRowCount() { 
            return results.size(); 
           } 
          }); 
      } 
     } catch (Exception ex) { 
      //Exception handling  
     } 

     return dataModel; 
    } 

    //Getters and setters 

} 

그리고, 해, ConcurrentModificationException가 발생 내가 말했듯이, 그것을 잘 작동하지만, 빠른 삭제하면 사용자 유형 빠르거나 (그것이 어떻게 정확히 잡기 어렵다). 여기가 정확히 어떻게 생겼는지입니다 : 나는 그것을 제거 할 수있는 방법 자바 코드의

WARNING: executePhase(RENDER_RESPONSE 6,[email protected]) threw exception 
java.util.ConcurrentModificationException 
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) 
    at java.util.AbstractList$Itr.next(AbstractList.java:343) 
    at org.richfaces.model.ExtendedTableDataModel.walk(ExtendedTableDataModel.java:108) 
    at org.ajax4jsf.component.UIDataAdaptorBase.walk(UIDataAdaptorBase.java:1156) 
    at org.richfaces.renderkit.AbstractExtendedRowsRenderer.encodeRows(AbstractExtendedRowsRenderer.java:159) 
    at org.richfaces.renderkit.AbstractExtendedRowsRenderer.encodeRows(AbstractExtendedRowsRenderer.java:142) 
    at org.richfaces.renderkit.AbstractExtendedRowsRenderer.encodeChildren(AbstractExtendedRowsRenderer.java:191) 
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:812) 
    at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:277) 
    at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:166) 
    at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:83) 
    at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:157) 
    ... 

동기화, 내 강한면, 나는 가장 중요한 오류의 원인이 될 것 모르는 적이있다. 리치 스 페이스 4.0은 richDataTable 구성 요소에 많은 변화를 가져 왔다는 것을 알고 있습니다.이 구성 요소는 이전에 문제 였고 지금은 해결되었다고 들었습니다. 그러나 전체 응용 프로그램을 Richfaces 4.0으로 업그레이드 할 시간이 없습니다 (2 단계에서 진행될 예정입니다.) 이것은 전체 프로젝트의 일부에 지나지 않습니다. 위에 설명 된 문제를 해결할 방법이 없다면 해결 방법이있을 수 있습니다. 아니면 비슷한 종류의 검색을 구현할 수있는 다른 방법이 있습니다. 일반 JSF를 사용하는 것입니다 (구현이 빠르면 빠름). 그 문제에 관해 어떤 종류의 도움이나 조언을 부탁드립니다. 코드가 충분히 이해할 수 있기를 바랍니다. 그러나 그렇지 않다면 알려주세요. 더 설명하겠습니다. 미리 감사드립니다. 정말 감사드립니다.

답변

2

문제는 서버로의 동시 아약스 호출입니다. a4j : support에서 "eventsQueue"속성을 사용하십시오. 일반적으로 모든 AJAX 구성 요소에서 항상 "eventsQueue"를 사용해야하며 동일한 페이지의 모든 "eventsQueue"는 동일한 대기열을 참조합니다.

또 다른 ajax 속성 인 "ajaxSingle"을 조사하고 싶을 것입니다.

+0

감사합니다. 정확하게 필요한 것입니다. 전에 ajaxSingle을 사용했는데 생각하지 않았습니다. 그러나 EventsQueue는 나에게 새로운 것이 었습니다. 그렇게 단순한 것으로 나타났습니다. 다시 한 번 감사드립니다. –

관련 문제