001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.core.dao.ojb;
017:
018: import java.math.BigDecimal;
019: import java.text.ParseException;
020: import java.text.SimpleDateFormat;
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.commons.beanutils.PropertyUtils;
028: import org.apache.commons.lang.StringUtils;
029: import org.apache.ojb.broker.query.Criteria;
030: import org.apache.ojb.broker.query.Query;
031: import org.apache.ojb.broker.query.QueryFactory;
032: import org.apache.ojb.broker.query.ReportQueryByCriteria;
033: import org.kuali.RiceConstants;
034: import org.kuali.RiceKeyConstants;
035: import org.kuali.core.bo.PersistableBusinessObject;
036: import org.kuali.core.bo.user.UniversalUser;
037: import org.kuali.core.dao.LookupDao;
038: import org.kuali.core.lookup.CollectionIncomplete;
039: import org.kuali.core.lookup.LookupUtils;
040: import org.kuali.core.service.DateTimeService;
041: import org.kuali.core.service.PersistenceStructureService;
042: import org.kuali.core.util.GlobalVariables;
043: import org.kuali.core.util.ObjectUtils;
044: import org.kuali.core.util.TypeUtils;
045: import org.kuali.rice.KNSServiceLocator;
046: import org.springframework.dao.DataIntegrityViolationException;
047: import org.springmodules.orm.ojb.OjbOperationException;
048:
049: /**
050: * This class is the OJB implementation of the LookupDao interface.
051: */
052: public class LookupDaoOjb extends PlatformAwareDaoBaseOjb implements
053: LookupDao {
054: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
055: .getLogger(LookupDaoOjb.class);
056: private DateTimeService dateTimeService;
057: private PersistenceStructureService persistenceStructureService;
058:
059: public void setPersistenceStructureService(
060: PersistenceStructureService persistenceStructureService) {
061: this .persistenceStructureService = persistenceStructureService;
062: }
063:
064: // TODO WARNING: this does not support nested joins, because i don't have a test case
065: public Collection findCollectionBySearchHelperWithUniversalUserJoin(
066: Class businessObjectClass,
067: Map nonUniversalUserSearchCriteria,
068: Map universalUserSearchCriteria, boolean unbounded,
069: boolean usePrimaryKeyValuesOnly) {
070: PersistableBusinessObject businessObject = checkBusinessObjectClass(businessObjectClass);
071: Criteria criteria;
072: if (usePrimaryKeyValuesOnly) {
073: criteria = getCollectionCriteriaFromMapUsingPrimaryKeysOnly(
074: businessObjectClass, nonUniversalUserSearchCriteria);
075: } else {
076: criteria = getCollectionCriteriaFromMap(businessObject,
077: nonUniversalUserSearchCriteria);
078: Iterator universalUserReferenceItr = universalUserSearchCriteria
079: .keySet().iterator();
080: UniversalUser universalUserExample = new UniversalUser();
081: while (universalUserReferenceItr.hasNext()) {
082: String institutionalIdSourcePrimitivePropertyName = (String) universalUserReferenceItr
083: .next();
084: Map universalUserReferenceSearchCriteria = (Map) universalUserSearchCriteria
085: .get(institutionalIdSourcePrimitivePropertyName);
086: Iterator universalUserReferenceSearchCriterionItr = universalUserReferenceSearchCriteria
087: .keySet().iterator();
088: Criteria universalUserSubCriteria = new Criteria();
089: while (universalUserReferenceSearchCriterionItr
090: .hasNext()) {
091: String universalUserSearchFieldName = (String) universalUserReferenceSearchCriterionItr
092: .next();
093: Boolean caseInsensitive = Boolean.FALSE;
094: if (KNSServiceLocator.getDataDictionaryService()
095: .isAttributeDefined(businessObjectClass,
096: universalUserSearchFieldName)) {
097: caseInsensitive = !KNSServiceLocator
098: .getDataDictionaryService()
099: .getAttributeForceUppercase(
100: UniversalUser.class,
101: universalUserSearchFieldName);
102: }
103: if (caseInsensitive == null) {
104: caseInsensitive = Boolean.FALSE;
105: }
106: createCriteria(
107: universalUserExample,
108: (String) universalUserReferenceSearchCriteria
109: .get(universalUserSearchFieldName),
110: universalUserSearchFieldName,
111: caseInsensitive, universalUserSubCriteria);
112: }
113: ReportQueryByCriteria universalUserSubQuery = QueryFactory
114: .newReportQuery(UniversalUser.class,
115: universalUserSubCriteria);
116: universalUserSubQuery
117: .setAttributes(new String[] { "personUniversalIdentifier" });
118: criteria.addIn(
119: institutionalIdSourcePrimitivePropertyName,
120: universalUserSubQuery);
121: }
122: }
123: return executeSearch(businessObjectClass, criteria, unbounded);
124: }
125:
126: public Collection findCollectionBySearchHelper(
127: Class businessObjectClass, Map formProps,
128: boolean unbounded, boolean usePrimaryKeyValuesOnly) {
129: return findCollectionBySearchHelper(businessObjectClass,
130: formProps, unbounded, usePrimaryKeyValuesOnly, null);
131: }
132:
133: public Collection findCollectionBySearchHelper(
134: Class businessObjectClass, Map formProps,
135: boolean unbounded, boolean usePrimaryKeyValuesOnly,
136: Object additionalCriteria) {
137: PersistableBusinessObject businessObject = checkBusinessObjectClass(businessObjectClass);
138: if (usePrimaryKeyValuesOnly) {
139: return executeSearch(businessObjectClass,
140: getCollectionCriteriaFromMapUsingPrimaryKeysOnly(
141: businessObjectClass, formProps), unbounded);
142: } else {
143: Criteria crit = getCollectionCriteriaFromMap(
144: businessObject, formProps);
145: if (additionalCriteria != null
146: && additionalCriteria instanceof Criteria) {
147: crit.addAndCriteria((Criteria) additionalCriteria);
148: }
149: return executeSearch(businessObjectClass, crit, unbounded);
150: }
151: }
152:
153: /**
154: * Builds up criteria object based on the object and map.
155: */
156: public Criteria getCollectionCriteriaFromMap(
157: PersistableBusinessObject example, Map formProps) {
158: Criteria criteria = new Criteria();
159: Iterator propsIter = formProps.keySet().iterator();
160: while (propsIter.hasNext()) {
161: String propertyName = (String) propsIter.next();
162: if (formProps.get(propertyName) instanceof Collection) {
163: Iterator iter = ((Collection) formProps
164: .get(propertyName)).iterator();
165: while (iter.hasNext()) {
166: Boolean caseInsensitive = Boolean.FALSE;
167: if (KNSServiceLocator.getDataDictionaryService()
168: .isAttributeDefined(example.getClass(),
169: propertyName)) {
170: caseInsensitive = !KNSServiceLocator
171: .getDataDictionaryService()
172: .getAttributeForceUppercase(
173: example.getClass(),
174: propertyName);
175: }
176: if (caseInsensitive == null) {
177: caseInsensitive = Boolean.FALSE;
178: }
179: if (!createCriteria(example, (String) iter.next(),
180: propertyName, caseInsensitive
181: .booleanValue(), criteria)) {
182: throw new RuntimeException(
183: "Invalid value in Collection");
184: }
185: }
186: } else {
187: Boolean caseInsensitive = Boolean.FALSE;
188: if (KNSServiceLocator.getDataDictionaryService()
189: .isAttributeDefined(example.getClass(),
190: propertyName)) {
191: caseInsensitive = !KNSServiceLocator
192: .getDataDictionaryService()
193: .getAttributeForceUppercase(
194: example.getClass(), propertyName);
195: }
196: if (caseInsensitive == null) {
197: caseInsensitive = Boolean.FALSE;
198: }
199: if (!createCriteria(example, (String) formProps
200: .get(propertyName), propertyName,
201: caseInsensitive.booleanValue(), criteria)) {
202: continue;
203: }
204: }
205: }
206: return criteria;
207: }
208:
209: public Criteria getCollectionCriteriaFromMapUsingPrimaryKeysOnly(
210: Class businessObjectClass, Map formProps) {
211: PersistableBusinessObject businessObject = checkBusinessObjectClass(businessObjectClass);
212: Criteria criteria = new Criteria();
213: List pkFields = persistenceStructureService
214: .listPrimaryKeyFieldNames(businessObjectClass);
215: Iterator pkIter = pkFields.iterator();
216: while (pkIter.hasNext()) {
217: String pkFieldName = (String) pkIter.next();
218: String pkValue = (String) formProps.get(pkFieldName);
219:
220: if (StringUtils.isBlank(pkValue)) {
221: throw new RuntimeException(
222: "Missing pk value for field "
223: + pkFieldName
224: + " when a search based on PK values only is performed.");
225: } else if (StringUtils.indexOfAny(pkValue,
226: RiceConstants.QUERY_CHARACTERS) != -1) {
227: throw new RuntimeException("Value \"" + pkValue
228: + "\" for PK field " + pkFieldName
229: + " contains wildcard/operator characters.");
230: }
231: createCriteria(businessObject, pkValue, pkFieldName, false,
232: criteria);
233: }
234: return criteria;
235: }
236:
237: private PersistableBusinessObject checkBusinessObjectClass(
238: Class businessObjectClass) {
239: if (businessObjectClass == null) {
240: throw new IllegalArgumentException(
241: "BusinessObject class passed to LookupDaoOjb findCollectionBySearchHelper... method was null");
242: }
243: PersistableBusinessObject businessObject = null;
244: try {
245: businessObject = (PersistableBusinessObject) businessObjectClass
246: .newInstance();
247: } catch (IllegalAccessException e) {
248: throw new RuntimeException(
249: "LookupDaoOjb could not get instance of "
250: + businessObjectClass.getName(), e);
251: } catch (InstantiationException e) {
252: throw new RuntimeException(
253: "LookupDaoOjb could not get instance of "
254: + businessObjectClass.getName(), e);
255: }
256: return businessObject;
257: }
258:
259: private Collection executeSearch(Class businessObjectClass,
260: Criteria criteria, boolean unbounded) {
261: Collection searchResults = new ArrayList();
262: Long matchingResultsCount = null;
263: try {
264: Integer searchResultsLimit = LookupUtils
265: .getApplicationSearchResultsLimit();
266: if (!unbounded && (searchResultsLimit != null)) {
267: matchingResultsCount = new Long(
268: getPersistenceBrokerTemplate().getCount(
269: QueryFactory.newQuery(
270: businessObjectClass, criteria)));
271: LookupUtils.applySearchResultsLimit(criteria,
272: getDbPlatform());
273: }
274: if ((matchingResultsCount == null)
275: || (matchingResultsCount.intValue() <= searchResultsLimit
276: .intValue())) {
277: matchingResultsCount = new Long(0);
278: }
279: searchResults = getPersistenceBrokerTemplate()
280: .getCollectionByQuery(
281: QueryFactory.newQuery(businessObjectClass,
282: criteria));
283: // populate UniversalUser objects in business objects
284: List bos = new ArrayList();
285: bos.addAll(searchResults);
286: searchResults = bos;
287: } catch (OjbOperationException e) {
288: throw new RuntimeException(
289: "LookupDaoOjb encountered exception during executeSearch",
290: e);
291: } catch (DataIntegrityViolationException e) {
292: throw new RuntimeException(
293: "LookupDaoOjb encountered exception during executeSearch",
294: e);
295: }
296: return new CollectionIncomplete(searchResults,
297: matchingResultsCount);
298: }
299:
300: /**
301: * Return whether or not an attribute is writeable. This method is aware that that Collections
302: * may be involved and handles them consistently with the way in which OJB handles specifying
303: * the attributes of elements of a Collection.
304: *
305: * @param o
306: * @param p
307: * @return
308: * @throws IllegalArgumentException
309: */
310: private boolean isWriteable(Object o, String p)
311: throws IllegalArgumentException {
312:
313: if (null == o || null == p) {
314:
315: throw new IllegalArgumentException(
316: "Cannot check writeable status with null arguments.");
317:
318: }
319:
320: boolean b = false;
321:
322: // Try the easy way.
323: if (!(PropertyUtils.isWriteable(o, p))) {
324:
325: // If that fails lets try to be a bit smarter, understanding that Collections may be involved.
326: if (-1 != p.indexOf('.')) {
327:
328: String[] parts = p.split("\\.");
329:
330: // Get the type of the attribute.
331: Class c = ObjectUtils.getPropertyType(o, parts[0],
332: persistenceStructureService);
333:
334: Object i = null;
335:
336: // If the next level is a Collection, look into the collection, to find out what type its elements are.
337: if (Collection.class.isAssignableFrom(c)) {
338:
339: Map<String, Class> m = persistenceStructureService
340: .listCollectionObjectTypes(o.getClass());
341: c = m.get(parts[0]);
342:
343: }
344:
345: // Look into the attribute class to see if it is writeable.
346: try {
347:
348: i = c.newInstance();
349:
350: StringBuffer sb = new StringBuffer();
351: for (int x = 1; x < parts.length; x++) {
352: sb.append(1 == x ? "" : ".").append(parts[x]);
353: }
354: b = isWriteable(i, sb.toString());
355:
356: } catch (InstantiationException ie) {
357: LOG.info(ie);
358: } catch (IllegalAccessException iae) {
359: LOG.info(iae);
360: }
361:
362: }
363:
364: } else {
365:
366: b = true;
367:
368: }
369:
370: return b;
371:
372: }
373:
374: public boolean createCriteria(Object example, String searchValue,
375: String propertyName, Criteria criteria) {
376: return createCriteria(example, searchValue, propertyName,
377: false, criteria);
378: }
379:
380: public boolean createCriteria(Object example, String searchValue,
381: String propertyName, boolean caseInsensitive,
382: Criteria criteria) {
383:
384: // if searchValue is empty and the key is not a valid property ignore
385: if (StringUtils.isBlank(searchValue)
386: || !isWriteable(example, propertyName)) {
387:
388: return false;
389:
390: }
391:
392: // get property type which is used to determine type of criteria
393: Class propertyType = ObjectUtils.getPropertyType(example,
394: propertyName, persistenceStructureService);
395: if (propertyType == null) {
396: return false;
397: }
398:
399: // build criteria
400: addCriteria(propertyName, searchValue, propertyType,
401: caseInsensitive, criteria);
402: return true;
403: }
404:
405: /**
406: * Find count of records meeting criteria based on the object and map.
407: */
408: public Long findCountByMap(Object example, Map formProps) {
409: Criteria criteria = new Criteria();
410: // iterate through the parameter map for key values search criteria
411: Iterator propsIter = formProps.keySet().iterator();
412: while (propsIter.hasNext()) {
413: String propertyName = (String) propsIter.next();
414: String searchValue = (String) formProps.get(propertyName);
415:
416: // if searchValue is empty and the key is not a valid property ignore
417: if (StringUtils.isBlank(searchValue)
418: || !(PropertyUtils.isWriteable(example,
419: propertyName))) {
420: continue;
421: }
422:
423: // get property type which is used to determine type of criteria
424: Class propertyType = ObjectUtils.getPropertyType(example,
425: propertyName, persistenceStructureService);
426: if (propertyType == null) {
427: continue;
428: }
429: Boolean caseInsensitive = Boolean.FALSE;
430: if (KNSServiceLocator.getDataDictionaryService()
431: .isAttributeDefined(example.getClass(),
432: propertyName)) {
433: caseInsensitive = !KNSServiceLocator
434: .getDataDictionaryService()
435: .getAttributeForceUppercase(example.getClass(),
436: propertyName);
437: }
438: if (caseInsensitive == null) {
439: caseInsensitive = Boolean.FALSE;
440: }
441:
442: // build criteria
443: addCriteria(propertyName, searchValue, propertyType,
444: caseInsensitive, criteria);
445: }
446:
447: // execute query and return result list
448: Query query = QueryFactory.newQuery(example.getClass(),
449: criteria);
450:
451: return new Long(getPersistenceBrokerTemplate().getCount(query));
452: }
453:
454: /**
455: * @see org.kuali.core.dao.LookupDao#findObjectByMap(java.lang.Object, java.util.Map)
456: */
457: public Object findObjectByMap(Object example, Map formProps) {
458: Criteria criteria = new Criteria();
459:
460: // iterate through the parameter map for key values search criteria
461: Iterator propsIter = formProps.keySet().iterator();
462: while (propsIter.hasNext()) {
463: String propertyName = (String) propsIter.next();
464: String searchValue = "";
465: if (formProps.get(propertyName) != null) {
466: searchValue = (formProps.get(propertyName)).toString();
467: }
468:
469: if (StringUtils.isNotBlank(searchValue)
470: & PropertyUtils.isWriteable(example, propertyName)) {
471: Class propertyType = ObjectUtils.getPropertyType(
472: example, propertyName,
473: persistenceStructureService);
474: if (TypeUtils.isIntegralClass(propertyType)
475: || TypeUtils.isDecimalClass(propertyType)) {
476: criteria.addEqualTo(propertyName,
477: cleanNumeric(searchValue));
478: } else if (TypeUtils.isTemporalClass(propertyType)) {
479: criteria.addEqualTo(propertyName,
480: parseDate(ObjectUtils.clean(searchValue)));
481: } else {
482: criteria.addEqualTo(propertyName, searchValue);
483: }
484: }
485: }
486:
487: // execute query and return result list
488: Query query = QueryFactory.newQuery(example.getClass(),
489: criteria);
490: return getPersistenceBrokerTemplate().getObjectByQuery(query);
491: }
492:
493: /**
494: * Adds to the criteria object based on the property type and any query characters given.
495: */
496: private void addCriteria(String propertyName, String propertyValue,
497: Class propertyType, boolean caseInsensitive,
498: Criteria criteria) {
499:
500: if (StringUtils.contains(propertyValue,
501: RiceConstants.OR_LOGICAL_OPERATOR)) {
502: addOrCriteria(propertyName, propertyValue, propertyType,
503: caseInsensitive, criteria);
504: return;
505: }
506:
507: if (StringUtils.contains(propertyValue,
508: RiceConstants.AND_LOGICAL_OPERATOR)) {
509: addAndCriteria(propertyName, propertyValue, propertyType,
510: caseInsensitive, criteria);
511: return;
512: }
513:
514: if (TypeUtils.isStringClass(propertyType)) {
515: // KULRICE-85 : made string searches case insensitive - used new DBPlatform function to force strings to upper case
516: if (caseInsensitive) {
517: propertyName = getDbPlatform().getUpperCaseFunction()
518: + "(" + propertyName + ")";
519: propertyValue = propertyValue.toUpperCase();
520: }
521: if (StringUtils.contains(propertyValue,
522: RiceConstants.NOT_LOGICAL_OPERATOR)) {
523: addNotCriteria(propertyName, propertyValue,
524: propertyType, caseInsensitive, criteria);
525: } else if (StringUtils.contains(propertyValue, "..")
526: || StringUtils.contains(propertyValue, ">")
527: || StringUtils.contains(propertyValue, "<")
528: || StringUtils.contains(propertyValue, ">=")
529: || StringUtils.contains(propertyValue, "<=")) {
530: addStringRangeCriteria(propertyName, propertyValue,
531: criteria);
532: } else {
533: criteria.addLike(propertyName, propertyValue);
534: }
535: } else if (TypeUtils.isIntegralClass(propertyType)
536: || TypeUtils.isDecimalClass(propertyType)) {
537: addNumericRangeCriteria(propertyName, propertyValue,
538: criteria);
539: } else if (TypeUtils.isTemporalClass(propertyType)) {
540: addDateRangeCriteria(propertyName, propertyValue, criteria);
541: } else if (TypeUtils.isBooleanClass(propertyType)) {
542: criteria.addEqualTo(propertyName, ObjectUtils
543: .clean(propertyValue));
544: } else {
545: LOG.error("not adding criterion for: " + propertyName + ","
546: + propertyType + "," + propertyValue);
547: }
548: }
549:
550: /**
551: * @param propertyName
552: * @param propertyValue
553: * @param propertyType
554: * @param criteria
555: */
556: private void addOrCriteria(String propertyName,
557: String propertyValue, Class propertyType,
558: boolean caseInsensitive, Criteria criteria) {
559: addLogicalOperatorCriteria(propertyName, propertyValue,
560: propertyType, caseInsensitive, criteria,
561: RiceConstants.OR_LOGICAL_OPERATOR);
562: }
563:
564: /**
565: * @param propertyName
566: * @param propertyValue
567: * @param propertyType
568: * @param criteria
569: */
570: private void addAndCriteria(String propertyName,
571: String propertyValue, Class propertyType,
572: boolean caseInsensitive, Criteria criteria) {
573: addLogicalOperatorCriteria(propertyName, propertyValue,
574: propertyType, caseInsensitive, criteria,
575: RiceConstants.AND_LOGICAL_OPERATOR);
576: }
577:
578: private void addNotCriteria(String propertyName,
579: String propertyValue, Class propertyType,
580: boolean caseInsensitive, Criteria criteria) {
581:
582: String[] splitPropVal = StringUtils.split(propertyValue,
583: RiceConstants.NOT_LOGICAL_OPERATOR);
584:
585: int strLength = splitPropVal.length;
586: // if more than one NOT operator assume an implicit and (i.e. !a!b = !a&!b)
587: if (strLength > 1) {
588: String expandedNot = "!"
589: + StringUtils
590: .join(
591: splitPropVal,
592: RiceConstants.AND_LOGICAL_OPERATOR
593: + RiceConstants.NOT_LOGICAL_OPERATOR);
594: addCriteria(propertyName, expandedNot, propertyType,
595: caseInsensitive, criteria);
596: } else {
597: // only one so add a not like
598: criteria.addNotLike(propertyName, splitPropVal[0]);
599: }
600: }
601:
602: /**
603: * Builds a sub criteria object joined with an 'AND' or 'OR' (depending on splitValue) using the split values of propertyValue. Then joins back the
604: * sub criteria to the main criteria using an 'AND'.
605: */
606: private void addLogicalOperatorCriteria(String propertyName,
607: String propertyValue, Class propertyType,
608: boolean caseInsensitive, Criteria criteria,
609: String splitValue) {
610: String[] splitPropVal = StringUtils.split(propertyValue,
611: splitValue);
612:
613: Criteria subCriteria = new Criteria();
614: for (int i = 0; i < splitPropVal.length; i++) {
615: Criteria predicate = new Criteria();
616:
617: addCriteria(propertyName, splitPropVal[i], propertyType,
618: caseInsensitive, predicate);
619: if (splitValue == RiceConstants.OR_LOGICAL_OPERATOR) {
620: subCriteria.addOrCriteria(predicate);
621: }
622: if (splitValue == RiceConstants.AND_LOGICAL_OPERATOR) {
623: subCriteria.addAndCriteria(predicate);
624: }
625: }
626:
627: criteria.addAndCriteria(subCriteria);
628: }
629:
630: private java.sql.Date parseDate(String dateString) {
631: dateString = dateString.trim();
632: try {
633: return dateTimeService.convertToSqlDate(dateString);
634: } catch (ParseException ex) {
635: return null;
636: }
637: }
638:
639: /**
640: * Adds to the criteria object based on query characters given
641: */
642: private void addDateRangeCriteria(String propertyName,
643: String propertyValue, Criteria criteria) {
644:
645: if (StringUtils.contains(propertyValue, "..")) {
646: String[] rangeValues = StringUtils.split(propertyValue,
647: "..");
648: criteria.addBetween(propertyName, parseDate(ObjectUtils
649: .clean(rangeValues[0])), parseDate(ObjectUtils
650: .clean(rangeValues[1])));
651: } else if (propertyValue.startsWith(">")) {
652: criteria.addGreaterThan(propertyName, parseDate(ObjectUtils
653: .clean(propertyValue)));
654: } else if (propertyValue.startsWith("<")) {
655: criteria.addLessThan(propertyName, parseDate(ObjectUtils
656: .clean(propertyValue)));
657: } else if (propertyValue.startsWith(">=")) {
658: criteria.addGreaterOrEqualThan(propertyName,
659: parseDate(ObjectUtils.clean(propertyValue)));
660: } else if (propertyValue.startsWith("<=")) {
661: criteria.addLessOrEqualThan(propertyName,
662: parseDate(ObjectUtils.clean(propertyValue)));
663: } else {
664: criteria.addEqualTo(propertyName, parseDate(ObjectUtils
665: .clean(propertyValue)));
666: }
667: }
668:
669: private BigDecimal cleanNumeric(String value) {
670: String cleanedValue = value.replaceAll("[^-0-9.]", "");
671: // ensure only one "minus" at the beginning, if any
672: if (cleanedValue.lastIndexOf('-') > 0) {
673: if (cleanedValue.charAt(0) == '-') {
674: cleanedValue = "-" + cleanedValue.replaceAll("-", "");
675: } else {
676: cleanedValue = cleanedValue.replaceAll("-", "");
677: }
678: }
679: // ensure only one decimal in the string
680: int decimalLoc = cleanedValue.lastIndexOf('.');
681: if (cleanedValue.indexOf('.') != decimalLoc) {
682: cleanedValue = cleanedValue.substring(0, decimalLoc)
683: .replaceAll("\\.", "")
684: + cleanedValue.substring(decimalLoc);
685: }
686: try {
687: return new BigDecimal(cleanedValue);
688: } catch (NumberFormatException ex) {
689: GlobalVariables.getErrorMap().putError(
690: RiceConstants.DOCUMENT_ERRORS,
691: RiceKeyConstants.ERROR_CUSTOM,
692: new String[] { "Invalid Numeric Input: " + value });
693: return null;
694: }
695: }
696:
697: /**
698: * Adds to the criteria object based on query characters given
699: */
700: private void addNumericRangeCriteria(String propertyName,
701: String propertyValue, Criteria criteria) {
702:
703: if (StringUtils.contains(propertyValue, "..")) {
704: String[] rangeValues = StringUtils.split(propertyValue,
705: "..");
706: criteria.addBetween(propertyName,
707: cleanNumeric(rangeValues[0]),
708: cleanNumeric(rangeValues[1]));
709: } else if (propertyValue.startsWith(">")) {
710: criteria.addGreaterThan(propertyName,
711: cleanNumeric(propertyValue));
712: } else if (propertyValue.startsWith("<")) {
713: criteria.addLessThan(propertyName,
714: cleanNumeric(propertyValue));
715: } else if (propertyValue.startsWith(">=")) {
716: criteria.addGreaterOrEqualThan(propertyName,
717: cleanNumeric(propertyValue));
718: } else if (propertyValue.startsWith("<=")) {
719: criteria.addLessOrEqualThan(propertyName,
720: cleanNumeric(propertyValue));
721: } else {
722: criteria.addEqualTo(propertyName,
723: cleanNumeric(propertyValue));
724: }
725: }
726:
727: /**
728: * Adds to the criteria object based on query characters given
729: */
730: private void addStringRangeCriteria(String propertyName,
731: String propertyValue, Criteria criteria) {
732:
733: if (StringUtils.contains(propertyValue, "..")) {
734: String[] rangeValues = StringUtils.split(propertyValue,
735: "..");
736: criteria.addBetween(propertyName, rangeValues[0],
737: rangeValues[1]);
738:
739: //To fix a bug related on number of digits issues for searching String field with range operator
740: Criteria orCriteria = new Criteria();
741: orCriteria.addGreaterThan(propertyName, rangeValues[0]
742: .length());
743: criteria.addOrCriteria(orCriteria);
744: criteria.addLessOrEqualThan(propertyName, rangeValues[1]
745: .length());
746:
747: } else if (propertyValue.startsWith(">")) {
748: criteria.addGreaterThan(propertyName, ObjectUtils
749: .clean(propertyValue));
750:
751: //To fix a bug related on number of digits issues for searching String field with range operator
752: Criteria orCriteria = new Criteria();
753: orCriteria.addGreaterThan(propertyName, ObjectUtils.clean(
754: propertyValue).length());
755: criteria.addOrCriteria(orCriteria);
756:
757: } else if (propertyValue.startsWith("<")) {
758: criteria.addLessThan(propertyName, ObjectUtils
759: .clean(propertyValue));
760:
761: //To fix a bug related on number of digits issues for searching String field with range operator
762: criteria.addLessOrEqualThan(propertyName, ObjectUtils
763: .clean(propertyValue).length());
764: } else if (propertyValue.startsWith(">=")) {
765: criteria.addGreaterOrEqualThan(propertyName, ObjectUtils
766: .clean(propertyValue));
767:
768: //To fix a bug related on number of digits issues for searching String field with range operator
769: criteria.addGreaterOrEqualThan(propertyName, ObjectUtils
770: .clean(propertyValue).length());
771: } else if (propertyValue.startsWith("<=")) {
772: criteria.addLessOrEqualThan(propertyName, ObjectUtils
773: .clean(propertyValue));
774:
775: //To fix a bug related on number of digits issues for searching String field with range operator
776: criteria.addLessOrEqualThan(propertyName, ObjectUtils
777: .clean(propertyValue).length());
778: }
779: }
780:
781: /**
782: * @param dateTimeService the dateTimeService to set
783: */
784: public void setDateTimeService(DateTimeService dateTimeService) {
785: this.dateTimeService = dateTimeService;
786: }
787: }
|