001: /*
002: * $Id: ParametricSearch.java,v 1.14 2004/01/26 22:13:25 jonesde Exp $
003: *
004: * Copyright (c) 2001 The Open For Business Project (www.ofbiz.org)
005: * Permission is hereby granted, free of charge, to any person obtaining a
006: * copy of this software and associated documentation files (the "Software"),
007: * to deal in the Software without restriction, including without limitation
008: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
009: * and/or sell copies of the Software, and to permit persons to whom the
010: * Software is furnished to do so, subject to the following conditions:
011: *
012: * The above copyright notice and this permission notice shall be included
013: * in all copies or substantial portions of the Software.
014: *
015: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
016: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
017: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
018: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
019: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
020: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
021: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
022: */
023: package org.ofbiz.product.feature;
024:
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import javax.servlet.ServletRequest;
034: import javax.servlet.http.HttpServletRequest;
035:
036: import org.ofbiz.base.util.Debug;
037: import org.ofbiz.base.util.UtilHttp;
038: import org.ofbiz.base.util.UtilMisc;
039: import org.ofbiz.entity.GenericDelegator;
040: import org.ofbiz.entity.GenericEntityException;
041: import org.ofbiz.entity.GenericValue;
042: import org.ofbiz.entity.util.EntityListIterator;
043: import org.ofbiz.entity.util.EntityUtil;
044:
045: /**
046: * Utilities for parametric search based on features.
047: *
048: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
049: * @version $Revision: 1.14 $
050: * @since 2.1
051: */
052: public class ParametricSearch {
053:
054: public static final String module = ParametricSearch.class
055: .getName();
056:
057: public static final int DEFAULT_PER_TYPE_MAX_SIZE = 1000;
058:
059: // caches expire after 10 minutes, a reasonable value hopefully...
060: //public static UtilCache featureAllCache = new UtilCache("custom.FeaturePerTypeAll", 0, 600000, true);
061: //public static UtilCache featureByCategoryCache = new UtilCache("custom.FeaturePerTypeByCategory", 0, 600000, true);
062:
063: /** Gets all features associated with the specified category through:
064: * ProductCategory -> ProductFeatureCategoryAppl -> ProductFeatureCategory -> ProductFeature.
065: * Returns a Map of Lists of ProductFeature GenericValue objects organized by productFeatureTypeId.
066: */
067: public static Map makeCategoryFeatureLists(
068: String productCategoryId, GenericDelegator delegator) {
069: return makeCategoryFeatureLists(productCategoryId, delegator,
070: DEFAULT_PER_TYPE_MAX_SIZE);
071: }
072:
073: public static Map makeCategoryFeatureLists(
074: String productCategoryId, GenericDelegator delegator,
075: int perTypeMaxSize) {
076: Map productFeaturesByTypeMap = new HashMap();
077: try {
078: List productFeatureCategoryAppls = delegator
079: .findByAndCache("ProductFeatureCategoryAppl",
080: UtilMisc.toMap("productCategoryId",
081: productCategoryId));
082: productFeatureCategoryAppls = EntityUtil.filterByDate(
083: productFeatureCategoryAppls, true);
084: if (productFeatureCategoryAppls != null) {
085: Iterator pfcasIter = productFeatureCategoryAppls
086: .iterator();
087: while (pfcasIter.hasNext()) {
088: GenericValue productFeatureCategoryAppl = (GenericValue) pfcasIter
089: .next();
090: List productFeatures = delegator
091: .findByAndCache(
092: "ProductFeature",
093: UtilMisc
094: .toMap(
095: "productFeatureCategoryId",
096: productFeatureCategoryAppl
097: .get("productFeatureCategoryId")));
098: Iterator pfsIter = productFeatures.iterator();
099: while (pfsIter.hasNext()) {
100: GenericValue productFeature = (GenericValue) pfsIter
101: .next();
102: String productFeatureTypeId = productFeature
103: .getString("productFeatureTypeId");
104: Map featuresByType = (Map) productFeaturesByTypeMap
105: .get(productFeatureTypeId);
106: if (featuresByType == null) {
107: featuresByType = new HashMap();
108: productFeaturesByTypeMap.put(
109: productFeatureTypeId,
110: featuresByType);
111: }
112: if (featuresByType.size() < perTypeMaxSize) {
113: featuresByType.put(productFeature
114: .get("productFeatureId"),
115: productFeature);
116: }
117: }
118: }
119: }
120: } catch (GenericEntityException e) {
121: Debug.logError(e,
122: "Error getting feature categories associated with the category with ID: "
123: + productCategoryId, module);
124: }
125:
126: try {
127: List productFeatureCatGrpAppls = delegator.findByAndCache(
128: "ProductFeatureCatGrpAppl", UtilMisc.toMap(
129: "productCategoryId", productCategoryId));
130: productFeatureCatGrpAppls = EntityUtil.filterByDate(
131: productFeatureCatGrpAppls, true);
132: if (productFeatureCatGrpAppls != null) {
133: Iterator pfcgasIter = productFeatureCatGrpAppls
134: .iterator();
135: while (pfcgasIter.hasNext()) {
136: GenericValue productFeatureCatGrpAppl = (GenericValue) pfcgasIter
137: .next();
138: List productFeatureGroupAppls = delegator
139: .findByAndCache(
140: "ProductFeatureGroupAppl",
141: UtilMisc
142: .toMap(
143: "productFeatureGroupId",
144: productFeatureCatGrpAppl
145: .get("productFeatureGroupId")));
146: Iterator pfgaasIter = productFeatureGroupAppls
147: .iterator();
148: while (pfgaasIter.hasNext()) {
149: GenericValue productFeatureGroupAppl = (GenericValue) pfgaasIter
150: .next();
151: GenericValue productFeature = delegator
152: .findByPrimaryKeyCache(
153: "ProductFeature",
154: UtilMisc
155: .toMap(
156: "productFeatureId",
157: productFeatureGroupAppl
158: .get("productFeatureId")));
159:
160: String productFeatureTypeId = productFeature
161: .getString("productFeatureTypeId");
162: Map featuresByType = (Map) productFeaturesByTypeMap
163: .get(productFeatureTypeId);
164: if (featuresByType == null) {
165: featuresByType = new HashMap();
166: productFeaturesByTypeMap.put(
167: productFeatureTypeId,
168: featuresByType);
169: }
170: if (featuresByType.size() < perTypeMaxSize) {
171: featuresByType.put(productFeature
172: .get("productFeatureId"),
173: productFeature);
174: }
175: }
176: }
177: }
178: } catch (GenericEntityException e) {
179: Debug.logError(e,
180: "Error getting feature groups associated with the category with ID: "
181: + productCategoryId, module);
182: }
183:
184: // now before returning, order the features in each list by description
185: Iterator productFeatureTypeEntries = productFeaturesByTypeMap
186: .entrySet().iterator();
187: while (productFeatureTypeEntries.hasNext()) {
188: Map.Entry entry = (Map.Entry) productFeatureTypeEntries
189: .next();
190: List sortedFeatures = EntityUtil.orderBy(((Map) entry
191: .getValue()).values(), UtilMisc
192: .toList("description"));
193: productFeaturesByTypeMap
194: .put(entry.getKey(), sortedFeatures);
195: }
196:
197: return productFeaturesByTypeMap;
198: }
199:
200: public static Map getAllFeaturesByType(GenericDelegator delegator) {
201: return getAllFeaturesByType(delegator,
202: DEFAULT_PER_TYPE_MAX_SIZE);
203: }
204:
205: public static Map getAllFeaturesByType(GenericDelegator delegator,
206: int perTypeMaxSize) {
207: Map productFeaturesByTypeMap = new HashMap();
208: try {
209: Set typesWithOverflowMessages = new HashSet();
210: EntityListIterator productFeatureEli = delegator
211: .findListIteratorByCondition("ProductFeature",
212: null, null, UtilMisc.toList("description"));
213: GenericValue productFeature = null;
214: while ((productFeature = (GenericValue) productFeatureEli
215: .next()) != null) {
216: String productFeatureTypeId = productFeature
217: .getString("productFeatureTypeId");
218: List featuresByType = (List) productFeaturesByTypeMap
219: .get(productFeatureTypeId);
220: if (featuresByType == null) {
221: featuresByType = new LinkedList();
222: productFeaturesByTypeMap.put(productFeatureTypeId,
223: featuresByType);
224: }
225: if (featuresByType.size() > perTypeMaxSize) {
226: if (!typesWithOverflowMessages
227: .contains(productFeatureTypeId)) {
228: typesWithOverflowMessages
229: .add(productFeatureTypeId);
230: // TODO: uh oh, how do we pass this message back? no biggie for now
231: }
232: } else {
233: featuresByType.add(productFeature);
234: }
235: }
236: } catch (GenericEntityException e) {
237: Debug.logError(e, "Error getting all features", module);
238: }
239: return productFeaturesByTypeMap;
240: }
241:
242: public static Map makeFeatureIdByTypeMap(ServletRequest request) {
243: Map parameters = UtilHttp
244: .getParameterMap((HttpServletRequest) request);
245: return makeFeatureIdByTypeMap(parameters);
246: }
247:
248: public static Map makeFeatureIdByTypeMap(Map parameters) {
249: Map featureIdByType = new HashMap();
250: if (parameters == null)
251: return featureIdByType;
252:
253: Iterator parameterNameIter = parameters.keySet().iterator();
254: while (parameterNameIter.hasNext()) {
255: String parameterName = (String) parameterNameIter.next();
256: if (parameterName.startsWith("pft_")) {
257: String productFeatureTypeId = parameterName
258: .substring(4);
259: String productFeatureId = (String) parameters
260: .get(parameterName);
261: if (productFeatureId != null
262: && productFeatureId.length() > 0) {
263: featureIdByType.put(productFeatureTypeId,
264: productFeatureId);
265: }
266: }
267: }
268:
269: return featureIdByType;
270: }
271:
272: public static String makeFeatureIdByTypeString(Map featureIdByType) {
273: if (featureIdByType == null || featureIdByType.size() == 0) {
274: return "";
275: }
276:
277: StringBuffer outSb = new StringBuffer();
278: Iterator fbtIter = featureIdByType.entrySet().iterator();
279: while (fbtIter.hasNext()) {
280: Map.Entry entry = (Map.Entry) fbtIter.next();
281: String productFeatureTypeId = (String) entry.getKey();
282: String productFeatureId = (String) entry.getValue();
283: outSb.append(productFeatureTypeId);
284: outSb.append('=');
285: outSb.append(productFeatureId);
286: if (fbtIter.hasNext()) {
287: outSb.append('&');
288: }
289: }
290:
291: return outSb.toString();
292: }
293:
294: /* TODO: DEJ 20031025 delete this if not used in the near future
295: public static void filterProductIdListByFeatures(List productIds, Map featureIdByType, GenericDelegator delegator) {
296: if (productIds == null || productIds.size() == 0) return;
297: //filter search results by features
298:
299: // the fun part: go through each product and make sure it has all specified features
300: Iterator productIdsIter = productIds.iterator();
301: while (productIdsIter.hasNext()) {
302: String productId = (String) productIdsIter.next();
303:
304: boolean doRemove = false;
305: Iterator requiredFeaturesIter = featureIdByType.values().iterator();
306: while (!doRemove && requiredFeaturesIter.hasNext()) {
307: String productFeatureId = (String) requiredFeaturesIter.next();
308: List productFeatureAppl = null;
309: try {
310: // for now only constraining by productId and productFeatureId, so any appl type will be included...
311: productFeatureAppl = delegator.findByAndCache("ProductFeatureAppl", UtilMisc.toMap("productId", productId, "productFeatureId", productFeatureId));
312: } catch (GenericEntityException e) {
313: Debug.logError(e, "Error getting feature appls associated with the productId: [" + productId + "] and the productFeatureId [" + productFeatureId + "], removing product from search match list.", module);
314: doRemove = true;
315: continue;
316: }
317:
318: productFeatureAppl = EntityUtil.filterByDate(productFeatureAppl, true);
319: if (productFeatureAppl == null || productFeatureAppl.size() == 0) {
320: doRemove = true;
321: }
322: }
323:
324: if (doRemove) {
325: productIdsIter.remove();
326: }
327: }
328: }
329:
330: public static ArrayList parametricKeywordSearch(Map featureIdByType, String keywordsString, GenericDelegator delegator, String categoryId, String visitId, boolean anyPrefix, boolean anySuffix, boolean isAnd) {
331: ArrayList productIds = KeywordSearch.productsByKeywords(keywordsString, delegator, categoryId, visitId, anyPrefix, anySuffix, isAnd);
332: filterProductIdListByFeatures(productIds, featureIdByType, delegator);
333: return productIds;
334: }
335: */
336: }
|