Java tutorial
/** * Copyright 2005-2013 The Kuali Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl2.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kuali.rice.krad.dao.impl; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.StringUtils; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.core.api.search.SearchOperator; import org.kuali.rice.core.api.util.RiceKeyConstants; import org.kuali.rice.core.api.util.type.TypeUtils; import org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria; import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria; import org.kuali.rice.core.framework.persistence.jpa.metadata.EntityDescriptor; import org.kuali.rice.core.framework.persistence.jpa.metadata.FieldDescriptor; import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager; import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbCharBooleanConversion; import org.kuali.rice.kns.service.KNSServiceLocator; import org.kuali.rice.krad.bo.InactivatableFromTo; import org.kuali.rice.krad.bo.PersistableBusinessObject; import org.kuali.rice.krad.bo.PersistableBusinessObjectExtension; import org.kuali.rice.krad.dao.LookupDao; import org.kuali.rice.krad.lookup.CollectionIncomplete; import org.kuali.rice.krad.lookup.LookupUtils; import org.kuali.rice.krad.service.DataDictionaryService; import org.kuali.rice.krad.service.KRADServiceLocator; import org.kuali.rice.krad.service.KRADServiceLocatorWeb; import org.kuali.rice.krad.service.PersistenceStructureService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.KRADPropertyConstants; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.dao.DataIntegrityViolationException; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceException; import java.lang.reflect.Field; import java.math.BigDecimal; import java.sql.Timestamp; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; /** * JPA implementation of the LookupDao interface * * @author Kuali Rice Team (rice.collab@kuali.org) */ public class LookupDaoJpa implements LookupDao { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LookupDao.class); private DateTimeService dateTimeService; private PersistenceStructureService persistenceStructureService; private DataDictionaryService dataDictionaryService; @PersistenceContext private EntityManager entityManager; public Long findCountByMap(Object example, Map formProps) { Criteria criteria = new Criteria(example.getClass().getName()); // iterate through the parameter map for key values search criteria Iterator propsIter = formProps.keySet().iterator(); while (propsIter.hasNext()) { String propertyName = (String) propsIter.next(); String searchValue = (String) formProps.get(propertyName); // if searchValue is empty and the key is not a valid property ignore if (StringUtils.isBlank(searchValue) || !(PropertyUtils.isWriteable(example, propertyName))) { continue; } // get property type which is used to determine type of criteria Class propertyType = ObjectUtils.getPropertyType(example, propertyName, persistenceStructureService); if (propertyType == null) { continue; } Boolean caseInsensitive = Boolean.TRUE; if (KRADServiceLocatorWeb.getDataDictionaryService().isAttributeDefined(example.getClass(), propertyName)) { // If forceUppercase is true, both the database value and the user entry should be converted to Uppercase -- so change the caseInsensitive to false since we don't need to // worry about the values not matching. However, if forceUppercase is false, make sure to do a caseInsensitive search because the database value and user entry // could be mixed case. Thus, caseInsensitive will be the opposite of forceUppercase. caseInsensitive = !KRADServiceLocatorWeb.getDataDictionaryService() .getAttributeForceUppercase(example.getClass(), propertyName); } if (caseInsensitive == null) { caseInsensitive = Boolean.TRUE; } boolean treatWildcardsAndOperatorsAsLiteral = KNSServiceLocator.getBusinessObjectDictionaryService() .isLookupFieldTreatWildcardsAndOperatorsAsLiteral(example.getClass(), propertyName); // build criteria if (!caseInsensitive) { // Verify that the searchValue is uppercased if caseInsensitive is false searchValue = searchValue.toUpperCase(); } addCriteria(propertyName, searchValue, propertyType, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria); } // execute query and return result list return (Long) new QueryByCriteria(entityManager, criteria).toCountQuery().getSingleResult(); } /** * Since 2.3 * This version of findCollectionBySearchHelper is needed for version compatibility. It allows executeSearch * to behave the same way as it did prior to 2.3. The value for searchResultsLimit will be retrieved from the * KNS version of LookupUtils. * * @see org.kuali.rice.krad.dao.LookupDao#findCollectionBySearchHelper(java.lang.Class, java.util.Map, boolean, * boolean) */ public Collection findCollectionBySearchHelper(Class businessObjectClass, Map formProps, boolean unbounded, boolean usePrimaryKeyValuesOnly) { Integer searchResultsLimit = org.kuali.rice.kns.lookup.LookupUtils .getSearchResultsLimit(businessObjectClass); return findCollectionBySearchHelper(businessObjectClass, formProps, unbounded, usePrimaryKeyValuesOnly, searchResultsLimit); } /** * @see org.kuali.rice.krad.dao.LookupDao#findCollectionBySearchHelper(java.lang.Class, java.util.Map, boolean, * boolean, Integer) * * If searchResultsLimit is null, the search results will not be limited by any other means. */ public Collection findCollectionBySearchHelper(Class businessObjectClass, Map formProps, boolean unbounded, boolean usePrimaryKeyValuesOnly, Integer searchResultsLimit) { PersistableBusinessObject businessObject = checkBusinessObjectClass(businessObjectClass); if (usePrimaryKeyValuesOnly) { return executeSearch(businessObjectClass, getCollectionCriteriaFromMapUsingPrimaryKeysOnly(businessObjectClass, formProps), unbounded, searchResultsLimit); } else { Criteria crit = getCollectionCriteriaFromMap(businessObject, formProps); return executeSearch(businessObjectClass, crit, unbounded, searchResultsLimit); } } public Criteria getCollectionCriteriaFromMap(PersistableBusinessObject example, Map formProps) { Criteria criteria = new Criteria(example.getClass().getName()); Iterator propsIter = formProps.keySet().iterator(); while (propsIter.hasNext()) { String propertyName = (String) propsIter.next(); Boolean caseInsensitive = Boolean.TRUE; if (KRADServiceLocatorWeb.getDataDictionaryService().isAttributeDefined(example.getClass(), propertyName)) { caseInsensitive = !KRADServiceLocatorWeb.getDataDictionaryService() .getAttributeForceUppercase(example.getClass(), propertyName); } if (caseInsensitive == null) { caseInsensitive = Boolean.TRUE; } boolean treatWildcardsAndOperatorsAsLiteral = KNSServiceLocator.getBusinessObjectDictionaryService() .isLookupFieldTreatWildcardsAndOperatorsAsLiteral(example.getClass(), propertyName); if (formProps.get(propertyName) instanceof Collection) { Iterator iter = ((Collection) formProps.get(propertyName)).iterator(); while (iter.hasNext()) { String searchValue = (String) iter.next(); if (!caseInsensitive) { // Verify that the searchValue is uppercased if caseInsensitive is false searchValue = searchValue.toUpperCase(); } if (!createCriteria(example, searchValue, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, formProps)) { throw new RuntimeException("Invalid value in Collection"); } } } else { String searchValue = (String) formProps.get(propertyName); if (!caseInsensitive) { // Verify that the searchValue is uppercased if caseInsensitive is false searchValue = searchValue.toUpperCase(); } if (!createCriteria(example, searchValue, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, formProps)) { continue; } } } return criteria; } public Criteria getCollectionCriteriaFromMapUsingPrimaryKeysOnly(Class businessObjectClass, Map formProps) { PersistableBusinessObject businessObject = checkBusinessObjectClass(businessObjectClass); Criteria criteria = new Criteria(businessObjectClass.getName()); List pkFields = persistenceStructureService.listPrimaryKeyFieldNames(businessObjectClass); Iterator pkIter = pkFields.iterator(); while (pkIter.hasNext()) { String pkFieldName = (String) pkIter.next(); String pkValue = (String) formProps.get(pkFieldName); if (StringUtils.isBlank(pkValue)) { throw new RuntimeException("Missing pk value for field " + pkFieldName + " when a search based on PK values only is performed."); } else { for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) { if (pkValue.contains(op.op())) { throw new RuntimeException("Value \"" + pkValue + "\" for PK field " + pkFieldName + " contains wildcard/operator characters."); } } } boolean treatWildcardsAndOperatorsAsLiteral = KNSServiceLocator.getBusinessObjectDictionaryService() .isLookupFieldTreatWildcardsAndOperatorsAsLiteral(businessObjectClass, pkFieldName); createCriteria(businessObject, pkValue, pkFieldName, false, treatWildcardsAndOperatorsAsLiteral, criteria); } return criteria; } private PersistableBusinessObject checkBusinessObjectClass(Class businessObjectClass) { if (businessObjectClass == null) { throw new IllegalArgumentException( "BusinessObject class passed to LookupDao findCollectionBySearchHelper... method was null"); } PersistableBusinessObject businessObject = null; try { businessObject = (PersistableBusinessObject) businessObjectClass.newInstance(); } catch (IllegalAccessException e) { throw new RuntimeException("LookupDao could not get instance of " + businessObjectClass.getName(), e); } catch (InstantiationException e) { throw new RuntimeException("LookupDao could not get instance of " + businessObjectClass.getName(), e); } return businessObject; } private Collection executeSearch(Class businessObjectClass, Criteria criteria, boolean unbounded, Integer searchResultsLimit) { Collection<PersistableBusinessObject> searchResults = new ArrayList<PersistableBusinessObject>(); Long matchingResultsCount = null; try { if (!unbounded && (searchResultsLimit != null)) { matchingResultsCount = (Long) new QueryByCriteria(entityManager, criteria).toCountQuery() .getSingleResult(); searchResults = new QueryByCriteria(entityManager, criteria).toQuery() .setMaxResults(searchResultsLimit).getResultList(); } else { searchResults = new QueryByCriteria(entityManager, criteria).toQuery().getResultList(); } if ((matchingResultsCount == null) || (matchingResultsCount.intValue() <= searchResultsLimit.intValue())) { matchingResultsCount = new Long(0); } // Temp solution for loading extension objects - need to find a // better way // Should look for a JOIN query, for the above query, that will grab // the PBOEs as well (1+n query problem) for (PersistableBusinessObject bo : searchResults) { if (bo.getExtension() != null) { PersistableBusinessObjectExtension boe = bo.getExtension(); EntityDescriptor entity = MetadataManager.getEntityDescriptor(bo.getExtension().getClass()); Criteria extensionCriteria = new Criteria(boe.getClass().getName()); for (FieldDescriptor fieldDescriptor : entity.getPrimaryKeys()) { try { Field field = bo.getClass().getDeclaredField(fieldDescriptor.getName()); field.setAccessible(true); extensionCriteria.eq(fieldDescriptor.getName(), field.get(bo)); } catch (Exception e) { LOG.error(e.getMessage(), e); } } try { boe = (PersistableBusinessObjectExtension) new QueryByCriteria(entityManager, extensionCriteria).toQuery().getSingleResult(); } catch (PersistenceException e) { } bo.setExtension(boe); } } // populate Person objects in business objects List bos = new ArrayList(); bos.addAll(searchResults); searchResults = bos; } catch (DataIntegrityViolationException e) { throw new RuntimeException("LookupDao encountered exception during executeSearch", e); } return new CollectionIncomplete(searchResults, matchingResultsCount); } /** * Return whether or not an attribute is writeable. This method is aware * that that Collections may be involved and handles them consistently with * the way in which OJB handles specifying the attributes of elements of a * Collection. * * @param o * @param p * @return * @throws IllegalArgumentException */ private boolean isWriteable(Object o, String p) throws IllegalArgumentException { if (null == o || null == p) { throw new IllegalArgumentException("Cannot check writeable status with null arguments."); } boolean b = false; // Try the easy way. if (!(PropertyUtils.isWriteable(o, p))) { // If that fails lets try to be a bit smarter, understanding that // Collections may be involved. if (-1 != p.indexOf('.')) { String[] parts = p.split("\\."); // Get the type of the attribute. Class c = ObjectUtils.getPropertyType(o, parts[0], persistenceStructureService); Object i = null; // If the next level is a Collection, look into the collection, // to find out what type its elements are. if (Collection.class.isAssignableFrom(c)) { Map<String, Class> m = persistenceStructureService.listCollectionObjectTypes(o.getClass()); c = m.get(parts[0]); } // Look into the attribute class to see if it is writeable. try { i = c.newInstance(); StringBuffer sb = new StringBuffer(); for (int x = 1; x < parts.length; x++) { sb.append(1 == x ? "" : ".").append(parts[x]); } b = isWriteable(i, sb.toString()); } catch (InstantiationException ie) { LOG.info(ie); } catch (IllegalAccessException iae) { LOG.info(iae); } } } else { b = true; } return b; } public boolean createCriteria(Object example, String searchValue, String propertyName, Object criteria) { return createCriteria(example, searchValue, propertyName, false, false, criteria); } public boolean createCriteria(Object example, String searchValue, String propertyName, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Object criteria) { return createCriteria(example, searchValue, propertyName, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, criteria, null); } public boolean createCriteria(Object example, String searchValue, String propertyName, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Object criteria, Map searchValues) { // if searchValue is empty and the key is not a valid property ignore if (!(criteria instanceof Criteria) || StringUtils.isBlank(searchValue) || !isWriteable(example, propertyName)) { return false; } // get property type which is used to determine type of criteria Class propertyType = ObjectUtils.getPropertyType(example, propertyName, persistenceStructureService); if (propertyType == null) { return false; } // build criteria if (example instanceof InactivatableFromTo) { if (KRADPropertyConstants.ACTIVE.equals(propertyName)) { addInactivateableFromToActiveCriteria(example, searchValue, (Criteria) criteria, searchValues); } else if (KRADPropertyConstants.CURRENT.equals(propertyName)) { addInactivateableFromToCurrentCriteria(example, searchValue, (Criteria) criteria, searchValues); } else if (!KRADPropertyConstants.ACTIVE_AS_OF_DATE.equals(propertyName)) { addCriteria(propertyName, searchValue, propertyType, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, (Criteria) criteria); } } else { addCriteria(propertyName, searchValue, propertyType, caseInsensitive, treatWildcardsAndOperatorsAsLiteral, (Criteria) criteria); } return true; } /** * @see org.kuali.rice.krad.dao.LookupDao#findObjectByMap(java.lang.Object, * java.util.Map) */ public Object findObjectByMap(Object example, Map formProps) { Criteria jpaCriteria = new Criteria(example.getClass().getName()); Iterator propsIter = formProps.keySet().iterator(); while (propsIter.hasNext()) { String propertyName = (String) propsIter.next(); String searchValue = ""; if (formProps.get(propertyName) != null) { searchValue = (formProps.get(propertyName)).toString(); } if (StringUtils.isNotBlank(searchValue) & PropertyUtils.isWriteable(example, propertyName)) { Class propertyType = ObjectUtils.getPropertyType(example, propertyName, persistenceStructureService); if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)) { if (propertyType.equals(Long.class)) { jpaCriteria.eq(propertyName, new Long(searchValue)); } else { jpaCriteria.eq(propertyName, new Integer(searchValue)); } } else if (TypeUtils.isTemporalClass(propertyType)) { jpaCriteria.eq(propertyName, parseDate(ObjectUtils.clean(searchValue))); } else { jpaCriteria.eq(propertyName, searchValue); } } } return new QueryByCriteria(entityManager, jpaCriteria).toQuery().getSingleResult(); } private void addCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, boolean treatWildcardsAndOperatorsAsLiteral, Criteria criteria) { String alias = ""; String[] keySplit = propertyName.split("\\."); if (keySplit.length > 1) { alias = keySplit[keySplit.length - 2]; String variableKey = keySplit[keySplit.length - 1]; for (int j = 0; j < keySplit.length - 1; j++) { if (StringUtils.contains(keySplit[j], Criteria.JPA_ALIAS_PREFIX)) { String tempKey = keySplit[j].substring( keySplit[j].indexOf('\'', keySplit[j].indexOf(Criteria.JPA_ALIAS_PREFIX)) + 1, keySplit[j].lastIndexOf('\'', keySplit[j].indexOf(Criteria.JPA_ALIAS_SUFFIX))); if (criteria.getAliasIndex(tempKey) == -1) { criteria.join(tempKey, tempKey, false, true); } } else { if (criteria.getAliasIndex(keySplit[j]) == -1) { criteria.join(keySplit[j], keySplit[j], false, true); } } } if (!StringUtils.contains(propertyName, "__JPA_ALIAS[[")) { propertyName = "__JPA_ALIAS[['" + alias + "']]__." + variableKey; } } if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue, SearchOperator.OR.op())) { addOrCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria); return; } if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue, SearchOperator.AND.op())) { addAndCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria); return; } if (StringUtils.containsIgnoreCase(propertyValue, SearchOperator.NULL.op())) { if (StringUtils.contains(propertyValue, SearchOperator.NOT.op())) { criteria.notNull(propertyName); } else { criteria.isNull(propertyName); } } else if (TypeUtils.isStringClass(propertyType)) { // KULRICE-85 : made string searches case insensitive - used new // DBPlatform function to force strings to upper case if (caseInsensitive) { // TODO: What to do here now that the JPA version does not extend platform aware? //propertyName = getDbPlatform().getUpperCaseFunction() + "(__JPA_ALIAS[[0]]__." + propertyName + ")"; if (StringUtils.contains(propertyName, "__JPA_ALIAS[[")) { propertyName = "UPPER(" + propertyName + ")"; } else { propertyName = "UPPER(__JPA_ALIAS[[0]]__." + propertyName + ")"; } propertyValue = propertyValue.toUpperCase(); } if (!treatWildcardsAndOperatorsAsLiteral && StringUtils.contains(propertyValue, SearchOperator.NOT.op())) { addNotCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria); } else if (!treatWildcardsAndOperatorsAsLiteral && propertyValue != null && (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op()) || propertyValue.startsWith(">") || propertyValue.startsWith("<"))) { addStringRangeCriteria(propertyName, propertyValue, criteria); } else { if (treatWildcardsAndOperatorsAsLiteral) { propertyValue = StringUtils.replace(propertyValue, "*", "\\*"); } criteria.like(propertyName, propertyValue); } } else if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)) { addNumericRangeCriteria(propertyName, propertyValue, criteria); } else if (TypeUtils.isTemporalClass(propertyType)) { addDateRangeCriteria(propertyName, propertyValue, criteria); } else if (TypeUtils.isBooleanClass(propertyType)) { String temp = ObjectUtils.clean(propertyValue); criteria.eq(propertyName, ("Y".equalsIgnoreCase(temp) || "T".equalsIgnoreCase(temp) || "1".equalsIgnoreCase(temp) || "true".equalsIgnoreCase(temp)) ? true : false); } else { LOG.error("not adding criterion for: " + propertyName + "," + propertyType + "," + propertyValue); } } /** * Translates criteria for active status to criteria on the active from and to fields * * @param example - business object being queried on * @param activeSearchValue - value for the active search field, should convert to boolean * @param criteria - Criteria object being built * @param searchValues - Map containing all search keys and values */ protected void addInactivateableFromToActiveCriteria(Object example, String activeSearchValue, Criteria criteria, Map searchValues) { Timestamp activeTimestamp = LookupUtils.getActiveDateTimestampForCriteria(searchValues); String activeBooleanStr = (String) (new OjbCharBooleanConversion()).javaToSql(activeSearchValue); if (OjbCharBooleanConversion.DATABASE_BOOLEAN_TRUE_STRING_REPRESENTATION.equals(activeBooleanStr)) { // (active from date <= date or active from date is null) and (date < active to date or active to date is null) Criteria criteriaBeginDate = new Criteria(example.getClass().getName()); criteriaBeginDate.lte(KRADPropertyConstants.ACTIVE_FROM_DATE, activeTimestamp); Criteria criteriaBeginDateNull = new Criteria(example.getClass().getName()); criteriaBeginDateNull.isNull(KRADPropertyConstants.ACTIVE_FROM_DATE); criteriaBeginDate.or(criteriaBeginDateNull); criteria.and(criteriaBeginDate); Criteria criteriaEndDate = new Criteria(example.getClass().getName()); criteriaEndDate.gt(KRADPropertyConstants.ACTIVE_TO_DATE, activeTimestamp); Criteria criteriaEndDateNull = new Criteria(example.getClass().getName()); criteriaEndDateNull.isNull(KRADPropertyConstants.ACTIVE_TO_DATE); criteriaEndDate.or(criteriaEndDateNull); criteria.and(criteriaEndDate); } else if (OjbCharBooleanConversion.DATABASE_BOOLEAN_FALSE_STRING_REPRESENTATION.equals(activeBooleanStr)) { // (date < active from date) or (active from date is null) or (date >= active to date) Criteria criteriaNonActive = new Criteria(example.getClass().getName()); criteriaNonActive.gt(KRADPropertyConstants.ACTIVE_FROM_DATE, activeTimestamp); Criteria criteriaBeginDateNull = new Criteria(example.getClass().getName()); criteriaBeginDateNull.isNull(KRADPropertyConstants.ACTIVE_FROM_DATE); criteriaNonActive.or(criteriaBeginDateNull); Criteria criteriaEndDate = new Criteria(example.getClass().getName()); criteriaEndDate.lte(KRADPropertyConstants.ACTIVE_TO_DATE, activeTimestamp); criteriaNonActive.or(criteriaEndDate); criteria.and(criteriaNonActive); } } /** * Translates criteria for current status to a sub-query on active begin date * * @param example - business object being queried on * @param currentSearchValue - value for the current search field, should convert to boolean * @param criteria - Criteria object being built */ protected void addInactivateableFromToCurrentCriteria(Object example, String currentSearchValue, Criteria criteria, Map searchValues) { Timestamp activeTimestamp = LookupUtils.getActiveDateTimestampForCriteria(searchValues); List<String> groupByFieldList = dataDictionaryService .getGroupByAttributesForEffectiveDating(example.getClass()); if (groupByFieldList == null) { return; } String alias = "c"; String jpql = " (select max(" + alias + "." + KRADPropertyConstants.ACTIVE_FROM_DATE + ") from " + example.getClass().getName() + " as " + alias + " where "; String activeDateDBStr = KRADServiceLocator.getDatabasePlatform() .getDateSQL(dateTimeService.toDateTimeString(activeTimestamp), null); jpql += alias + "." + KRADPropertyConstants.ACTIVE_FROM_DATE + " <= '" + activeDateDBStr + "'"; // join back to main query with the group by fields boolean firstGroupBy = true; String groupByJpql = ""; for (String groupByField : groupByFieldList) { if (!firstGroupBy) { groupByJpql += ", "; } jpql += " AND " + alias + "." + groupByField + " = " + criteria.getAlias() + "." + groupByField + " "; groupByJpql += alias + "." + groupByField; firstGroupBy = false; } jpql += " group by " + groupByJpql + " )"; String currentBooleanStr = (String) (new OjbCharBooleanConversion()).javaToSql(currentSearchValue); if (OjbCharBooleanConversion.DATABASE_BOOLEAN_TRUE_STRING_REPRESENTATION.equals(currentBooleanStr)) { jpql = criteria.getAlias() + "." + KRADPropertyConstants.ACTIVE_FROM_DATE + " in " + jpql; } else if (OjbCharBooleanConversion.DATABASE_BOOLEAN_FALSE_STRING_REPRESENTATION .equals(currentBooleanStr)) { jpql = criteria.getAlias() + "." + KRADPropertyConstants.ACTIVE_FROM_DATE + " not in " + jpql; } criteria.rawJpql(jpql); } private void addOrCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria) { addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.OR.op()); } private void addAndCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria) { addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.AND.op()); } private void addNotCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria) { String[] splitPropVal = StringUtils.split(propertyValue, SearchOperator.NOT.op()); int strLength = splitPropVal.length; // if more than one NOT operator assume an implicit and (i.e. !a!b = !a&!b) if (strLength > 1) { String expandedNot = "!" + StringUtils.join(splitPropVal, SearchOperator.AND.op() + SearchOperator.NOT.op()); // we know that since this method is called, treatWildcardsAndOperatorsAsLiteral is false addCriteria(propertyName, expandedNot, propertyType, caseInsensitive, false, criteria); } else { // only one so add a not like criteria.notLike(propertyName, splitPropVal[0]); } } private void addLogicalOperatorCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria, String splitValue) { String[] splitPropVal = StringUtils.split(propertyValue, splitValue); Criteria subCriteria = new Criteria("N/A"); for (int i = 0; i < splitPropVal.length; i++) { Criteria predicate = new Criteria("N/A"); // we know that since this method is called, treatWildcardsAndOperatorsAsLiteral is false addCriteria(propertyName, splitPropVal[i], propertyType, caseInsensitive, false, predicate); if (splitValue == SearchOperator.OR.op()) { subCriteria.or(predicate); } if (splitValue == SearchOperator.AND.op()) { subCriteria.and(predicate); } } criteria.and(subCriteria); } private java.sql.Date parseDate(String dateString) { dateString = dateString.trim(); try { return dateTimeService.convertToSqlDate(dateString); } catch (ParseException ex) { return null; } } private void addDateRangeCriteria(String propertyName, String propertyValue, Criteria criteria) { if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) { String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op()); criteria.between(propertyName, parseDate(ObjectUtils.clean(rangeValues[0])), parseDate(ObjectUtils.clean(rangeValues[1]))); } else if (propertyValue.startsWith(">=")) { criteria.gte(propertyName, parseDate(ObjectUtils.clean(propertyValue))); } else if (propertyValue.startsWith("<=")) { criteria.lte(propertyName, parseDate(ObjectUtils.clean(propertyValue))); } else if (propertyValue.startsWith(">")) { criteria.gt(propertyName, parseDate(ObjectUtils.clean(propertyValue))); } else if (propertyValue.startsWith("<")) { criteria.lt(propertyName, parseDate(ObjectUtils.clean(propertyValue))); } else { criteria.eq(propertyName, parseDate(ObjectUtils.clean(propertyValue))); } } private BigDecimal cleanNumeric(String value) { String cleanedValue = value.replaceAll("[^-0-9.]", ""); // ensure only one "minus" at the beginning, if any if (cleanedValue.lastIndexOf('-') > 0) { if (cleanedValue.charAt(0) == '-') { cleanedValue = "-" + cleanedValue.replaceAll("-", ""); } else { cleanedValue = cleanedValue.replaceAll("-", ""); } } // ensure only one decimal in the string int decimalLoc = cleanedValue.lastIndexOf('.'); if (cleanedValue.indexOf('.') != decimalLoc) { cleanedValue = cleanedValue.substring(0, decimalLoc).replaceAll("\\.", "") + cleanedValue.substring(decimalLoc); } try { return new BigDecimal(cleanedValue); } catch (NumberFormatException ex) { GlobalVariables.getMessageMap().putError(KRADConstants.DOCUMENT_ERRORS, RiceKeyConstants.ERROR_CUSTOM, new String[] { "Invalid Numeric Input: " + value }); return null; } } private void addNumericRangeCriteria(String propertyName, String propertyValue, Criteria criteria) { if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) { String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op()); criteria.between(propertyName, cleanNumeric(rangeValues[0]), cleanNumeric(rangeValues[1])); } else if (propertyValue.startsWith(">=")) { criteria.gte(propertyName, cleanNumeric(propertyValue)); } else if (propertyValue.startsWith("<=")) { criteria.lte(propertyName, cleanNumeric(propertyValue)); } else if (propertyValue.startsWith(">")) { criteria.gt(propertyName, cleanNumeric(propertyValue)); } else if (propertyValue.startsWith("<")) { criteria.lt(propertyName, cleanNumeric(propertyValue)); } else { criteria.eq(propertyName, cleanNumeric(propertyValue)); } } private void addStringRangeCriteria(String propertyName, String propertyValue, Criteria criteria) { if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) { String[] rangeValues = StringUtils.split(propertyValue, SearchOperator.BETWEEN.op()); criteria.between(propertyName, rangeValues[0], rangeValues[1]); } else if (propertyValue.startsWith(">=")) { criteria.gte(propertyName, ObjectUtils.clean(propertyValue)); } else if (propertyValue.startsWith("<=")) { criteria.lte(propertyName, ObjectUtils.clean(propertyValue)); } else if (propertyValue.startsWith(">")) { criteria.gt(propertyName, ObjectUtils.clean(propertyValue)); } else if (propertyValue.startsWith("<")) { criteria.lt(propertyName, ObjectUtils.clean(propertyValue)); } } /** * @param dateTimeService * the dateTimeService to set */ public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } /** * @return the entityManager */ public EntityManager getEntityManager() { return this.entityManager; } /** * @param entityManager the entityManager to set */ public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) { this.persistenceStructureService = persistenceStructureService; } public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { this.dataDictionaryService = dataDictionaryService; } }