/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache 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.apache.org/licenses/LICENSE-2.0 * * 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.apache.ofbiz.product.product; import java.io.IOException; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.UtilDateTime; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.base.util.UtilHttp; import org.apache.ofbiz.base.util.UtilMisc; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.GenericValue; import org.apache.ofbiz.entity.condition.EntityCondition; import org.apache.ofbiz.entity.condition.EntityOperator; import org.apache.ofbiz.entity.model.DynamicViewEntity; import org.apache.ofbiz.entity.model.ModelKeyMap; import org.apache.ofbiz.entity.util.EntityListIterator; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityUtilProperties; import org.apache.ofbiz.product.catalog.CatalogWorker; import org.apache.ofbiz.product.category.CategoryWorker; import org.apache.ofbiz.product.feature.ParametricSearch; import org.apache.ofbiz.product.product.ProductSearch.CategoryConstraint; import org.apache.ofbiz.product.product.ProductSearch.FeatureConstraint; import org.apache.ofbiz.product.product.ProductSearch.KeywordConstraint; import org.apache.ofbiz.product.product.ProductSearch.ProductSearchConstraint; import org.apache.ofbiz.product.product.ProductSearch.ProductSearchContext; import org.apache.ofbiz.product.product.ProductSearch.ResultSortOrder; import org.apache.ofbiz.product.product.ProductSearch.SortKeywordRelevancy; import org.apache.ofbiz.product.store.ProductStoreWorker; import org.apache.ofbiz.webapp.control.RequestHandler; import org.apache.ofbiz.webapp.stats.VisitHandler; /** * Utility class with methods to prepare and perform ProductSearch operations in the content of an HttpSession */ public class ProductSearchSession { public static final String module = ProductSearchSession.class.getName(); @SuppressWarnings("serial") public static class ProductSearchOptions implements java.io.Serializable { protected List<ProductSearchConstraint> constraintList = null; protected String topProductCategoryId = null; protected ResultSortOrder resultSortOrder = null; protected Integer viewIndex = null; protected Integer viewSize = null; protected boolean changed = false; protected String paging = "Y"; protected Integer previousViewSize = null; public ProductSearchOptions() { } /** Basic copy constructor */ public ProductSearchOptions(ProductSearchOptions productSearchOptions) { this.constraintList = new LinkedList<ProductSearch.ProductSearchConstraint>(); if (UtilValidate.isNotEmpty(productSearchOptions.constraintList)) { this.constraintList.addAll(productSearchOptions.constraintList); } this.topProductCategoryId = productSearchOptions.topProductCategoryId; this.resultSortOrder = productSearchOptions.resultSortOrder; this.viewIndex = productSearchOptions.viewIndex; this.viewSize = productSearchOptions.viewSize; this.changed = productSearchOptions.changed; this.paging = productSearchOptions.paging; this.previousViewSize = productSearchOptions.previousViewSize; } public List<ProductSearchConstraint> getConstraintList() { return this.constraintList; } public static List<ProductSearchConstraint> getConstraintList(HttpSession session) { return getProductSearchOptions(session).constraintList; } public static void addConstraint(ProductSearchConstraint productSearchConstraint, HttpSession session) { ProductSearchOptions productSearchOptions = getProductSearchOptions(session); if (productSearchOptions.constraintList == null) { productSearchOptions.constraintList = new LinkedList<ProductSearch.ProductSearchConstraint>(); } if (!productSearchOptions.constraintList.contains(productSearchConstraint)) { productSearchOptions.constraintList.add(productSearchConstraint); productSearchOptions.changed = true; } } public ResultSortOrder getResultSortOrder() { if (this.resultSortOrder == null) { this.resultSortOrder = new SortKeywordRelevancy(); this.changed = true; } return this.resultSortOrder; } public static ResultSortOrder getResultSortOrder(HttpServletRequest request) { ProductSearchOptions productSearchOptions = getProductSearchOptions(request.getSession()); return productSearchOptions.getResultSortOrder(); } public static void setResultSortOrder(ResultSortOrder resultSortOrder, HttpSession session) { ProductSearchOptions productSearchOptions = getProductSearchOptions(session); productSearchOptions.resultSortOrder = resultSortOrder; productSearchOptions.changed = true; } public static void clearSearchOptions(HttpSession session) { ProductSearchOptions productSearchOptions = getProductSearchOptions(session); productSearchOptions.constraintList = null; productSearchOptions.topProductCategoryId = null; productSearchOptions.resultSortOrder = null; } public void clearViewInfo() { this.viewIndex = null; this.viewSize = null; this.paging = "Y"; this.previousViewSize = null; } /** * Get the view size * @return returns the viewIndex. */ public Integer getViewIndex() { return viewIndex; } /** * Set the view index * @param viewIndex the viewIndex to set. */ public void setViewIndex(Integer viewIndex) { this.viewIndex = viewIndex; } /** * Set the view index * @param viewIndexStr the viewIndex to set. */ public void setViewIndex(String viewIndexStr) { if (UtilValidate.isEmpty(viewIndexStr)) { return; } try { this.setViewIndex(Integer.valueOf(viewIndexStr)); } catch (Exception e) { Debug.logError(e, "Error in formatting of VIEW_INDEX [" + viewIndexStr + "], setting to 20", module); if (this.viewIndex == null) { this.setViewIndex(Integer.valueOf(20)); } } } /** * Get the view size * @return returns the view size. */ public Integer getViewSize() { return viewSize; } /** * Set the view size * @param viewSize the view size to set. */ public void setViewSize(Integer viewSize) { setPreviousViewSize(getViewSize()); this.viewSize = viewSize; } /** * Set the view size * @param viewSizeStr the view size to set. */ public void setViewSize(String viewSizeStr) { if (UtilValidate.isEmpty(viewSizeStr)) { return; } try { this.setViewSize(Integer.valueOf(viewSizeStr)); } catch (Exception e) { Debug.logError(e, "Error in formatting of VIEW_SIZE [" + viewSizeStr + "], setting to 20", module); if (this.viewSize == null) { this.setViewSize(Integer.valueOf(20)); } } } /** * Get the paging * @return Returns the paging */ public String getPaging() { return paging; } /** * Set the paging * @param paging the paging to set */ public void setPaging(String paging) { if (paging == null) { paging = "Y"; } this.paging = paging; } /** * Get the previous view size * @return returns the previous view size */ public Integer getPreviousViewSize() { return previousViewSize; } /** * Set the previous view size * @param previousViewSize the previousViewSize to set. */ public void setPreviousViewSize(Integer previousViewSize) { if (previousViewSize == null) { this.previousViewSize = Integer.valueOf(20); } else { this.previousViewSize = previousViewSize; } } public String getTopProductCategoryId() { return topProductCategoryId; } public static void setTopProductCategoryId(String topProductCategoryId, HttpSession session) { ProductSearchOptions productSearchOptions = getProductSearchOptions(session); productSearchOptions.setTopProductCategoryId(topProductCategoryId); } public void setTopProductCategoryId(String topProductCategoryId) { if (this.topProductCategoryId != null && topProductCategoryId != null) { if (!this.topProductCategoryId.equals(topProductCategoryId)) { this.topProductCategoryId = topProductCategoryId; this.changed = true; } } else { if (this.topProductCategoryId != null || topProductCategoryId != null) { this.topProductCategoryId = topProductCategoryId; this.changed = true; } } } public List<String> searchGetConstraintStrings(boolean detailed, Delegator delegator, Locale locale) { List<ProductSearchConstraint> productSearchConstraintList = this.getConstraintList(); List<String> constraintStrings = new LinkedList<String>(); if (productSearchConstraintList == null) { return constraintStrings; } for (ProductSearchConstraint productSearchConstraint: productSearchConstraintList) { if (productSearchConstraint == null) continue; String constraintString = productSearchConstraint.prettyPrintConstraint(delegator, detailed, locale); if (UtilValidate.isNotEmpty(constraintString)) { constraintStrings.add(constraintString); } else { constraintStrings.add("Description not available"); } } return constraintStrings; } } public static ProductSearchOptions getProductSearchOptions(HttpSession session) { ProductSearchOptions productSearchOptions = (ProductSearchOptions) session.getAttribute("_PRODUCT_SEARCH_OPTIONS_CURRENT_"); if (productSearchOptions == null) { productSearchOptions = new ProductSearchOptions(); session.setAttribute("_PRODUCT_SEARCH_OPTIONS_CURRENT_", productSearchOptions); } return productSearchOptions; } public static void checkSaveSearchOptionsHistory(HttpSession session) { ProductSearchOptions productSearchOptions = getProductSearchOptions(session); // if the options have changed since the last search, add it to the beginning of the search options history if (productSearchOptions.changed) { List<ProductSearchOptions> optionsHistoryList = getSearchOptionsHistoryList(session); optionsHistoryList.add(0, new ProductSearchOptions(productSearchOptions)); productSearchOptions.changed = false; } } public static List<ProductSearchOptions> getSearchOptionsHistoryList(HttpSession session) { List<ProductSearchOptions> optionsHistoryList = UtilGenerics.checkList(session.getAttribute("_PRODUCT_SEARCH_OPTIONS_HISTORY_")); if (optionsHistoryList == null) { optionsHistoryList = new LinkedList<ProductSearchSession.ProductSearchOptions>(); session.setAttribute("_PRODUCT_SEARCH_OPTIONS_HISTORY_", optionsHistoryList); } return optionsHistoryList; } public static void clearSearchOptionsHistoryList(HttpSession session) { session.removeAttribute("_PRODUCT_SEARCH_OPTIONS_HISTORY_"); } public static void setCurrentSearchFromHistory(int index, boolean removeOld, HttpSession session) { List<ProductSearchOptions> searchOptionsHistoryList = getSearchOptionsHistoryList(session); if (index < searchOptionsHistoryList.size()) { ProductSearchOptions productSearchOptions = searchOptionsHistoryList.get(index); if (removeOld) { searchOptionsHistoryList.remove(index); } if (productSearchOptions != null) { session.setAttribute("_PRODUCT_SEARCH_OPTIONS_CURRENT_", new ProductSearchOptions(productSearchOptions)); } } else { throw new IllegalArgumentException("Could not set current search options to history index [" + index + "], only [" + searchOptionsHistoryList.size() + "] entries in the history list."); } } public static String clearSearchOptionsHistoryList(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); clearSearchOptionsHistoryList(session); return "success"; } public static String setCurrentSearchFromHistory(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); String searchHistoryIndexStr = request.getParameter("searchHistoryIndex"); String removeOldStr = request.getParameter("removeOld"); if (UtilValidate.isEmpty(searchHistoryIndexStr)) { request.setAttribute("_ERROR_MESSAGE_", "No search history index passed, cannot set current search to previous."); return "error"; } try { int searchHistoryIndex = Integer.parseInt(searchHistoryIndexStr); boolean removeOld = true; if (UtilValidate.isNotEmpty(removeOldStr)) { removeOld = !"false".equals(removeOldStr); } setCurrentSearchFromHistory(searchHistoryIndex, removeOld, session); } catch (Exception e) { request.setAttribute("_ERROR_MESSAGE_", e.toString()); return "error"; } return "success"; } /** A ControlServlet event method used to check to see if there is an override for any of the current keywords in the search */ public static final String checkDoKeywordOverride(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Delegator delegator = (Delegator) request.getAttribute("delegator"); Map<String, Object> requestParams = UtilHttp.getParameterMap(request); ProductSearchSession.processSearchParameters(requestParams, request); // get the current productStoreId String productStoreId = ProductStoreWorker.getProductStoreId(request); if (productStoreId != null) { // get a Set of all keywords in the search, if there are any... Set<String> keywords = new HashSet<String>(); List<ProductSearchConstraint> constraintList = ProductSearchOptions.getConstraintList(session); if (constraintList != null) { for (ProductSearchConstraint constraint: constraintList) { if (constraint instanceof KeywordConstraint) { KeywordConstraint keywordConstraint = (KeywordConstraint) constraint; Set<String> keywordSet = keywordConstraint.makeFullKeywordSet(delegator); if (keywordSet != null) keywords.addAll(keywordSet); } } } if (keywords.size() > 0) { List<GenericValue> productStoreKeywordOvrdList = null; try { productStoreKeywordOvrdList = EntityQuery.use(delegator).from("ProductStoreKeywordOvrd").where("productStoreId", productStoreId).orderBy("-fromDate").cache(true).filterByDate().queryList(); } catch (GenericEntityException e) { Debug.logError(e, "Error reading ProductStoreKeywordOvrd list, not doing keyword override", module); } if (UtilValidate.isNotEmpty(productStoreKeywordOvrdList)) { for (GenericValue productStoreKeywordOvrd: productStoreKeywordOvrdList) { String ovrdKeyword = productStoreKeywordOvrd.getString("keyword"); if (keywords.contains(ovrdKeyword)) { String targetTypeEnumId = productStoreKeywordOvrd.getString("targetTypeEnumId"); String target = productStoreKeywordOvrd.getString("target"); ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); if ("KOTT_PRODCAT".equals(targetTypeEnumId)) { String requestName = "/category/~category_id=" + target; target = rh.makeLink(request, response, requestName, false, false, false); } else if ("KOTT_PRODUCT".equals(targetTypeEnumId)) { String requestName = "/product/~product_id=" + target; target = rh.makeLink(request, response, requestName, false, false, false); } else if ("KOTT_OFBURL".equals(targetTypeEnumId)) { target = rh.makeLink(request, response, target, false, false, false); } else if ("KOTT_AURL".equals(targetTypeEnumId)) { // do nothing, is absolute URL } else { Debug.logError("The targetTypeEnumId [] is not recognized, not doing keyword override", module); // might as well see if there are any others... continue; } try { response.sendRedirect(target); return "none"; } catch (IOException e) { Debug.logError(e, "Could not send redirect to: " + target, module); continue; } } } } } } return "success"; } public static ArrayList<String> searchDo(HttpSession session, Delegator delegator, String prodCatalogId) { String visitId = VisitHandler.getVisitId(session); ProductSearchOptions productSearchOptions = getProductSearchOptions(session); List<ProductSearchConstraint> productSearchConstraintList = productSearchOptions.getConstraintList(); if (UtilValidate.isEmpty(productSearchConstraintList)) { // no constraints, don't do a search... return new ArrayList<String>(); } ResultSortOrder resultSortOrder = productSearchOptions.getResultSortOrder(); // if the search options have changed since the last search, put at the beginning of the options history list checkSaveSearchOptionsHistory(session); return ProductSearch.searchProducts(productSearchConstraintList, resultSortOrder, delegator, visitId); } public static void searchClear(HttpSession session) { ProductSearchOptions.clearSearchOptions(session); } public static List<String> searchGetConstraintStrings(boolean detailed, HttpSession session, Delegator delegator) { Locale locale = UtilHttp.getLocale(session); ProductSearchOptions productSearchOptions = getProductSearchOptions(session); return productSearchOptions.searchGetConstraintStrings(detailed, delegator, locale); } public static String searchGetSortOrderString(boolean detailed, HttpServletRequest request) { Locale locale = UtilHttp.getLocale(request); ResultSortOrder resultSortOrder = ProductSearchOptions.getResultSortOrder(request); if (resultSortOrder == null) return ""; return resultSortOrder.prettyPrintSortOrder(detailed, locale); } public static void searchSetSortOrder(ResultSortOrder resultSortOrder, HttpSession session) { ProductSearchOptions.setResultSortOrder(resultSortOrder, session); } public static void searchAddFeatureIdConstraints(Collection<String> featureIds, Boolean exclude, HttpServletRequest request) { HttpSession session = request.getSession(); if (UtilValidate.isEmpty(featureIds)) { return; } for (String productFeatureId: featureIds) { searchAddConstraint(new FeatureConstraint(productFeatureId, exclude), session); } } public static void searchAddConstraint(ProductSearchConstraint productSearchConstraint, HttpSession session) { ProductSearchOptions.addConstraint(productSearchConstraint, session); } public static void searchRemoveConstraint(int index, HttpSession session) { List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); if (productSearchConstraintList == null) { return; } else if (index >= productSearchConstraintList.size()) { return; } else { productSearchConstraintList.remove(index); } } public static void processSearchParameters(Map<String, Object> parameters, HttpServletRequest request) { Delegator delegator = (Delegator) request.getAttribute("delegator"); Boolean alreadyRun = (Boolean) request.getAttribute("processSearchParametersAlreadyRun"); if (Boolean.TRUE.equals(alreadyRun)) { // even if already run, check the VIEW_SIZE and VIEW_INDEX again, just for kicks ProductSearchOptions productSearchOptions = getProductSearchOptions(request.getSession()); productSearchOptions.setViewIndex((String) parameters.get("VIEW_INDEX")); productSearchOptions.setViewSize((String) parameters.get("VIEW_SIZE")); productSearchOptions.setPaging((String) parameters.get("PAGING")); return; } else { request.setAttribute("processSearchParametersAlreadyRun", Boolean.TRUE); } HttpSession session = request.getSession(); boolean constraintsChanged = false; GenericValue productStore = ProductStoreWorker.getProductStore(request); // clear search? by default yes, but if the clearSearch parameter is N then don't String clearSearchString = (String) parameters.get("clearSearch"); if (!"N".equals(clearSearchString)) { searchClear(session); constraintsChanged = true; } else { String removeConstraint = (String) parameters.get("removeConstraint"); if (UtilValidate.isNotEmpty(removeConstraint)) { try { searchRemoveConstraint(Integer.parseInt(removeConstraint), session); constraintsChanged = true; } catch (Exception e) { Debug.logError(e, "Error removing constraint [" + removeConstraint + "]", module); } } } String prioritizeCategoryId = null; if (UtilValidate.isNotEmpty(parameters.get("PRIORITIZE_CATEGORY_ID"))) { prioritizeCategoryId = (String) parameters.get("PRIORITIZE_CATEGORY_ID"); } else if (UtilValidate.isNotEmpty(parameters.get("S_TPC"))) { prioritizeCategoryId = (String) parameters.get("S_TPC"); } if (UtilValidate.isNotEmpty(prioritizeCategoryId)) { ProductSearchOptions.setTopProductCategoryId(prioritizeCategoryId, session); constraintsChanged = true; } // if there is another category, add a constraint for it if (UtilValidate.isNotEmpty(parameters.get("SEARCH_CATEGORY_ID"))) { String searchCategoryId = (String) parameters.get("SEARCH_CATEGORY_ID"); String searchSubCategories = (String) parameters.get("SEARCH_SUB_CATEGORIES"); String searchCategoryExc = (String) parameters.get("SEARCH_CATEGORY_EXC"); Boolean exclude = UtilValidate.isEmpty(searchCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchCategoryExc)); searchAddConstraint(new ProductSearch.CategoryConstraint(searchCategoryId, !"N".equals(searchSubCategories), exclude), session); constraintsChanged = true; } for (int catNum = 1; catNum < 10; catNum++) { if (UtilValidate.isNotEmpty(parameters.get("SEARCH_CATEGORY_ID" + catNum))) { String searchCategoryId = (String) parameters.get("SEARCH_CATEGORY_ID" + catNum); String searchSubCategories = (String) parameters.get("SEARCH_SUB_CATEGORIES" + catNum); String searchCategoryExc = (String) parameters.get("SEARCH_CATEGORY_EXC" + catNum); Boolean exclude = UtilValidate.isEmpty(searchCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchCategoryExc)); searchAddConstraint(new ProductSearch.CategoryConstraint(searchCategoryId, !"N".equals(searchSubCategories), exclude), session); constraintsChanged = true; } } // a shorter variation for categories for (int catNum = 1; catNum < 10; catNum++) { if (UtilValidate.isNotEmpty(parameters.get("S_CAT" + catNum))) { String searchCategoryId = (String) parameters.get("S_CAT" + catNum); String searchSubCategories = (String) parameters.get("S_CSB" + catNum); String searchCategoryExc = (String) parameters.get("S_CEX" + catNum); Boolean exclude = UtilValidate.isEmpty(searchCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchCategoryExc)); searchAddConstraint(new ProductSearch.CategoryConstraint(searchCategoryId, !"N".equals(searchSubCategories), exclude), session); constraintsChanged = true; } } // if there is any category selected try to use catalog and add a constraint for it if (UtilValidate.isNotEmpty(parameters.get("SEARCH_CATALOG_ID"))) { String searchCatalogId = (String) parameters.get("SEARCH_CATALOG_ID"); if (searchCatalogId != null && !searchCatalogId.equalsIgnoreCase("")) { String topCategory = CatalogWorker.getCatalogTopCategoryId(request, searchCatalogId); if (UtilValidate.isEmpty(topCategory)) { topCategory = CatalogWorker.getCatalogTopEbayCategoryId(request, searchCatalogId); } List<GenericValue> categories = CategoryWorker.getRelatedCategoriesRet(request, "topLevelList", topCategory, true, false, true); searchAddConstraint(new ProductSearch.CatalogConstraint(searchCatalogId, categories), session); constraintsChanged = true; } } // if keywords were specified, add a constraint for them if (UtilValidate.isNotEmpty(parameters.get("SEARCH_STRING"))) { String keywordString = (String) parameters.get("SEARCH_STRING"); String searchOperator = (String) parameters.get("SEARCH_OPERATOR"); // defaults to true/Y, ie anything but N is true/Y boolean anyPrefixSuffix = !"N".equals(parameters.get("SEARCH_ANYPRESUF")); searchAddConstraint(new ProductSearch.KeywordConstraint(keywordString, anyPrefixSuffix, anyPrefixSuffix, null, "AND".equals(searchOperator)), session); constraintsChanged = true; } // if productName were specified, add a constraint for them if (UtilValidate.isNotEmpty(parameters.get("SEARCH_PRODUCT_NAME"))) { String productName = (String) parameters.get("SEARCH_PRODUCT_NAME"); searchAddConstraint(new ProductSearch.ProductFieldConstraint(productName, "productName"), session); constraintsChanged = true; } // if internalName were specified, add a constraint for them if (UtilValidate.isNotEmpty(parameters.get("SEARCH_INTERNAL_PROD_NAME"))) { String internalName = (String) parameters.get("SEARCH_INTERNAL_PROD_NAME"); searchAddConstraint(new ProductSearch.ProductFieldConstraint(internalName, "internalName"), session); constraintsChanged = true; } for (int kwNum = 1; kwNum < 10; kwNum++) { if (UtilValidate.isNotEmpty(parameters.get("SEARCH_STRING" + kwNum))) { String keywordString = (String) parameters.get("SEARCH_STRING" + kwNum); String searchOperator = (String) parameters.get("SEARCH_OPERATOR" + kwNum); // defaults to true/Y, ie anything but N is true/Y boolean anyPrefixSuffix = !"N".equals(parameters.get("SEARCH_ANYPRESUF" + kwNum)); searchAddConstraint(new ProductSearch.KeywordConstraint(keywordString, anyPrefixSuffix, anyPrefixSuffix, null, "AND".equals(searchOperator)), session); constraintsChanged = true; } } for (String parameterName: parameters.keySet()) { if (parameterName.startsWith("SEARCH_FEAT") && !parameterName.startsWith("SEARCH_FEAT_EXC")) { String productFeatureId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureId)) { String paramNameExt = parameterName.substring("SEARCH_FEAT".length()); String searchCategoryExc = (String) parameters.get("SEARCH_FEAT_EXC" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchCategoryExc)); //Debug.logInfo("parameterName=" + parameterName + ", paramNameExt=" + paramNameExt + ", searchCategoryExc=" + searchCategoryExc + ", exclude=" + exclude, module); searchAddConstraint(new ProductSearch.FeatureConstraint(productFeatureId, exclude), session); constraintsChanged = true; } } // a shorter feature variation if (parameterName.startsWith("S_PFI")) { String productFeatureId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureId)) { String paramNameExt = parameterName.substring("S_PFI".length()); String searchCategoryExc = (String) parameters.get("S_PFX" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchCategoryExc)); searchAddConstraint(new ProductSearch.FeatureConstraint(productFeatureId, exclude), session); constraintsChanged = true; } } //if product features category were selected add a constraint for each if (parameterName.startsWith("SEARCH_PROD_FEAT_CAT") && !parameterName.startsWith("SEARCH_PROD_FEAT_CAT_EXC")) { String productFeatureCategoryId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureCategoryId)) { String paramNameExt = parameterName.substring("SEARCH_PROD_FEAT_CAT".length()); String searchProdFeatureCategoryExc = (String) parameters.get("SEARCH_PROD_FEAT_CAT_EXC" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchProdFeatureCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchProdFeatureCategoryExc)); searchAddConstraint(new ProductSearch.FeatureCategoryConstraint(productFeatureCategoryId, exclude), session); constraintsChanged = true; } } // a shorter variation for feature category if (parameterName.startsWith("S_FCI")) { String productFeatureCategoryId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureCategoryId)) { String paramNameExt = parameterName.substring("S_FCI".length()); String searchProdFeatureCategoryExc = (String) parameters.get("S_FCX" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchProdFeatureCategoryExc) ? null : Boolean.valueOf(!"N".equals(searchProdFeatureCategoryExc)); searchAddConstraint(new ProductSearch.FeatureCategoryConstraint(productFeatureCategoryId, exclude), session); constraintsChanged = true; } } //if product features group were selected add a constraint for each if (parameterName.startsWith("SEARCH_PROD_FEAT_GRP") && !parameterName.startsWith("SEARCH_PROD_FEAT_GRP_EXC")) { String productFeatureGroupId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureGroupId)) { String paramNameExt = parameterName.substring("SEARCH_PROD_FEAT_GRP".length()); String searchProdFeatureGroupExc = (String) parameters.get("SEARCH_PROD_FEAT_GRP_EXC" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchProdFeatureGroupExc) ? null : Boolean.valueOf(!"N".equals(searchProdFeatureGroupExc)); searchAddConstraint(new ProductSearch.FeatureGroupConstraint(productFeatureGroupId, exclude), session); constraintsChanged = true; } } // a shorter variation for feature group if (parameterName.startsWith("S_FGI")) { String productFeatureGroupId = (String) parameters.get(parameterName); if (UtilValidate.isNotEmpty(productFeatureGroupId)) { String paramNameExt = parameterName.substring("S_FGI".length()); String searchProdFeatureGroupExc = (String) parameters.get("S_FGX" + paramNameExt); Boolean exclude = UtilValidate.isEmpty(searchProdFeatureGroupExc) ? null : Boolean.valueOf(!"N".equals(searchProdFeatureGroupExc)); searchAddConstraint(new ProductSearch.FeatureGroupConstraint(productFeatureGroupId, exclude), session); constraintsChanged = true; } } } // if features were selected add a constraint for each Map<String, String> featureIdByType = ParametricSearch.makeFeatureIdByTypeMap(parameters); if (featureIdByType.size() > 0) { constraintsChanged = true; searchAddFeatureIdConstraints(featureIdByType.values(), null, request); } // add a supplier to the search if (UtilValidate.isNotEmpty(parameters.get("SEARCH_SUPPLIER_ID")) || UtilValidate.isNotEmpty(parameters.get("S_SUP"))) { String supplierPartyId = (String) parameters.get("SEARCH_SUPPLIER_ID"); if (UtilValidate.isEmpty(supplierPartyId)) supplierPartyId = (String) parameters.get("S_SUP"); searchAddConstraint(new ProductSearch.SupplierConstraint(supplierPartyId), session); constraintsChanged = true; } // add a list price range to the search if (UtilValidate.isNotEmpty(parameters.get("LIST_PRICE_LOW")) || UtilValidate.isNotEmpty(parameters.get("LIST_PRICE_HIGH"))) { BigDecimal listPriceLow = null; BigDecimal listPriceHigh = null; String listPriceCurrency = UtilHttp.getCurrencyUom(request); if (UtilValidate.isNotEmpty(parameters.get("LIST_PRICE_LOW"))) { try { listPriceLow = new BigDecimal((String) parameters.get("LIST_PRICE_LOW")); } catch (NumberFormatException e) { Debug.logError("Error parsing LIST_PRICE_LOW parameter [" + (String) parameters.get("LIST_PRICE_LOW") + "]: " + e.toString(), module); } } if (UtilValidate.isNotEmpty(parameters.get("LIST_PRICE_HIGH"))) { try { listPriceHigh = new BigDecimal((String) parameters.get("LIST_PRICE_HIGH")); } catch (NumberFormatException e) { Debug.logError("Error parsing LIST_PRICE_HIGH parameter [" + (String) parameters.get("LIST_PRICE_HIGH") + "]: " + e.toString(), module); } } searchAddConstraint(new ProductSearch.ListPriceRangeConstraint(listPriceLow, listPriceHigh, listPriceCurrency), session); constraintsChanged = true; } if (UtilValidate.isNotEmpty(parameters.get("LIST_PRICE_RANGE")) || UtilValidate.isNotEmpty(parameters.get("S_LPR"))) { String listPriceRangeStr = (String) parameters.get("LIST_PRICE_RANGE"); if (UtilValidate.isEmpty(listPriceRangeStr)) listPriceRangeStr = (String) parameters.get("S_LPR"); int underscoreIndex = listPriceRangeStr.indexOf("_"); String listPriceLowStr; String listPriceHighStr; if (underscoreIndex >= 0) { listPriceLowStr = listPriceRangeStr.substring(0, listPriceRangeStr.indexOf("_")); listPriceHighStr = listPriceRangeStr.substring(listPriceRangeStr.indexOf("_") + 1); } else { // no underscore: assume it is a low range with no high range, ie the ending underscore was left off listPriceLowStr = listPriceRangeStr; listPriceHighStr = null; } BigDecimal listPriceLow = null; BigDecimal listPriceHigh = null; String listPriceCurrency = UtilHttp.getCurrencyUom(request); if (UtilValidate.isNotEmpty(listPriceLowStr)) { try { listPriceLow = new BigDecimal(listPriceLowStr); } catch (NumberFormatException e) { Debug.logError("Error parsing low part of LIST_PRICE_RANGE parameter [" + listPriceLowStr + "]: " + e.toString(), module); } } if (UtilValidate.isNotEmpty(listPriceHighStr)) { try { listPriceHigh = new BigDecimal(listPriceHighStr); } catch (NumberFormatException e) { Debug.logError("Error parsing high part of LIST_PRICE_RANGE parameter [" + listPriceHighStr + "]: " + e.toString(), module); } } searchAddConstraint(new ProductSearch.ListPriceRangeConstraint(listPriceLow, listPriceHigh, listPriceCurrency), session); constraintsChanged = true; } // check the ProductStore to see if we should add the ExcludeVariantsConstraint if (productStore != null && !"N".equals(productStore.getString("prodSearchExcludeVariants"))) { searchAddConstraint(new ProductSearch.ExcludeVariantsConstraint(), session); // not consider this a change for now, shouldn't change often: constraintsChanged = true; } if ("true".equalsIgnoreCase((String) parameters.get("AVAILABILITY_FILTER"))) { searchAddConstraint(new ProductSearch.AvailabilityDateConstraint(), session); constraintsChanged = true; } if (UtilValidate.isNotEmpty(parameters.get("SEARCH_GOOD_IDENTIFICATION_TYPE")) || UtilValidate.isNotEmpty(parameters.get("SEARCH_GOOD_IDENTIFICATION_VALUE"))) { String include = (String) parameters.get("SEARCH_GOOD_IDENTIFICATION_INCL"); if (UtilValidate.isEmpty(include)) { include = "Y"; } Boolean inc = Boolean.TRUE; if ("N".equalsIgnoreCase(include)) { inc = Boolean.FALSE; } searchAddConstraint(new ProductSearch.GoodIdentificationConstraint((String)parameters.get("SEARCH_GOOD_IDENTIFICATION_TYPE"), (String) parameters.get("SEARCH_GOOD_IDENTIFICATION_VALUE"), inc), session); constraintsChanged = true; } String prodCatalogId = CatalogWorker.getCurrentCatalogId(request); String viewProductCategoryId = CatalogWorker.getCatalogViewAllowCategoryId(delegator, prodCatalogId); if (UtilValidate.isNotEmpty(viewProductCategoryId)) { ProductSearchConstraint viewAllowConstraint = new CategoryConstraint(viewProductCategoryId, true, null); searchAddConstraint(viewAllowConstraint, session); // not consider this a change for now, shouldn't change often: constraintsChanged = true; } // set the sort order String sortOrder = (String) parameters.get("sortOrder"); if (UtilValidate.isEmpty(sortOrder)) sortOrder = (String) parameters.get("S_O"); String sortAscending = (String) parameters.get("sortAscending"); if (UtilValidate.isEmpty(sortAscending)) sortAscending = (String) parameters.get("S_A"); boolean ascending = !"N".equals(sortAscending); if (sortOrder != null) { if (sortOrder.equals("SortKeywordRelevancy") || sortOrder.equals("SKR")) { searchSetSortOrder(new ProductSearch.SortKeywordRelevancy(), session); } else if (sortOrder.startsWith("SortProductField:")) { String fieldName = sortOrder.substring("SortProductField:".length()); searchSetSortOrder(new ProductSearch.SortProductField(fieldName, ascending), session); } else if (sortOrder.startsWith("SPF:")) { String fieldName = sortOrder.substring("SPF:".length()); searchSetSortOrder(new ProductSearch.SortProductField(fieldName, ascending), session); } else if (sortOrder.startsWith("SortProductPrice:")) { String priceTypeId = sortOrder.substring("SortProductPrice:".length()); searchSetSortOrder(new ProductSearch.SortProductPrice(priceTypeId, ascending), session); } else if (sortOrder.startsWith("SPP:")) { String priceTypeId = sortOrder.substring("SPP:".length()); searchSetSortOrder(new ProductSearch.SortProductPrice(priceTypeId, ascending), session); } else if (sortOrder.startsWith("SortProductFeature:")) { String featureId = sortOrder.substring("SortProductFeature:".length()); searchSetSortOrder(new ProductSearch.SortProductFeature(featureId, ascending), session); } else if (sortOrder.startsWith("SPFT:")) { String priceTypeId = sortOrder.substring("SPFT:".length()); searchSetSortOrder(new ProductSearch.SortProductPrice(priceTypeId, ascending), session); } } ProductSearchOptions productSearchOptions = getProductSearchOptions(session); if (constraintsChanged) { // query changed, clear out the VIEW_INDEX & VIEW_SIZE productSearchOptions.clearViewInfo(); } productSearchOptions.setViewIndex((String) parameters.get("VIEW_INDEX")); productSearchOptions.setViewSize((String) parameters.get("VIEW_SIZE")); productSearchOptions.setPaging((String) parameters.get("PAGING")); } @SuppressWarnings("unchecked") public static Map<String, Object> getProductSearchResult(HttpServletRequest request, Delegator delegator, String prodCatalogId) { // ========== Create View Indexes int viewIndex = 0; int viewSize = 20; int highIndex = 0; int lowIndex = 0; int listSize = 0; String paging = "Y"; int previousViewSize = 20; Map<String, Object> requestParams = UtilHttp.getCombinedMap(request); List<String> keywordTypeIds = new LinkedList<String>(); if (requestParams.get("keywordTypeId") instanceof String) { keywordTypeIds.add((String) requestParams.get("keywordTypeId")); } else if (requestParams.get("keywordTypeId") instanceof List){ keywordTypeIds = (List<String>) requestParams.get("keywordTypeId"); } String statusId = (String) requestParams.get("statusId"); HttpSession session = request.getSession(); ProductSearchOptions productSearchOptions = getProductSearchOptions(session); String addOnTopProdCategoryId = productSearchOptions.getTopProductCategoryId(); Integer viewIndexInteger = productSearchOptions.getViewIndex(); if (viewIndexInteger != null) { viewIndex = viewIndexInteger.intValue(); } Integer viewSizeInteger = productSearchOptions.getViewSize(); if (viewSizeInteger != null) { viewSize = viewSizeInteger.intValue(); } Integer previousViewSizeInteger = productSearchOptions.getPreviousViewSize(); if (previousViewSizeInteger != null) { previousViewSize = previousViewSizeInteger.intValue(); } String pag = productSearchOptions.getPaging(); if (paging != null) { paging = pag; } lowIndex = viewIndex * viewSize; highIndex = (viewIndex + 1) * viewSize; // ========== Do the actual search List<String> productIds = new LinkedList<String>(); String visitId = VisitHandler.getVisitId(session); List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); String noConditionFind = (String) requestParams.get("noConditionFind"); if (UtilValidate.isEmpty(noConditionFind)) { noConditionFind = EntityUtilProperties.getPropertyValue("widget", "widget.defaultNoConditionFind", delegator); } // if noConditionFind to Y then find without conditions otherwise search according to constraints. if ("Y".equals(noConditionFind) || UtilValidate.isNotEmpty(productSearchConstraintList)) { // if the search options have changed since the last search, put at the beginning of the options history list checkSaveSearchOptionsHistory(session); int addOnTopTotalListSize = 0; int addOnTopListSize = 0; List<GenericValue> addOnTopProductCategoryMembers = new LinkedList<GenericValue>(); if (UtilValidate.isNotEmpty(addOnTopProdCategoryId)) { // always include the members of the addOnTopProdCategoryId Timestamp now = UtilDateTime.nowTimestamp(); List<EntityCondition> addOnTopProdCondList = new LinkedList<EntityCondition>(); addOnTopProdCondList.add(EntityCondition.makeCondition(EntityCondition.makeCondition("thruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition("thruDate", EntityOperator.GREATER_THAN, now))); addOnTopProdCondList.add(EntityCondition.makeCondition("fromDate", EntityOperator.LESS_THAN, now)); addOnTopProdCondList.add(EntityCondition.makeCondition("productCategoryId", EntityOperator.EQUALS, addOnTopProdCategoryId)); EntityListIterator pli = null; try { pli = EntityQuery.use(delegator).select(UtilMisc.toSet("productId", "sequenceNum")) .from("ProductCategoryMember") .where(addOnTopProdCondList) .orderBy("sequenceNum") .cursorScrollInsensitive() .distinct() .maxRows(highIndex) .queryIterator(); addOnTopProductCategoryMembers = pli.getPartialList(lowIndex, viewSize); addOnTopListSize = addOnTopProductCategoryMembers.size(); for (GenericValue alwaysAddProductCategoryMember: addOnTopProductCategoryMembers) { productIds.add(alwaysAddProductCategoryMember.getString("productId")); } addOnTopTotalListSize = pli.getResultsSizeAfterPartialList(); listSize = listSize + addOnTopTotalListSize; } catch (GenericEntityException e) { Debug.logError(e, module); } finally { if (pli != null) { try { pli.close(); } catch (GenericEntityException e) { Debug.logError(e, module); } } } } // setup resultOffset and maxResults, noting that resultOffset is 1 based, not zero based as these numbers int resultOffsetInt = lowIndex - addOnTopTotalListSize + 1; if (resultOffsetInt < 1) { resultOffsetInt = 1; } int maxResultsInt = viewSize - addOnTopListSize; Integer resultOffset = Integer.valueOf(resultOffsetInt); Integer maxResults = Integer.valueOf(maxResultsInt); ResultSortOrder resultSortOrder = ProductSearchOptions.getResultSortOrder(request); ProductSearchContext productSearchContext = new ProductSearchContext(delegator, visitId); if (UtilValidate.isNotEmpty(productSearchConstraintList)) { productSearchContext.addProductSearchConstraints(productSearchConstraintList); } productSearchContext.setResultSortOrder(resultSortOrder); productSearchContext.setResultOffset(resultOffset); productSearchContext.setMaxResults(maxResults); if (UtilValidate.isNotEmpty(keywordTypeIds)) { productSearchContext.keywordTypeIds = keywordTypeIds; } else { productSearchContext.keywordTypeIds = UtilMisc.toList("KWT_KEYWORD"); } if (UtilValidate.isNotEmpty(statusId)) { productSearchContext.statusId = statusId; } List<String> foundProductIds = productSearchContext.doSearch(); if (maxResultsInt > 0) { productIds.addAll(foundProductIds); } Integer totalResults = productSearchContext.getTotalResults(); if (totalResults != null) { listSize = listSize + totalResults.intValue(); } } if (listSize < highIndex) { highIndex = listSize; } // ========== Setup other display info List<String> searchConstraintStrings = searchGetConstraintStrings(false, session, delegator); String searchSortOrderString = searchGetSortOrderString(false, request); // ========== populate the result Map Map<String, Object> result = new HashMap<String, Object>(); result.put("productIds", productIds); result.put("viewIndex", Integer.valueOf(viewIndex)); result.put("viewSize", Integer.valueOf(viewSize)); result.put("listSize", Integer.valueOf(listSize)); result.put("lowIndex", Integer.valueOf(lowIndex)); result.put("highIndex", Integer.valueOf(highIndex)); result.put("paging", paging); result.put("previousViewSize", previousViewSize); result.put("searchConstraintStrings", searchConstraintStrings); result.put("searchSortOrderString", searchSortOrderString); result.put("noConditionFind", noConditionFind); return result; } public static String makeSearchParametersString(HttpSession session) { return makeSearchParametersString(getProductSearchOptions(session)); } public static String makeSearchParametersString(ProductSearchOptions productSearchOptions) { StringBuilder searchParamString = new StringBuilder(); List<ProductSearchConstraint> constraintList = productSearchOptions.getConstraintList(); if (UtilValidate.isEmpty(constraintList)) { constraintList = new ArrayList<ProductSearchConstraint>(); } int categoriesCount = 0; int featuresCount = 0; int featureCategoriesCount = 0; int featureGroupsCount = 0; int keywordsCount = 0; boolean isNotFirst = false; for (ProductSearchConstraint psc: constraintList) { if (psc instanceof ProductSearch.CategoryConstraint) { ProductSearch.CategoryConstraint cc = (ProductSearch.CategoryConstraint) psc; categoriesCount++; if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_CAT"); searchParamString.append(categoriesCount); searchParamString.append("="); searchParamString.append(cc.productCategoryId); searchParamString.append("&S_CSB"); searchParamString.append(categoriesCount); searchParamString.append("="); searchParamString.append(cc.includeSubCategories ? "Y" : "N"); if (cc.exclude != null) { searchParamString.append("&S_CEX"); searchParamString.append(categoriesCount); searchParamString.append("="); searchParamString.append(cc.exclude.booleanValue() ? "Y" : "N"); } } else if (psc instanceof ProductSearch.FeatureConstraint) { ProductSearch.FeatureConstraint fc = (ProductSearch.FeatureConstraint) psc; featuresCount++; if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_PFI"); searchParamString.append(featuresCount); searchParamString.append("="); searchParamString.append(fc.productFeatureId); if (fc.exclude != null) { searchParamString.append("&S_PFX"); searchParamString.append(featuresCount); searchParamString.append("="); searchParamString.append(fc.exclude.booleanValue() ? "Y" : "N"); } } else if (psc instanceof ProductSearch.FeatureCategoryConstraint) { ProductSearch.FeatureCategoryConstraint pfcc = (ProductSearch.FeatureCategoryConstraint) psc; featureCategoriesCount++; if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_FCI"); searchParamString.append(featureCategoriesCount); searchParamString.append("="); searchParamString.append(pfcc.productFeatureCategoryId); if (pfcc.exclude != null) { searchParamString.append("&S_FCX"); searchParamString.append(featureCategoriesCount); searchParamString.append("="); searchParamString.append(pfcc.exclude.booleanValue() ? "Y" : "N"); } } else if (psc instanceof ProductSearch.FeatureGroupConstraint) { ProductSearch.FeatureGroupConstraint pfgc = (ProductSearch.FeatureGroupConstraint) psc; featureGroupsCount++; if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_FGI"); searchParamString.append(featureGroupsCount); searchParamString.append("="); searchParamString.append(pfgc.productFeatureGroupId); if (pfgc.exclude != null) { searchParamString.append("&S_FGX"); searchParamString.append(featureGroupsCount); searchParamString.append("="); searchParamString.append(pfgc.exclude.booleanValue() ? "Y" : "N"); } } else if (psc instanceof ProductSearch.KeywordConstraint) { ProductSearch.KeywordConstraint kc = (ProductSearch.KeywordConstraint) psc; keywordsCount++; if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("SEARCH_STRING"); searchParamString.append(keywordsCount); searchParamString.append("="); searchParamString.append(UtilHttp.encodeBlanks(kc.keywordsString)); searchParamString.append("&SEARCH_OPERATOR"); searchParamString.append(keywordsCount); searchParamString.append("="); searchParamString.append(kc.isAnd ? "AND" : "OR"); searchParamString.append("&SEARCH_ANYPRESUF"); searchParamString.append(keywordsCount); searchParamString.append("="); searchParamString.append(kc.anyPrefix | kc.anySuffix ? "Y" : "N"); } else if (psc instanceof ProductSearch.ListPriceRangeConstraint) { ProductSearch.ListPriceRangeConstraint lprc = (ProductSearch.ListPriceRangeConstraint) psc; if (lprc.lowPrice != null || lprc.highPrice != null) { if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_LPR"); searchParamString.append("="); if (lprc.lowPrice != null) searchParamString.append(lprc.lowPrice); searchParamString.append("_"); if (lprc.highPrice != null) searchParamString.append(lprc.highPrice); } } else if (psc instanceof ProductSearch.SupplierConstraint) { ProductSearch.SupplierConstraint suppc = (ProductSearch.SupplierConstraint) psc; if (suppc.supplierPartyId != null) { if (isNotFirst) { searchParamString.append("&"); } else { isNotFirst = true; } searchParamString.append("S_SUP"); searchParamString.append("="); searchParamString.append(suppc.supplierPartyId); } } } String topProductCategoryId = productSearchOptions.getTopProductCategoryId(); if (topProductCategoryId != null) { searchParamString.append("&S_TPC"); searchParamString.append("="); searchParamString.append(topProductCategoryId); } ResultSortOrder resultSortOrder = productSearchOptions.getResultSortOrder(); if (resultSortOrder != null) { if (resultSortOrder instanceof ProductSearch.SortKeywordRelevancy) { searchParamString.append("&S_O=SKR"); } else if (resultSortOrder instanceof ProductSearch.SortProductField) { ProductSearch.SortProductField spf = (ProductSearch.SortProductField) resultSortOrder; searchParamString.append("&S_O=SPF:"); searchParamString.append(spf.fieldName); } else if (resultSortOrder instanceof ProductSearch.SortProductPrice) { ProductSearch.SortProductPrice spp = (ProductSearch.SortProductPrice) resultSortOrder; searchParamString.append("&S_O=SPP:"); searchParamString.append(spp.productPriceTypeId); } else if (resultSortOrder instanceof ProductSearch.SortProductFeature) { ProductSearch.SortProductFeature spf = (ProductSearch.SortProductFeature) resultSortOrder; searchParamString.append("&S_O=SPFT:"); searchParamString.append(spf.productFeatureTypeId); } searchParamString.append("&S_A="); searchParamString.append(resultSortOrder.isAscending() ? "Y" : "N"); } return searchParamString.toString(); } /** * This method returns a list of productId counts grouped by productFeatureId's of input productFeatureTypeId, * the constraint being applied on current ProductSearchConstraint list in session. * @param productFeatureTypeId The productFeatureTypeId, productFeatureId's of which should be considered. * @param session Current session. * @param delegator The delegator object. * @return List of Maps containing productFeatureId, productFeatureTypeId, description, featureCount. */ public static List<Map<String, String>> listCountByFeatureForType(String productFeatureTypeId, HttpSession session, Delegator delegator) { String visitId = VisitHandler.getVisitId(session); ProductSearchContext productSearchContext = new ProductSearchContext(delegator, visitId); List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); if (UtilValidate.isNotEmpty(productSearchConstraintList)) { productSearchContext.addProductSearchConstraints(productSearchConstraintList); } productSearchContext.finishKeywordConstraints(); productSearchContext.finishCategoryAndFeatureConstraints(); DynamicViewEntity dynamicViewEntity = productSearchContext.dynamicViewEntity; List<EntityCondition> entityConditionList = productSearchContext.entityConditionList; dynamicViewEntity.addMemberEntity("PFAC", "ProductFeatureAppl"); dynamicViewEntity.addAlias("PFAC", "pfacProductFeatureId", "productFeatureId", null, null, Boolean.TRUE, null); dynamicViewEntity.addAlias("PFAC", "pfacFromDate", "fromDate", null, null, null, null); dynamicViewEntity.addAlias("PFAC", "pfacThruDate", "thruDate", null, null, null, null); dynamicViewEntity.addAlias("PFAC", "featureCount", "productId", null, null, null, "count-distinct"); dynamicViewEntity.addViewLink("PROD", "PFAC", Boolean.FALSE, ModelKeyMap.makeKeyMapList("productId")); entityConditionList.add(EntityCondition.makeCondition(EntityCondition.makeCondition("pfacThruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition("pfacThruDate", EntityOperator.GREATER_THAN, UtilDateTime.nowTimestamp()))); entityConditionList.add(EntityCondition.makeCondition("pfacFromDate", EntityOperator.LESS_THAN, UtilDateTime.nowTimestamp())); dynamicViewEntity.addMemberEntity("PFC", "ProductFeature"); dynamicViewEntity.addAlias("PFC", "pfcProductFeatureTypeId", "productFeatureTypeId", null, null, Boolean.TRUE, null); dynamicViewEntity.addAlias("PFC", "pfcDescription", "description", null, null, Boolean.TRUE, null); dynamicViewEntity.addViewLink("PFAC", "PFC", Boolean.FALSE, ModelKeyMap.makeKeyMapList("productFeatureId")); entityConditionList.add(EntityCondition.makeCondition("pfcProductFeatureTypeId", EntityOperator.EQUALS, productFeatureTypeId)); EntityListIterator eli = null; try { eli = EntityQuery.use(delegator) .select(UtilMisc.toSet("pfacProductFeatureId", "featureCount", "pfcDescription", "pfcProductFeatureTypeId")) .from(dynamicViewEntity) .where(entityConditionList) .orderBy(productSearchContext.orderByList) .cursorScrollInsensitive() .queryIterator(); } catch (GenericEntityException e) { Debug.logError(e, "Error in product search", module); return null; } List<Map<String, String>> featureCountList = new LinkedList<Map<String,String>>(); GenericValue searchResult = null; while ((searchResult = eli.next()) != null) { featureCountList.add(UtilMisc.<String, String>toMap("productFeatureId", (String) searchResult.get("pfacProductFeatureId"), "productFeatureTypeId", (String) searchResult.get("pfcProductFeatureTypeId"), "description", (String) searchResult.get("pfcDescription"), "featureCount", Long.toString((Long) searchResult.get("featureCount")))); } if (eli != null) { try { eli.close(); } catch (GenericEntityException e) { Debug.logError(e, "Error closing ProductSearch EntityListIterator"); } } return featureCountList; } public static int getCategoryCostraintIndex(HttpSession session) { int index = 0; List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); for (ProductSearchConstraint constraint: productSearchConstraintList) { if (constraint instanceof CategoryConstraint) { index++; } } return index; } /** * This method returns count of products within a given price range, the constraint being * applied on current ProductSearchConstraint list in session. * @param priceLow The low price. * @param priceHigh The high price. * @param session Current session. * @param delegator The delegator object. * @return The long value of count of products. */ public static long getCountForListPriceRange(BigDecimal priceLow, BigDecimal priceHigh, HttpSession session, Delegator delegator) { String visitId = VisitHandler.getVisitId(session); ProductSearchContext productSearchContext = new ProductSearchContext(delegator, visitId); List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); if (UtilValidate.isNotEmpty(productSearchConstraintList)) { productSearchContext.addProductSearchConstraints(productSearchConstraintList); } productSearchContext.finishKeywordConstraints(); productSearchContext.finishCategoryAndFeatureConstraints(); DynamicViewEntity dynamicViewEntity = productSearchContext.dynamicViewEntity; List<EntityCondition> entityConditionList = productSearchContext.entityConditionList; List<String> fieldsToSelect = new LinkedList<String>(); dynamicViewEntity.addMemberEntity("PPC", "ProductPrice"); dynamicViewEntity.addAlias("PPC", "ppcProductPriceTypeId", "productPriceTypeId", null, null, null, null); dynamicViewEntity.addAlias("PPC", "ppcFromDate", "fromDate", null, null, null, null); dynamicViewEntity.addAlias("PPC", "ppcThruDate", "thruDate", null, null, null, null); dynamicViewEntity.addAlias("PPC", "ppcPrice", "price", null, null, null, null); dynamicViewEntity.addAlias("PPC", "priceRangeCount", "productId", null, null, null, "count-distinct"); dynamicViewEntity.addViewLink("PROD", "PPC", Boolean.FALSE, ModelKeyMap.makeKeyMapList("productId")); fieldsToSelect.add("priceRangeCount"); entityConditionList.add(EntityCondition.makeCondition(EntityCondition.makeCondition("ppcThruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition("ppcThruDate", EntityOperator.GREATER_THAN, UtilDateTime.nowTimestamp()))); entityConditionList.add(EntityCondition.makeCondition("ppcFromDate", EntityOperator.LESS_THAN, UtilDateTime.nowTimestamp())); entityConditionList.add(EntityCondition.makeCondition("ppcPrice", EntityOperator.GREATER_THAN_EQUAL_TO, priceLow)); entityConditionList.add(EntityCondition.makeCondition("ppcPrice", EntityOperator.LESS_THAN_EQUAL_TO, priceHigh)); entityConditionList.add(EntityCondition.makeCondition("ppcProductPriceTypeId", EntityOperator.EQUALS, "LIST_PRICE")); EntityListIterator eli = null; try { eli = EntityQuery.use(delegator).select(UtilMisc.toSet(fieldsToSelect)) .from(dynamicViewEntity) .where(entityConditionList) .orderBy(productSearchContext.orderByList) .cursorScrollInsensitive() .queryIterator(); } catch (GenericEntityException e) { Debug.logError(e, "Error in product search", module); return 0; } GenericValue searchResult = null; Long priceRangeCount = Long.valueOf(0); while ((searchResult = eli.next()) != null) { priceRangeCount = searchResult.getLong("priceRangeCount"); } if (eli != null) { try { eli.close(); } catch (GenericEntityException e) { Debug.logError(e, "Error closing ProductSearch EntityListIterator"); } } return priceRangeCount; } /** * This method returns count of products in a given category (including all sub categories), the constraint being * applied on current ProductSearchConstraint list in session. * @param productCategoryId productCategoryId for which the count should be returned. * @param session Current session. * @param delegator The delegator object. * @return The long value of count of products. */ public static long getCountForProductCategory(String productCategoryId, HttpSession session, Delegator delegator) { String visitId = VisitHandler.getVisitId(session); ProductSearchContext productSearchContext = new ProductSearchContext(delegator, visitId); List<ProductSearchConstraint> productSearchConstraintList = ProductSearchOptions.getConstraintList(session); if (UtilValidate.isNotEmpty(productSearchConstraintList)) { productSearchContext.addProductSearchConstraints(productSearchConstraintList); } productSearchContext.finishKeywordConstraints(); productSearchContext.finishCategoryAndFeatureConstraints(); DynamicViewEntity dynamicViewEntity = productSearchContext.dynamicViewEntity; List<EntityCondition> entityConditionList = productSearchContext.entityConditionList; List<String> fieldsToSelect = new LinkedList<String>(); dynamicViewEntity.addMemberEntity("PCMC", "ProductCategoryMember"); dynamicViewEntity.addAlias("PCMC", "pcmcProductCategoryId", "productCategoryId", null, null, null, null); dynamicViewEntity.addAlias("PCMC", "pcmcFromDate", "fromDate", null, null, null, null); dynamicViewEntity.addAlias("PCMC", "pcmcThruDate", "thruDate", null, null, null, null); dynamicViewEntity.addAlias("PCMC", "categoryCount", "productId", null, null, null, "count-distinct"); dynamicViewEntity.addViewLink("PROD", "PCMC", Boolean.FALSE, ModelKeyMap.makeKeyMapList("productId")); fieldsToSelect.add("categoryCount"); entityConditionList.add(EntityCondition.makeCondition(EntityCondition.makeCondition("pcmcThruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition("pcmcThruDate", EntityOperator.GREATER_THAN, productSearchContext.nowTimestamp))); entityConditionList.add(EntityCondition.makeCondition("pcmcFromDate", EntityOperator.LESS_THAN, productSearchContext.nowTimestamp)); Set<String> productCategoryIdSet = new HashSet<String>(); ProductSearch.getAllSubCategoryIds(productCategoryId, productCategoryIdSet, delegator, productSearchContext.nowTimestamp); entityConditionList.add(EntityCondition.makeCondition("pcmcProductCategoryId", EntityOperator.IN, productCategoryIdSet)); EntityListIterator eli = null; try { eli = EntityQuery.use(delegator).select(UtilMisc.toSet(fieldsToSelect)) .from(dynamicViewEntity) .where(entityConditionList) .orderBy(productSearchContext.orderByList) .cursorScrollInsensitive() .queryIterator(); } catch (GenericEntityException e) { Debug.logError(e, "Error in product search", module); return 0; } GenericValue searchResult = null; Long categoryCount = Long.valueOf(0); while ((searchResult = eli.next()) != null) { categoryCount = searchResult.getLong("categoryCount"); } if (eli != null) { try { eli.close(); } catch (GenericEntityException e) { Debug.logError(e, "Error closing ProductSearch EntityListIterator"); } } return categoryCount; } }