001: /*
002: * $Id: FindServices.java,v 1.6 2004/02/17 17:51:39 jonesde Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.common;
026:
027: import java.sql.Timestamp;
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033:
034: import org.ofbiz.base.util.UtilDateTime;
035: import org.ofbiz.entity.GenericDelegator;
036: import org.ofbiz.entity.GenericEntityException;
037: import org.ofbiz.entity.GenericValue;
038: import org.ofbiz.entity.condition.EntityComparisonOperator;
039: import org.ofbiz.entity.condition.EntityConditionList;
040: import org.ofbiz.entity.condition.EntityExpr;
041: import org.ofbiz.entity.condition.EntityJoinOperator;
042: import org.ofbiz.entity.condition.EntityOperator;
043: import org.ofbiz.entity.model.ModelEntity;
044: import org.ofbiz.entity.util.EntityFindOptions;
045: import org.ofbiz.entity.util.EntityListIterator;
046: import org.ofbiz.service.DispatchContext;
047: import org.ofbiz.service.ServiceUtil;
048:
049: /**
050: * FindServices Class
051: *
052: * @author <a href="mailto:byersa@automationgroups.com">Al Byers</a>
053: * @version $Revision: 1.6 $
054: * @since 2.2
055: */
056: public class FindServices {
057:
058: public static final String module = FindServices.class.getName();
059:
060: public static HashMap entityOperators;
061:
062: static {
063: entityOperators = new HashMap();
064: entityOperators.put("and", EntityOperator.AND);
065: entityOperators.put("between", EntityOperator.BETWEEN);
066: entityOperators.put("equals", EntityOperator.EQUALS);
067: entityOperators.put("greaterThan", EntityOperator.GREATER_THAN);
068: entityOperators.put("greaterThanEqualTo",
069: EntityOperator.GREATER_THAN_EQUAL_TO);
070: entityOperators.put("in", EntityOperator.IN);
071: entityOperators.put("lessThan", EntityOperator.LESS_THAN);
072: entityOperators.put("lessThanEqualTo",
073: EntityOperator.LESS_THAN_EQUAL_TO);
074: entityOperators.put("like", EntityOperator.LIKE);
075: entityOperators.put("not", EntityOperator.NOT);
076: entityOperators.put("notEqual", EntityOperator.NOT_EQUAL);
077: entityOperators.put("or", EntityOperator.OR);
078: }
079:
080: public FindServices() {
081: }
082:
083: /**
084: * performFind
085: *
086: * This is a generic method that expects entity data affixed with special suffixes
087: * to indicate their purpose in formulating an SQL query statement.
088: */
089: public static Map performFind(DispatchContext dctx, Map context) {
090:
091: String entityName = (String) context.get("entityName");
092:
093: Map inputFields = (Map) context.get("inputFields"); // Input
094: // parameters run thru UtilHttp.getParameterMap
095:
096: String fieldName = null;
097: String fieldNameRaw = null; // The name as it appeas in the HTML form
098: String fieldNameRoot = null; // The entity field name.
099: // Everything to the left of the first "_" if
100: // it exists, or the whole word, if not.
101: String fieldPair = null; // "fld0" or "fld1" - begin/end of range
102: // or just fld0 if no range.
103: String fieldValue = null; // If it is a "value" field, it will be the value
104: // to be used in the query.
105: // If it is an "op" field, it will be
106: // "equals", "greaterThan", etc.
107: int iPos = -1;
108: int iPos2 = -1;
109: HashMap subMap = null;
110: HashMap subMap2 = null;
111: String fieldMode = null;
112: EntityOperator fieldOp = null;
113:
114: // Strip the "_suffix" off of the parameter name and
115: // build a three-level map of values keyed by fieldRoot name,
116: // fld0 or fld1, and, then, "op" or "value"
117: // ie. id
118: // - fld0
119: // - op:like
120: // - value:abc
121: // - fld1 (if there is a range)
122: // - op:lessThan
123: // - value:55 (note: these two "flds" wouldn't really go together)
124: // Also note that op/fld can be in any order. (eg. id_fld1_equals or id_equals_fld1)
125: // Note that "normalizedFields" will contain values other than those
126: // Contained in the associated entity.
127: // Those extra fields will be ignored in the second half of this method.
128: HashMap normalizedFields = new HashMap();
129: Iterator ifIter = inputFields.keySet().iterator();
130: while (ifIter.hasNext()) {
131: fieldNameRaw = (String) ifIter.next();
132: fieldValue = (String) inputFields.get(fieldNameRaw);
133: if (fieldValue == null || fieldValue.length() == 0)
134: continue;
135:
136: iPos = fieldNameRaw.indexOf("_"); // Look for suffix
137:
138: // If no suffix, assume no range (default to fld0) and operations of equals
139: // If no field op is present, it will assume "equals".
140: if (iPos < 0) {
141: fieldNameRoot = fieldNameRaw;
142: fieldPair = "fld0";
143: fieldMode = "value";
144: } else { // Must have at least "fld0/1" or "equals, greaterThan, etc."
145: // Some bogus fields will slip in, like "ENTITY_NAME", but they will be ignored
146:
147: fieldNameRoot = fieldNameRaw.substring(0, iPos);
148: String suffix = fieldNameRaw.substring(iPos + 1);
149: iPos2 = suffix.indexOf("_");
150: if (iPos2 < 0) {
151: if (suffix.startsWith("fld")) {
152: // If only one token and it starts with "fld"
153: // assume it is a value field, not an op
154: fieldPair = suffix;
155: fieldMode = "value";
156: } else {
157: // if it does not start with fld, assume it is an op
158: fieldPair = "fld0";
159: fieldMode = suffix;
160: }
161: } else {
162: String tkn0 = suffix.substring(0, iPos2);
163: String tkn1 = suffix.substring(iPos2 + 1);
164: // If suffix has two parts, let them be in any order
165: // One will be "fld0/1" and the other will be the op (eg. equals, greaterThan_
166: if (tkn0.startsWith("fld")) {
167: fieldPair = tkn0;
168: fieldMode = tkn1;
169: } else {
170: fieldPair = tkn1;
171: fieldMode = tkn0;
172: }
173: }
174: }
175: subMap = (HashMap) normalizedFields.get(fieldNameRoot);
176: if (subMap == null) {
177: subMap = new HashMap();
178: normalizedFields.put(fieldNameRoot, subMap);
179: }
180: subMap2 = (HashMap) subMap.get(fieldPair);
181: if (subMap2 == null) {
182: subMap2 = new HashMap();
183: subMap.put(fieldPair, subMap2);
184: }
185: subMap2.put(fieldMode, fieldValue);
186: }
187:
188: // Now use only the values that correspond to entity fields to build
189: // an EntityConditionList
190: GenericDelegator delegator = dctx.getDelegator();
191:
192: GenericValue entityValue = delegator.makeValue(entityName,
193: new HashMap());
194:
195: ModelEntity modelEntity = entityValue.getModelEntity();
196: List keys = modelEntity.getAllFieldNames();
197: Iterator iter = keys.iterator();
198: EntityOperator entOp = EntityOperator.AND;
199: EntityExpr cond = null;
200: ArrayList tmpList = new ArrayList();
201: String opString = null;
202: int count = 0;
203: while (iter.hasNext()) {
204: fieldName = (String) iter.next();
205: subMap = (HashMap) normalizedFields.get(fieldName);
206: if (subMap == null) {
207: continue;
208: }
209:
210: subMap2 = (HashMap) subMap.get("fld0");
211: opString = (String) subMap2.get("op");
212:
213: if (opString != null) {
214: if (opString.equals("contains")) {
215: fieldOp = (EntityOperator) entityOperators
216: .get("like");
217:
218: } else if (opString.equals("empty")) {
219: fieldOp = (EntityOperator) entityOperators
220: .get("equals");
221: } else {
222: fieldOp = (EntityOperator) entityOperators
223: .get(opString);
224: }
225: } else {
226: fieldOp = (EntityOperator) entityOperators
227: .get("equals");
228: }
229:
230: fieldValue = (String) subMap2.get("value");
231: if (fieldValue == null) {
232: continue;
233: }
234:
235: if (opString != null) {
236: if (opString.equals("contains")) {
237: fieldOp = (EntityOperator) entityOperators
238: .get("like");
239: fieldValue = "%" + fieldValue + "%";
240: } else if (opString.equals("empty")) {
241: fieldOp = (EntityOperator) entityOperators
242: .get("equals");
243: fieldValue = null;
244: } else if (opString.equals("like")) {
245: fieldOp = (EntityOperator) entityOperators
246: .get("like");
247: fieldValue += "%";
248: } else if (opString.equals("greaterThanFromDayStart")) {
249: fieldValue = dayStart(fieldValue, 0);
250: fieldOp = (EntityOperator) entityOperators
251: .get("greaterThan");
252: } else if (opString.equals("sameDay")) {
253: String timeStampString = fieldValue;
254: fieldValue = dayStart(timeStampString, 0);
255: fieldOp = (EntityOperator) entityOperators
256: .get("greaterThan");
257:
258: // Set up so next part finds ending conditions for same day
259: subMap2 = (HashMap) subMap.get("fld1");
260: if (subMap2 == null) {
261: subMap2 = new HashMap();
262: subMap.put("fld1", subMap2);
263: }
264: String endOfDay = dayStart(timeStampString, 1);
265: subMap2.put("value", endOfDay);
266: subMap2.put("op", "lessThan");
267: } else {
268: fieldOp = (EntityOperator) entityOperators
269: .get(opString);
270: }
271: } else {
272: fieldOp = (EntityOperator) entityOperators
273: .get("equals");
274: }
275:
276: cond = new EntityExpr(fieldName,
277: (EntityComparisonOperator) fieldOp, fieldValue);
278: tmpList.add(cond);
279: count++;
280:
281: // Repeat above operations if there is a "range" - second value
282: subMap2 = (HashMap) subMap.get("fld1");
283: if (subMap2 == null) {
284: continue;
285: }
286: opString = (String) subMap2.get("op");
287:
288: if (opString != null) {
289: if (opString.equals("contains")) {
290: fieldOp = (EntityOperator) entityOperators
291: .get("like");
292: } else if (opString.equals("empty")) {
293: fieldOp = (EntityOperator) entityOperators
294: .get("equals");
295: } else {
296: fieldOp = (EntityOperator) entityOperators
297: .get(opString);
298: }
299: } else {
300: fieldOp = (EntityOperator) entityOperators
301: .get("equals");
302: }
303:
304: fieldValue = (String) subMap2.get("value");
305: if (fieldValue == null) {
306: continue;
307: }
308: if (opString.equals("like")) {
309: fieldValue += "%";
310: } else if (opString.equals("contains")) {
311: fieldValue += "%" + fieldValue + "%";
312: } else if (opString.equals("empty")) {
313: fieldOp = (EntityOperator) entityOperators
314: .get("equals");
315: fieldValue = null;
316: } else if (opString.equals("upToDay")) {
317: fieldValue = dayStart(fieldValue, 0);
318: fieldOp = (EntityOperator) entityOperators
319: .get("lessThan");
320: } else if (opString.equals("upThruDay")) {
321: fieldValue = dayStart(fieldValue, 1);
322: fieldOp = (EntityOperator) entityOperators
323: .get("lessThan");
324: }
325: // String rhs = fieldValue.toString();
326: cond = new EntityExpr(fieldName,
327: (EntityComparisonOperator) fieldOp, fieldValue);
328: tmpList.add(cond);
329: }
330: EntityConditionList exprList = new EntityConditionList(tmpList,
331: (EntityJoinOperator) entOp);
332: EntityListIterator listIt = null;
333:
334: if (count > 0) {
335: /* Retrieve entities - an iterator over all the values*/
336: try {
337: listIt = delegator
338: .findListIteratorByCondition(
339: entityName,
340: exprList,
341: null,
342: null,
343: null,
344: new EntityFindOptions(
345: true,
346: EntityFindOptions.TYPE_SCROLL_INSENSITIVE,
347: EntityFindOptions.CONCUR_READ_ONLY,
348: false));
349: } catch (GenericEntityException e) {
350: return ServiceUtil
351: .returnError("Error finding iterator: "
352: + e.getMessage());
353: }
354: } else {
355: try {
356: /*
357: List pkList = delegator.getModelEntity(entityName).getPkFieldNames();
358: String pkName = (String)pkList.get(0);
359: EntityExpr pkExpr = new EntityExpr(pkName, EntityOperator.LIKE, "%");
360: */
361: listIt = delegator
362: .findListIteratorByCondition(
363: entityName,
364: null,
365: null,
366: null,
367: null,
368: new EntityFindOptions(
369: true,
370: EntityFindOptions.TYPE_SCROLL_INSENSITIVE,
371: EntityFindOptions.CONCUR_READ_ONLY,
372: false));
373: } catch (GenericEntityException e) {
374: return ServiceUtil.returnError("Error finding all: "
375: + e.getMessage());
376: }
377: }
378:
379: Map results = ServiceUtil.returnSuccess();
380: results.put("listIt", listIt);
381: return results;
382: }
383:
384: private static String dayStart(String timeStampString, int daysLater) {
385: String retValue = null;
386: Timestamp ts = null;
387: Timestamp startTs = null;
388: try {
389: ts = Timestamp.valueOf(timeStampString);
390: } catch (IllegalArgumentException e) {
391: timeStampString += " 00:00:00.000";
392: try {
393: ts = Timestamp.valueOf(timeStampString);
394: } catch (IllegalArgumentException e2) {
395: return retValue;
396: }
397: }
398: startTs = UtilDateTime.getDayStart(ts, daysLater);
399: retValue = startTs.toString();
400: return retValue;
401: }
402: }
|