001 package org.kuali.rice.krad.data.provider.query; 002 003 import org.kuali.rice.core.api.criteria.*; 004 005 import java.util.ArrayList; 006 import java.util.List; 007 008 /** 009 * Base class for QueryByCriteria lookups for both Jpa and Ojb PersistenceProvider 010 * implementations. This class implements the core api CriteriaLookupService, as that 011 * is the exact interface required, however this class is not intended to be defined 012 * as a "service", it is merely a helper. 013 */ 014 public abstract class DataObjectCriteriaQueryBase<C, Q> implements CriteriaQuery { 015 protected abstract QueryTranslator<C, Q> getQueryTranslator(); 016 protected abstract int getRowCount(Q query); 017 protected abstract int getIncludedRowCount(Q query, List rows); 018 protected abstract <T> List<T> getResults(Q query); 019 020 @Override 021 public <T> GenericQueryResults<T> lookup(Class<T> queryClass, QueryByCriteria criteria) { 022 return lookup(queryClass, criteria, LookupCustomizer.Builder.<T>create().build()); 023 } 024 025 @Override 026 public <T> GenericQueryResults<T> lookup(final Class<T> queryClass, final QueryByCriteria criteria, LookupCustomizer<T> customizer) { 027 if (queryClass == null) { 028 throw new IllegalArgumentException("queryClass is null"); 029 } 030 031 if (criteria == null) { 032 throw new IllegalArgumentException("criteria is null"); 033 } 034 035 if (customizer == null) { 036 throw new IllegalArgumentException("customizer is null"); 037 } 038 039 final C parent = getQueryTranslator().translateCriteria(queryClass, criteria.getPredicate(), customizer); 040 041 switch (criteria.getCountFlag()) { 042 case ONLY: 043 return forCountOnly(queryClass, criteria, parent); 044 case NONE: 045 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform()); 046 case INCLUDE: 047 return forRowResults(queryClass, criteria, parent, criteria.getCountFlag(), customizer.getResultTransform()); 048 default: throw new UnsupportedCountFlagException(criteria.getCountFlag()); 049 } 050 } 051 052 /** gets results where the actual rows are requested. */ 053 protected <T> GenericQueryResults<T> forRowResults(final Class<T> queryClass, final QueryByCriteria criteria, final C ojbCriteria, CountFlag flag, LookupCustomizer.Transform<T, T> transform) { 054 final Q query = getQueryTranslator().createQuery(queryClass, ojbCriteria); 055 final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create(); 056 057 getQueryTranslator().convertQueryFlags(criteria, query); 058 059 final List<T> rows = getResults(query); 060 if (flag == CountFlag.INCLUDE) { 061 results.setTotalRowCount(getIncludedRowCount(query, rows)); 062 } 063 064 if (criteria.getMaxResults() != null && rows.size() > criteria.getMaxResults()) { 065 results.setMoreResultsAvailable(true); 066 //remove the extra row that was returned 067 rows.remove(criteria.getMaxResults().intValue()); 068 } 069 070 results.setResults(transformResults(rows, transform)); 071 return results.build(); 072 } 073 074 /** gets results where only the count is requested. */ 075 protected <T> GenericQueryResults<T> forCountOnly(final Class<T> queryClass, final QueryByCriteria criteria, final C platformCriteria) { 076 final Q query = getQueryTranslator().createQuery(queryClass, platformCriteria); 077 final GenericQueryResults.Builder<T> results = GenericQueryResults.Builder.<T>create(); 078 results.setTotalRowCount(getRowCount(query)); 079 return results.build(); 080 } 081 082 protected static <T> List<T> transformResults(List<T> results, LookupCustomizer.Transform<T, T> transform) { 083 final List<T> list = new ArrayList<T>(); 084 for (T r : results) { 085 list.add(transform.apply(r)); 086 } 087 return list; 088 } 089 090 /** this is a fatal error since this implementation should support all known count flags. */ 091 protected static class UnsupportedCountFlagException extends RuntimeException { 092 protected UnsupportedCountFlagException(CountFlag flag) { 093 super("Unsupported predicate [" + String.valueOf(flag) + "]"); 094 } 095 } 096 }