package org.jboss.seam.framework; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.NonUniqueResultException; import javax.transaction.SystemException; import org.jboss.seam.annotations.Transactional; import org.jboss.seam.persistence.PersistenceProvider; import org.jboss.seam.persistence.QueryParser; import org.jboss.seam.persistence.PersistenceProvider.Feature; import org.jboss.seam.transaction.Transaction; /** * A Query object for JPA. * * @author Gavin King * */ public class EntityQuery<E> extends Query<EntityManager, E> { private List<E> resultList; private E singleResult; private Long resultCount; private Map<String, String> hints; /** * Validate the query * * @throws IllegalStateException if the query is not valid */ @Override public void validate() { super.validate(); if ( getEntityManager()==null ) { throw new IllegalStateException("entityManager is null"); } if (!PersistenceProvider.instance().supportsFeature(Feature.WILDCARD_AS_COUNT_QUERY_SUBJECT)) { setUseWildcardAsCountQuerySubject(false); } } @Override @Transactional public boolean isNextExists() { return resultList!=null && getMaxResults()!=null && resultList.size() > getMaxResults(); } /** * Get the list of results this query returns * * Any changed restriction values will be applied */ @Transactional @Override public List<E> getResultList() { if ( isAnyParameterDirty() ) { refresh(); } initResultList(); return truncResultList(resultList); } private void initResultList() { if (resultList==null) { javax.persistence.Query query = createQuery(); resultList = query==null ? null : query.getResultList(); } } /** * Get a single result from the query * * Any changed restriction values will be applied * * @throws NonUniqueResultException if there is more than one result */ @Transactional @Override public E getSingleResult() { if (isAnyParameterDirty()) { refresh(); } initSingleResult(); return singleResult; } private void initSingleResult() { if ( singleResult==null) { javax.persistence.Query query = createQuery(); singleResult = (E) (query==null ? null : query.getSingleResult()); } } /** * Get the number of results this query returns * * Any changed restriction values will be applied */ @Transactional @Override public Long getResultCount() { if (isAnyParameterDirty()) { refresh(); } initResultCount(); return resultCount; } private void initResultCount() { if ( resultCount==null ) { javax.persistence.Query query = createCountQuery(); resultCount = query==null ? null : (Long) query.getSingleResult(); } } /** * The refresh method will cause the result to be cleared. The next access * to the result set will cause the query to be executed. * * This method <b>does not</b> cause the ejbql or restrictions to reread. * If you want to update the ejbql or restrictions you must call * {@link #setEjbql(String)} or {@link #setRestrictions(List)} */ @Override public void refresh() { super.refresh(); resultCount = null; resultList = null; singleResult = null; } public EntityManager getEntityManager() { return getPersistenceContext(); } public void setEntityManager(EntityManager entityManager) { setPersistenceContext(entityManager); } @Override protected String getPersistenceContextName() { return "entityManager"; } protected javax.persistence.Query createQuery() { parseEjbql(); evaluateAllParameters(); joinTransaction(); javax.persistence.Query query = getEntityManager().createQuery( getRenderedEjbql() ); setParameters( query, getQueryParameterValues(), 0 ); setParameters( query, getRestrictionParameterValues(), getQueryParameterValues().size() ); if ( getFirstResult()!=null) query.setFirstResult( getFirstResult() ); if ( getMaxResults()!=null) query.setMaxResults( getMaxResults()+1 ); //add one, so we can tell if there is another page if ( getHints()!=null ) { for ( Map.Entry<String, String> me: getHints().entrySet() ) { query.setHint(me.getKey(), me.getValue()); } } return query; } protected javax.persistence.Query createCountQuery() { parseEjbql(); evaluateAllParameters(); joinTransaction(); javax.persistence.Query query = getEntityManager().createQuery( getCountEjbql() ); setParameters( query, getQueryParameterValues(), 0 ); setParameters( query, getRestrictionParameterValues(), getQueryParameterValues().size() ); return query; } private void setParameters(javax.persistence.Query query, List<Object> parameters, int start) { for (int i=0; i<parameters.size(); i++) { Object parameterValue = parameters.get(i); if ( isRestrictionParameterSet(parameterValue) ) { query.setParameter( QueryParser.getParameterName(start + i), parameterValue ); } } } public Map<String, String> getHints() { return hints; } public void setHints(Map<String, String> hints) { this.hints = hints; } protected void joinTransaction() { try { Transaction.instance().enlist( getEntityManager() ); } catch (SystemException se) { throw new RuntimeException("could not join transaction", se); } } }