Strange behaviour of seam component in different roles
timtimgo Sep 16, 2010 9:47 AMHi,
I was just experimenting with seam @Roles and stumbled upon a weird behaviour. I'm using a List component in two Roles, one called fileListCon, the other one called fileListConAdd. When the page is called, I set some parameters on fileListCon in order to receive a different result list.
This works, when fileListCon.getResultList() is called before fileListConAdd.getResultList(). When calling the other way around, both return the same result list.
Does anyone have a clue why this happens?
Here is my setup:
The seam component:
The standard seam List component is modified to support fulltextsearch with hibernate search and lucene.
package com.ifta.lager.action; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.criterion.Restrictions; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Role; import org.jboss.seam.annotations.Roles; import com.ifta.lager.model.File; @Name("fileList") @Roles( { @Role(name = "fileListConAdd", scope = ScopeType.CONVERSATION), @Role(name = "fileListCon", scope = ScopeType.CONVERSATION), @Role(name = "fileListConAll", scope = ScopeType.CONVERSATION) }) public class FileList extends FullTextEntityQuery<File> { /** * */ private static final long serialVersionUID = 6158710691671984120L; private String childListOf = "komponenten"; private Integer parentId; public FileList() { setMaxResults(25); setOrderColumn("name"); setOrderDirection("asc"); setEjbql("select file from File file"); } @Override protected Class<File> getEntityClass() { return File.class; } private final String[] fields = { "name", "beschreibung" }; @Override protected String[] getSearchFields() { return fields; } @Override protected Criteria getCriteria() { Session session = (Session) getEntityManager().getDelegate(); Criteria criteria = session.createCriteria(File.class).createAlias( childListOf, "p").add(Restrictions.eq("p.id", parentId)); if (parentId != null) { return criteria; } return null; } /** * @return the childListOf */ public String getChildListOf() { return childListOf; } /** * @param childListOf * the childListOf to set */ public void setChildListOf(String childListOf) { if (!childListOf.equals(childListOf)) { parametersChanged(); } this.childListOf = childListOf; } /** * @return the parentId */ public Integer getParentId() { return parentId; } /** * @param parentId * the parentId to set */ public void setParentId(Integer parentId) { if (parentId != this.parentId) { parametersChanged(); } this.parentId = parentId; } /** * http://seamframework.org/Community/AccessComponentName * * @return will magically return the current seam component when called from * xhtml (Seam interceptors must be avail */ public Component getComponent() { return null; } }
It's parent:
package com.ifta.lager.action; import java.util.List; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.hibernate.Criteria; import org.hibernate.search.jpa.FullTextEntityManager; import org.hibernate.search.jpa.FullTextQuery; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Transactional; import org.jboss.seam.framework.EntityQuery; import org.jboss.seam.log.Log; public abstract class FullTextEntityQuery<E> extends EntityQuery<E> { /** * */ private static final long serialVersionUID = 4876483608027791290L; private String fulltextSearchString = "*"; @Logger Log logger; private List<E> resultList = null; private boolean parametersChanged = true; private Long resultSize; private Integer firstResult; private String orderColumn; private Integer maxResult; private String name; /** * Returns result list and notifies the corresponding tree to update */ @SuppressWarnings("unchecked") @Override public List<E> getResultList() { if (parametersChanged) { parametersChanged = false; try { FullTextQuery ftq; // Leading wildcards can easily cause an TooManyClausesException. Thus // we just match all documents with a MatchAllDocsQuery if (fulltextSearchString.equals("*") || fulltextSearchString.equals("")) { ftq = ((FullTextEntityManager) getEntityManager()) .createFullTextQuery(new MatchAllDocsQuery(), getEntityClass()) .setCriteriaQuery(this.getCriteria()); } else { QueryParser parser = new MultiFieldQueryParser(getSearchFields(), new StandardAnalyzer()); parser.setAllowLeadingWildcard(true); org.apache.lucene.search.Query luceneQuery = parser .parse(fulltextSearchString); ftq = ((FullTextEntityManager) getEntityManager()) .createFullTextQuery(luceneQuery, getEntityClass()) .setCriteriaQuery(this.getCriteria()); } if (getOrderColumn() != null) { Sort sort = new Sort(new SortField(getOrderColumn(), SortField.STRING, getOrderDirection().toLowerCase() .equals("desc"))); ftq.setSort(sort); } if (getFirstResult() != null) { ftq.setFirstResult(getFirstResult()); } if (getMaxResults() != null) { ftq.setMaxResults(getMaxResults()); } resultSize = new Long(ftq.getResultSize()); resultList = ftq.getResultList(); int hash = resultList.hashCode(); String name = this.name; } catch (ParseException ex) { logger.error("Search terms: #0, Error: #1", fulltextSearchString, ex); return null; } } return resultList; } /** * dummy method to allow templating */ public void doSearch() { parametersChanged = true; } protected abstract String[] getSearchFields(); protected abstract Class<E> getEntityClass(); @Override public void setOrderColumn(String orderColumn) { if (orderColumn != getOrderColumn()) parametersChanged = true; this.orderColumn = orderColumn; } public String getOrderColumn() { return orderColumn; } public void setFirstResult(Integer firstResult) { if (firstResult != getFirstResult()) parametersChanged = true; this.firstResult = firstResult; } public Integer getFirstResult() { if (firstResult == null) { return 0; } return firstResult; } @Override public void setMaxResults(Integer maxResults) { if (maxResults != getMaxResults()) parametersChanged = true; this.maxResult = maxResults; } public Integer getMaxResults() { return this.maxResult; } @Override public Long getResultCount() { if (parametersChanged || resultSize == null) { this.getResultList(); } return resultSize; } public boolean isPaginated() { return maxResult != null; } @Override @Transactional public boolean isNextExists() { return resultList != null && getMaxResults() != null && getFirstResult() + getResultList().size() < getResultCount(); } public boolean isParametersChanged() { return this.parametersChanged; } public void parametersChanged() { this.parametersChanged = true; } public void setFulltextSearchString(String fulltextSearchString) { parametersChanged = true; setFirstResult(0); this.fulltextSearchString = fulltextSearchString; } public String getFulltextSearchString() { return fulltextSearchString; } public void resetSearch() { setFulltextSearchString("*"); } protected Criteria getCriteria() { return null; } public void setName(String name) { this.name = name; } }
On the xhtml page:
#{fileListCon.component.getName()} #{fileListCon.resultList.hashCode()} #{fileListCon.resultList.size()} #{fileListConAdd.component.getName()} #{fileListConAdd.resultList.hashCode()} #{fileListConAdd.resultList.size()} #{fileListCon.component.getName()} #{fileListCon.resultList.hashCode()} #{fileListCon.resultList.size()}
This will result in the following output:
fileListCon 1 0
fileListConAdd -201530514 25
fileListCon 1 0
When resultListConAdd.getResultList() is called first
#{fileListConAdd.component.getName()} #{fileListConAdd.resultList.hashCode()} #{fileListConAdd.resultList.size()} #{fileListCon.component.getName()} #{fileListCon.resultList.hashCode()} #{fileListCon.resultList.size()} #{fileListCon.component.getName()} #{fileListCon.resultList.hashCode()} #{fileListCon.resultList.size()}
the result is:
fileListConAdd -1155361796 25
fileListCon -1155361796 25
fileListCon -1155361796 25
Notice that in the first result, the result count first is 0, then 25 and then again 0. This is the expected bahviour. Also the hashes of first and third resultList are not equal to the one in the middle.
In the second setup, all hashed and result counts are equal, but the should not.
I have spent quite a while debugging this but I didn't get anywhere.
Maybe somebody can give me a hint?
I greatly appreciate your help :-)
Timo