• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Seamless search using richfaces extendedDataTable

 
Ranch Hand
Posts: 38
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello, everyone. I apologize for being wordy, but I really need your help. In our project we have a seamless search (I hope it's the right term ;)). That is, a user types the value in a text box and while he types, the table gets updated. I was able to get that working, using Richfaces 3.3.3 component rich:extendedDataTable, however, after a few tries I get ConcurrentModificationException, thrown by the component itself. The initial list I am searching comes from the properties file (because I don't want the search to hit database every time the user types something). I've been banging my head over it for months. What am I missing? Let me show you what I've done:

This is the input text that should trigger the search logic (I make sure that the table does not get updated when the value is less than 4 characters or if the user presses keys, like arrows, shift, and ctrl - this function is "returnunicode(event)"):

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


Action listener is what should update the list. Here is the extendedDataTable, right below the inputText:

<rich:extendedDataTable selection="#{ExtendedTable.selection}"
tableState="#{ExtendedTable.tableState}" var="item" id="resultsTable" value="#{ExtendedTable.dataModel}">

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

</rich:extendedDataTable>


Now, if it's ok, I would like to show you the back-end code. I only left the logic that's important to my issue.

//The action listener itself
public void searchForResult(ActionEvent e) {
//Results is an ArrayList - a local variable, defined as an empty ArrayList, with getter and setter
synchronized(results) {
results.clear();
}

if (this.searchValue.length() > 3) {
results.clear();
updateTableList();
} else {
results.clear();
}

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

public void updateTableList() {
try {
//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
List<ResultObject> searchedResults = getResultsPerValue(this.searchValue);
synchronized(results) {
results.clear();
results.addAll(Collections.unmodifiableList(searchedResults));
}
} catch(Throwable xcpt) {
lgr.error(TM, xcpt);
}
lgr.debug("Exit");
}

//And finally, a dataModel getter, which is what causes the list to constantly get updated. DataModel (ExtendedTableDataModel<ResultObject> dataModel)
//is also defined as a local variable, but it doesn't have a setter, only this getter, which should get updated automatically, every time the value is changing
//and the results list is refreshed
public synchronized ExtendedTableDataModel<ResultObject> getDataModel() {
try {
if (dataModel == null) {
//If data model is empty, initialize it and fill it with the results currently in a result list
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 (ConcurrentModificationException cme) {
lgr.error(TM+ "$ExtendedTableDataModel.getItemByKey", cme);
}
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 (ConcurrentModificationException cme) {
return getDataModel();
}
return dataModel;
}


And like I said, it works fine, but either when too many calls are made to the back-end or the user types fast (it's hard to catch exactly when it happens), ConcurrentModificationException is thrown. Synchronization of the Java code has never been my strongest side, I don't know what would be causing it and, most importantly, how can I go about avoiding it. I'm aware, that Richfaces 4.0 has made a lot of changes to rich:extendedDataTable component, I've heard that this was an issue before and now it's resolved. However, I don't have time to upgrade the whole application to Richfaces 4.0 (it's going to be done in phase 2), this is just the small part of the whole project. Maybe there's a workaround? Or, perhaps, there are other ways to implement similar kind of search, using plain JSF (provided that they are quick enough to implement). I will appreciate any kind of help or advice on that. I hope the code is understandable enough, but if not, let me know, I'll explain further. Thank you in advance, I really appreciate it.
 
reply
    Bookmark Topic Watch Topic
  • New Topic