001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.common;
019:
020: import java.sql.Timestamp;
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.ofbiz.base.util.Debug;
028: import org.ofbiz.base.util.ObjectType;
029: import org.ofbiz.base.util.StringUtil;
030: import org.ofbiz.base.util.UtilDateTime;
031: import org.ofbiz.base.util.UtilHttp;
032: import org.ofbiz.base.util.UtilValidate;
033: import org.ofbiz.base.util.UtilMisc;
034: import org.ofbiz.entity.GenericDelegator;
035: import org.ofbiz.entity.GenericEntityException;
036: import org.ofbiz.entity.GenericValue;
037: import org.ofbiz.entity.condition.EntityComparisonOperator;
038: import org.ofbiz.entity.condition.EntityConditionList;
039: import org.ofbiz.entity.condition.EntityCondition;
040: import org.ofbiz.entity.condition.EntityExpr;
041: import org.ofbiz.entity.condition.EntityOperator;
042: import org.ofbiz.entity.condition.EntityFunction;
043: import org.ofbiz.entity.condition.EntityFieldValue;
044: import org.ofbiz.entity.model.ModelEntity;
045: import org.ofbiz.entity.util.EntityFindOptions;
046: import org.ofbiz.entity.util.EntityListIterator;
047: import org.ofbiz.entity.util.EntityUtil;
048: import org.ofbiz.service.DispatchContext;
049: import org.ofbiz.service.ServiceUtil;
050: import org.ofbiz.service.GenericServiceException;
051: import org.ofbiz.service.LocalDispatcher;
052:
053: /**
054: * FindServices Class
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: * prepareField, analyse inputFields to created normalizedFields a map with field name and operator.
085: *
086: * This is use to the generic method that expects entity data affixed with special suffixes
087: * to indicate their purpose in formulating an SQL query statement.
088: * @param inputFields Input parameters run thru UtilHttp.getParameterMap
089: * @return a map with field name and operator
090: */
091: public static HashMap prepareField(Map inputFields,
092: Map queryStringMap, Map origValueMap) {
093: // Strip the "_suffix" off of the parameter name and
094: // build a three-level map of values keyed by fieldRoot name,
095: // fld0 or fld1, and, then, "op" or "value"
096: // ie. id
097: // - fld0
098: // - op:like
099: // - value:abc
100: // - fld1 (if there is a range)
101: // - op:lessThan
102: // - value:55 (note: these two "flds" wouldn't really go together)
103: // Also note that op/fld can be in any order. (eg. id_fld1_equals or id_equals_fld1)
104: // Note that "normalizedFields" will contain values other than those
105: // Contained in the associated entity.
106: // Those extra fields will be ignored in the second half of this method.
107: HashMap normalizedFields = new HashMap();
108: Iterator ifIter = inputFields.keySet().iterator();
109: //StringBuffer queryStringBuf = new StringBuffer();
110: while (ifIter.hasNext()) {
111: String fieldNameRaw = null; // The name as it appeas in the HTML form
112: String fieldNameRoot = null; // The entity field name. Everything to the left of the first "_" if
113: // it exists, or the whole word, if not.
114: String fieldPair = null; // "fld0" or "fld1" - begin/end of range or just fld0 if no range.
115: Object fieldValue = null; // If it is a "value" field, it will be the value to be used in the query.
116: // If it is an "op" field, it will be "equals", "greaterThan", etc.
117: int iPos = -1;
118: int iPos2 = -1;
119: HashMap subMap = null;
120: HashMap subMap2 = null;
121: String fieldMode = null;
122:
123: fieldNameRaw = (String) ifIter.next();
124: fieldValue = inputFields.get(fieldNameRaw);
125: if (ObjectType.isEmpty(fieldValue)) {
126: continue;
127: }
128:
129: //queryStringBuffer.append(fieldNameRaw + "=" + fieldValue);
130: queryStringMap.put(fieldNameRaw, fieldValue);
131: iPos = fieldNameRaw.indexOf("_"); // Look for suffix
132:
133: // This is a hack to skip fields from "multi" forms
134: // These would have the form "fieldName_o_1"
135: if (iPos >= 0) {
136: String suffix = fieldNameRaw.substring(iPos + 1);
137: iPos2 = suffix.indexOf("_");
138: if (iPos2 == 1) {
139: continue;
140: }
141: }
142:
143: // If no suffix, assume no range (default to fld0) and operations of equals
144: // If no field op is present, it will assume "equals".
145: if (iPos < 0) {
146: fieldNameRoot = fieldNameRaw;
147: fieldPair = "fld0";
148: fieldMode = "value";
149: } else { // Must have at least "fld0/1" or "equals, greaterThan, etc."
150: // Some bogus fields will slip in, like "ENTITY_NAME", but they will be ignored
151:
152: fieldNameRoot = fieldNameRaw.substring(0, iPos);
153: String suffix = fieldNameRaw.substring(iPos + 1);
154: iPos2 = suffix.indexOf("_");
155: if (iPos2 < 0) {
156: if (suffix.startsWith("fld")) {
157: // If only one token and it starts with "fld"
158: // assume it is a value field, not an op
159: fieldPair = suffix;
160: fieldMode = "value";
161: } else {
162: // if it does not start with fld, assume it is an op or the 'ignore case' (ic) field
163: fieldPair = "fld0";
164: fieldMode = suffix;
165: }
166: } else {
167: String tkn0 = suffix.substring(0, iPos2);
168: String tkn1 = suffix.substring(iPos2 + 1);
169: // If suffix has two parts, let them be in any order
170: // One will be "fld0/1" and the other will be the op (eg. equals, greaterThan_
171: if (tkn0.startsWith("fld")) {
172: fieldPair = tkn0;
173: fieldMode = tkn1;
174: } else {
175: fieldPair = tkn1;
176: fieldMode = tkn0;
177: }
178: }
179: }
180: subMap = (HashMap) normalizedFields.get(fieldNameRoot);
181: if (subMap == null) {
182: subMap = new HashMap();
183: normalizedFields.put(fieldNameRoot, subMap);
184: }
185: subMap2 = (HashMap) subMap.get(fieldPair);
186: if (subMap2 == null) {
187: subMap2 = new HashMap();
188: subMap.put(fieldPair, subMap2);
189: }
190: subMap2.put(fieldMode, fieldValue);
191:
192: List origList = (List) origValueMap.get(fieldNameRoot);
193: if (origList == null) {
194: origList = new ArrayList();
195: origValueMap.put(fieldNameRoot, origList);
196: }
197: Object[] origValues = { fieldNameRaw, fieldValue };
198: origList.add(origValues);
199: }
200: return normalizedFields;
201: }
202:
203: /**
204: * createCondition, comparing the normalizedFields with the list of keys, .
205: *
206: * This is use to the generic method that expects entity data affixed with special suffixes
207: * to indicate their purpose in formulating an SQL query statement.
208: * @param keys list of field for which it's possible to make the query
209: * @param normalizedFields list of field the user have populated
210: * @return a arrayList usable to create an entityCondition
211: */
212: public static ArrayList createCondition(List keys,
213: HashMap normalizedFields, Map queryStringMap,
214: Map origValueMap) {
215: String fieldName = null;
216: HashMap subMap = null;
217: HashMap subMap2 = null;
218: EntityOperator fieldOp = null;
219: String fieldValue = null; // If it is a "value" field, it will be the value to be used in the query.
220: // If it is an "op" field, it will be "equals", "greaterThan", etc.
221: Iterator iter = keys.iterator();
222: EntityExpr cond = null;
223: ArrayList tmpList = new ArrayList();
224: String opString = null;
225: String ignoreCase = null;
226: int count = 0;
227: while (iter.hasNext()) {
228: fieldName = (String) iter.next();
229: subMap = (HashMap) normalizedFields.get(fieldName);
230: if (subMap == null) {
231: continue;
232: }
233:
234: subMap2 = (HashMap) subMap.get("fld0");
235: opString = (String) subMap2.get("op");
236: ignoreCase = (String) subMap2.get("ic");
237:
238: if (opString != null) {
239: if (opString.equals("contains")) {
240: fieldOp = EntityOperator.LIKE;
241: } else if (opString.equals("empty")) {
242: fieldOp = EntityOperator.EQUALS;
243: } else {
244: fieldOp = (EntityOperator) entityOperators
245: .get(opString);
246: }
247: } else {
248: fieldOp = EntityOperator.EQUALS;
249: }
250:
251: fieldValue = (String) subMap2.get("value");
252: if (fieldValue == null) {
253: continue;
254: }
255:
256: if (opString != null) {
257: if (opString.equals("contains")) {
258: fieldOp = EntityOperator.LIKE;
259: fieldValue = "%" + fieldValue + "%";
260: } else if (opString.equals("empty")) {
261: fieldOp = EntityOperator.EQUALS;
262: fieldValue = null;
263: ignoreCase = null;
264: } else if (opString.equals("like")) {
265: fieldOp = EntityOperator.LIKE;
266: fieldValue += "%";
267: } else if (opString.equals("greaterThanFromDayStart")) {
268: fieldValue = dayStart(fieldValue, 0);
269: fieldOp = EntityOperator.GREATER_THAN;
270: ignoreCase = null;
271: } else if (opString.equals("sameDay")) {
272: String timeStampString = fieldValue;
273: fieldValue = dayStart(timeStampString, 0);
274: fieldOp = EntityOperator.GREATER_THAN_EQUAL_TO;
275: ignoreCase = null;
276: // Set up so next part finds ending conditions for same day
277: subMap2 = (HashMap) subMap.get("fld1");
278: if (subMap2 == null) {
279: subMap2 = new HashMap();
280: subMap.put("fld1", subMap2);
281: }
282: String endOfDay = dayStart(timeStampString, 1);
283: subMap2.put("value", endOfDay);
284: subMap2.put("op", "lessThan");
285: } else {
286: fieldOp = (EntityOperator) entityOperators
287: .get(opString);
288: }
289: } else {
290: fieldOp = EntityOperator.EQUALS;
291: }
292:
293: if (ignoreCase != null && ignoreCase.equals("Y")) {
294: cond = new EntityExpr(new EntityFunction.UPPER(
295: new EntityFieldValue(fieldName)),
296: (EntityComparisonOperator) fieldOp,
297: new EntityFunction.UPPER(fieldValue
298: .toUpperCase()));
299: } else {
300: cond = new EntityExpr(fieldName,
301: (EntityComparisonOperator) fieldOp, fieldValue);
302: }
303: tmpList.add(cond);
304: count++;
305:
306: // Repeat above operations if there is a "range" - second value
307: subMap2 = (HashMap) subMap.get("fld1");
308: if (subMap2 == null) {
309: continue;
310: }
311: opString = (String) subMap2.get("op");
312:
313: if (opString != null) {
314: if (opString.equals("contains")) {
315: fieldOp = EntityOperator.LIKE;
316: } else if (opString.equals("empty")) {
317: fieldOp = EntityOperator.EQUALS;
318: } else {
319: fieldOp = (EntityOperator) entityOperators
320: .get(opString);
321: }
322: } else {
323: fieldOp = EntityOperator.EQUALS;
324: }
325:
326: fieldValue = (String) subMap2.get("value");
327: if (fieldValue == null) {
328: continue;
329: }
330: if (opString.equals("like")) {
331: fieldValue += "%";
332: } else if (opString.equals("contains")) {
333: fieldValue += "%" + fieldValue + "%";
334: } else if (opString.equals("empty")) {
335: fieldOp = EntityOperator.EQUALS;
336: fieldValue = null;
337: } else if (opString.equals("upToDay")) {
338: fieldValue = dayStart(fieldValue, 0);
339: fieldOp = EntityOperator.LESS_THAN;
340: } else if (opString.equals("upThruDay")) {
341: fieldValue = dayStart(fieldValue, 1);
342: fieldOp = EntityOperator.LESS_THAN;
343: }
344: // String rhs = fieldValue.toString();
345: cond = new EntityExpr(fieldName,
346: (EntityComparisonOperator) fieldOp, fieldValue);
347: tmpList.add(cond);
348:
349: // add to queryStringMap
350: List origList = (List) origValueMap.get(fieldName);
351: if (origList != null && origList.size() > 0) {
352: Iterator origIter = origList.iterator();
353: while (origIter.hasNext()) {
354: Object[] arr = (Object[]) origIter.next();
355: queryStringMap.put(arr[0], arr[1]);
356: }
357: }
358: }
359: return tmpList;
360: }
361:
362: /**
363: *
364: * same as performFind but now returning a list instead of an iterator
365: * Extra parameters viewIndex: startPage of the partial list (0 = first page)
366: * viewSize: the length of the page (number of records)
367: * Extra output parameter: listSize: size of the totallist
368: * list : the list itself.
369: *
370: * @param dctx
371: * @param context
372: * @return Map
373: */
374: public static Map performFindList(DispatchContext dctx, Map context) {
375: Map result = performFind(dctx, context);
376:
377: Integer viewSize = (Integer) context.get("viewSize");
378: if (viewSize == null)
379: viewSize = new Integer(20); // default
380: Integer viewIndex = (Integer) context.get("viewIndex");
381: if (viewIndex == null)
382: viewIndex = new Integer(0); // default
383:
384: int start = viewIndex.intValue() * viewSize.intValue();
385: List list = null;
386: Integer listSize = null;
387: try {
388: EntityListIterator it = (EntityListIterator) result
389: .get("listIt");
390: list = it.getPartialList(start + 1, viewSize.intValue()); // list starts at '1'
391: it.last();
392: listSize = new Integer(it.currentIndex());
393: it.close();
394: } catch (Exception e) {
395: Debug.logInfo("Problem getting partial list" + e, module);
396: }
397:
398: result.put("listSize", listSize);
399: result.put("list", list);
400: result.remove("listIt");
401: return result;
402: }
403:
404: /**
405: * performFind
406: *
407: * This is a generic method that expects entity data affixed with special suffixes
408: * to indicate their purpose in formulating an SQL query statement.
409: */
410: public static Map performFind(DispatchContext dctx, Map context) {
411: String entityName = (String) context.get("entityName");
412: String orderBy = (String) context.get("orderBy");
413: Map inputFields = (Map) context.get("inputFields"); // Input
414: String noConditionFind = (String) context
415: .get("noConditionFind");
416: GenericValue userLogin = (GenericValue) context
417: .get("userLogin");
418: if (UtilValidate.isEmpty(noConditionFind)) {
419: // try finding in inputFields Map
420: noConditionFind = (String) inputFields
421: .get("noConditionFind");
422: }
423: String filterByDate = (String) context.get("filterByDate");
424: if (UtilValidate.isEmpty(filterByDate)) {
425: // try finding in inputFields Map
426: filterByDate = (String) inputFields.get("filterByDate");
427: }
428: Timestamp filterByDateValue = (Timestamp) context
429: .get("filterByDateValue");
430:
431: LocalDispatcher dispatcher = dctx.getDispatcher();
432:
433: Map prepareResult = null;
434: try {
435: prepareResult = dispatcher.runSync("prepareFind", UtilMisc
436: .toMap("entityName", entityName, "orderBy",
437: orderBy, "inputFields", inputFields,
438: "filterByDate", filterByDate,
439: "filterByDateValue", filterByDateValue,
440: "userLogin", userLogin));
441: } catch (GenericServiceException gse) {
442: return ServiceUtil
443: .returnError("Error preparing conditions: "
444: + gse.getMessage());
445: }
446: EntityConditionList exprList = (EntityConditionList) prepareResult
447: .get("entityConditionList");
448: List orderByList = (List) prepareResult.get("orderByList");
449:
450: Map executeResult = null;
451: try {
452: executeResult = dispatcher.runSync("executeFind", UtilMisc
453: .toMap("entityName", entityName, "orderByList",
454: orderByList, "entityConditionList",
455: exprList, "noConditionFind",
456: noConditionFind));
457: } catch (GenericServiceException gse) {
458: return ServiceUtil.returnError("Error finding iterator: "
459: + gse.getMessage());
460: }
461:
462: if (executeResult.get("listIt") == null) {
463: Debug.logInfo("No list iterator found for query string + ["
464: + prepareResult.get("queryString") + "]", module);
465: }
466:
467: Map results = ServiceUtil.returnSuccess();
468: results.put("listIt", executeResult.get("listIt"));
469: results.put("queryString", prepareResult.get("queryString"));
470: results.put("queryStringMap", prepareResult
471: .get("queryStringMap"));
472: return results;
473: }
474:
475: /**
476: * prepareFind
477: *
478: * This is a generic method that expects entity data affixed with special suffixes
479: * to indicate their purpose in formulating an SQL query statement.
480: */
481: public static Map prepareFind(DispatchContext dctx, Map context) {
482: String entityName = (String) context.get("entityName");
483: String orderBy = (String) context.get("orderBy");
484: Map inputFields = (Map) context.get("inputFields"); // Input
485: String noConditionFind = (String) context
486: .get("noConditionFind");
487: if (UtilValidate.isEmpty(noConditionFind)) {
488: // try finding in inputFields Map
489: noConditionFind = (String) inputFields
490: .get("noConditionFind");
491: }
492: String filterByDate = (String) context.get("filterByDate");
493: if (UtilValidate.isEmpty(filterByDate)) {
494: // try finding in inputFields Map
495: filterByDate = (String) inputFields.get("filterByDate");
496: }
497: Timestamp filterByDateValue = (Timestamp) context
498: .get("filterByDateValue");
499:
500: // parameters run thru UtilHttp.getParameterMap
501: Map queryStringMap = new HashMap();
502: Map origValueMap = new HashMap();
503: HashMap normalizedFields = prepareField(inputFields,
504: queryStringMap, origValueMap);
505:
506: // Now use only the values that correspond to entity fields to build
507: // an EntityConditionList
508: GenericDelegator delegator = dctx.getDelegator();
509:
510: GenericValue entityValue = delegator.makeValue(entityName,
511: new HashMap());
512:
513: ModelEntity modelEntity = entityValue.getModelEntity();
514: List keys = modelEntity.getAllFieldNames();
515: ArrayList tmpList = createCondition(keys, normalizedFields,
516: queryStringMap, origValueMap);
517:
518: /* the filter by date condition should only be added when there are other conditions or when
519: * the user has specified a noConditionFind. Otherwise, specifying filterByDate will become
520: * its own condition.
521: */
522: if ((tmpList.size() > 0)
523: || ((noConditionFind != null) && (noConditionFind
524: .equals("Y")))) {
525: if (!UtilValidate.isEmpty(filterByDate)
526: && "Y".equals(filterByDate)) {
527: if (UtilValidate.isEmpty(filterByDateValue)) {
528: EntityCondition filterByDateCondition = EntityUtil
529: .getFilterByDateExpr();
530: tmpList.add(filterByDateCondition);
531: } else {
532: EntityCondition filterByDateCondition = EntityUtil
533: .getFilterByDateExpr(filterByDateValue);
534: tmpList.add(filterByDateCondition);
535: }
536: }
537: }
538:
539: EntityConditionList exprList = null;
540: if (tmpList.size() > 0) {
541: exprList = new EntityConditionList(tmpList,
542: EntityOperator.AND);
543: }
544:
545: List orderByList = null;
546: if (UtilValidate.isNotEmpty(orderBy)) {
547: orderByList = StringUtil.split(orderBy, "|");
548: }
549:
550: Map results = ServiceUtil.returnSuccess();
551: Map reducedQueryStringMap = buildReducedQueryString(
552: inputFields, entityName, delegator);
553: reducedQueryStringMap.put("noConditionFind", noConditionFind);
554: reducedQueryStringMap.put("filterByDate", filterByDate);
555: reducedQueryStringMap.put("filterByDateValue",
556: filterByDateValue);
557: String queryString = UtilHttp
558: .urlEncodeArgs(reducedQueryStringMap);
559: results.put("queryString", queryString);
560: results.put("queryStringMap", reducedQueryStringMap);
561:
562: results.put("orderByList", orderByList);
563: results.put("entityConditionList", exprList);
564: return results;
565: }
566:
567: /**
568: * executeFind
569: *
570: * This is a generic method that returns an EntityListIterator.
571: */
572: public static Map executeFind(DispatchContext dctx, Map context) {
573: String entityName = (String) context.get("entityName");
574: EntityConditionList entityConditionList = (EntityConditionList) context
575: .get("entityConditionList");
576: List orderByList = (List) context.get("orderByList");
577: boolean noConditionFind = "Y".equals((String) context
578: .get("noConditionFind"));
579:
580: GenericDelegator delegator = dctx.getDelegator();
581:
582: // Retrieve entities - an iterator over all the values
583: EntityListIterator listIt = null;
584: try {
585: if (noConditionFind
586: || (entityConditionList != null && entityConditionList
587: .getConditionListSize() > 0)) {
588: listIt = delegator
589: .findListIteratorByCondition(
590: entityName,
591: entityConditionList,
592: null,
593: null,
594: orderByList,
595: new EntityFindOptions(
596: true,
597: EntityFindOptions.TYPE_SCROLL_INSENSITIVE,
598: EntityFindOptions.CONCUR_READ_ONLY,
599: false));
600: }
601: } catch (GenericEntityException e) {
602: return ServiceUtil
603: .returnError("Error running Find on the ["
604: + entityName + "] entity: "
605: + e.getMessage());
606: }
607:
608: Map results = ServiceUtil.returnSuccess();
609: results.put("listIt", listIt);
610: return results;
611: }
612:
613: private static String dayStart(String timeStampString, int daysLater) {
614: String retValue = null;
615: Timestamp ts = null;
616: Timestamp startTs = null;
617: try {
618: ts = Timestamp.valueOf(timeStampString);
619: } catch (IllegalArgumentException e) {
620: timeStampString += " 00:00:00.000";
621: try {
622: ts = Timestamp.valueOf(timeStampString);
623: } catch (IllegalArgumentException e2) {
624: return retValue;
625: }
626: }
627: startTs = UtilDateTime.getDayStart(ts, daysLater);
628: retValue = startTs.toString();
629: return retValue;
630: }
631:
632: public static HashMap buildReducedQueryString(Map inputFields,
633: String entityName, GenericDelegator delegator) {
634: // Strip the "_suffix" off of the parameter name and
635: // build a three-level map of values keyed by fieldRoot name,
636: // fld0 or fld1, and, then, "op" or "value"
637: // ie. id
638: // - fld0
639: // - op:like
640: // - value:abc
641: // - fld1 (if there is a range)
642: // - op:lessThan
643: // - value:55 (note: these two "flds" wouldn't really go together)
644: // Also note that op/fld can be in any order. (eg. id_fld1_equals or id_equals_fld1)
645: // Note that "normalizedFields" will contain values other than those
646: // Contained in the associated entity.
647: // Those extra fields will be ignored in the second half of this method.
648: ModelEntity modelEntity = delegator.getModelEntity(entityName);
649: HashMap normalizedFields = new HashMap();
650: Iterator ifIter = inputFields.keySet().iterator();
651: //StringBuffer queryStringBuf = new StringBuffer();
652: while (ifIter.hasNext()) {
653: String fieldNameRaw = null; // The name as it appeas in the HTML form
654: String fieldNameRoot = null; // The entity field name. Everything to the left of the first "_" if
655: // it exists, or the whole word, if not.
656: String fieldPair = null; // "fld0" or "fld1" - begin/end of range or just fld0 if no range.
657: Object fieldValue = null; // If it is a "value" field, it will be the value to be used in the query.
658: // If it is an "op" field, it will be "equals", "greaterThan", etc.
659: int iPos = -1;
660: int iPos2 = -1;
661: String fieldMode = null;
662:
663: fieldNameRaw = (String) ifIter.next();
664: fieldValue = inputFields.get(fieldNameRaw);
665: if (ObjectType.isEmpty(fieldValue)) {
666: continue;
667: }
668:
669: //queryStringBuffer.append(fieldNameRaw + "=" + fieldValue);
670: iPos = fieldNameRaw.indexOf("_"); // Look for suffix
671:
672: // This is a hack to skip fields from "multi" forms
673: // These would have the form "fieldName_o_1"
674: if (iPos >= 0) {
675: String suffix = fieldNameRaw.substring(iPos + 1);
676: iPos2 = suffix.indexOf("_");
677: if (iPos2 == 1) {
678: continue;
679: }
680: }
681:
682: // If no suffix, assume no range (default to fld0) and operations of equals
683: // If no field op is present, it will assume "equals".
684: if (iPos < 0) {
685: fieldNameRoot = fieldNameRaw;
686: fieldPair = "fld0";
687: fieldMode = "value";
688: } else { // Must have at least "fld0/1" or "equals, greaterThan, etc."
689: // Some bogus fields will slip in, like "ENTITY_NAME", but they will be ignored
690:
691: fieldNameRoot = fieldNameRaw.substring(0, iPos);
692: }
693: if (modelEntity.isField(fieldNameRoot)) {
694: normalizedFields.put(fieldNameRaw, fieldValue);
695: }
696: }
697: return normalizedFields;
698: }
699:
700: /**
701: * Returns the first generic item of the service 'performFind'
702: * Same parameters as performFind service but returns a single GenericValue
703: *
704: * @param dctx
705: * @param context
706: * @return
707: */
708: public static Map performFindItem(DispatchContext dctx, Map context) {
709: Map result = org.ofbiz.common.FindServices.performFind(dctx,
710: context);
711:
712: List list = null;
713: GenericValue item = null;
714: try {
715: EntityListIterator it = (EntityListIterator) result
716: .get("listIt");
717: list = it.getPartialList(1, 1); // list starts at '1'
718: if (list != null && list.size() > 0) {
719: item = (GenericValue) list.get(0);
720: }
721: it.close();
722: } catch (Exception e) {
723: Debug.logInfo("Problem getting list Item" + e, module);
724: }
725:
726: if (!UtilValidate.isEmpty(item)) {
727: result.put("item", item);
728: }
729: result.remove("listIt");
730: return result;
731: }
732: }
|