| /******************************************************************************* |
| * 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.category.ftl; |
| |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Collection; |
| import java.util.Hashtable; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.RequestDispatcher; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.oro.text.regex.MalformedPatternException; |
| import org.apache.oro.text.regex.Pattern; |
| import org.apache.oro.text.regex.Perl5Compiler; |
| import org.apache.oro.text.regex.Perl5Matcher; |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.StringUtil; |
| import org.apache.ofbiz.base.util.StringUtil.StringWrapper; |
| import org.apache.ofbiz.base.util.UtilMisc; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.common.UrlServletHelper; |
| 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.EntityExpr; |
| import org.apache.ofbiz.entity.condition.EntityOperator; |
| import org.apache.ofbiz.product.category.CatalogUrlServlet; |
| import org.apache.ofbiz.product.category.CategoryContentWrapper; |
| import org.apache.ofbiz.product.category.CategoryWorker; |
| import org.apache.ofbiz.product.category.SeoConfigUtil; |
| import org.apache.ofbiz.product.category.SeoUrlUtil; |
| import org.apache.ofbiz.product.product.ProductContentWrapper; |
| |
| import freemarker.core.Environment; |
| import freemarker.ext.beans.BeanModel; |
| import freemarker.ext.beans.StringModel; |
| import freemarker.template.SimpleScalar; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.TemplateTransformModel; |
| |
| public class CatalogUrlSeoTransform implements TemplateTransformModel { |
| public final static String module = CatalogUrlSeoTransform.class.getName(); |
| |
| private static Map<String, String> categoryNameIdMap = null; |
| private static Map<String, String> categoryIdNameMap = null; |
| private static boolean categoryMapInitialed = false; |
| private static final String asciiRegexp = "^[0-9-_a-zA-Z]*$"; |
| private static Pattern asciiPattern = null; |
| public static final String URL_HYPHEN = "-"; |
| |
| static { |
| if (!SeoConfigUtil.isInitialed()) { |
| SeoConfigUtil.init(); |
| } |
| try { |
| Perl5Compiler perlCompiler = new Perl5Compiler(); |
| asciiPattern = perlCompiler.compile(asciiRegexp, Perl5Compiler.READ_ONLY_MASK); |
| } catch (MalformedPatternException e1) { |
| Debug.logWarning(e1, module); |
| } |
| } |
| |
| public String getStringArg(Map args, String key) { |
| Object o = args.get(key); |
| if (o instanceof SimpleScalar) { |
| return ((SimpleScalar) o).getAsString(); |
| } else if (o instanceof StringModel) { |
| return ((StringModel) o).getAsString(); |
| } |
| return null; |
| } |
| |
| @Override |
| public Writer getWriter(final Writer out, final Map args) |
| throws TemplateModelException, IOException { |
| final StringBuilder buf = new StringBuilder(); |
| |
| return new Writer(out) { |
| |
| @Override |
| public void write(char[] cbuf, int off, int len) throws IOException { |
| buf.append(cbuf, off, len); |
| } |
| |
| @Override |
| public void flush() throws IOException { |
| out.flush(); |
| } |
| |
| @Override |
| public void close() throws IOException { |
| try { |
| Environment env = Environment.getCurrentEnvironment(); |
| BeanModel req = (BeanModel) env.getVariable("request"); |
| if (req != null) { |
| String productId = getStringArg(args, "productId"); |
| String currentCategoryId = getStringArg(args, "currentCategoryId"); |
| String previousCategoryId = getStringArg(args, "previousCategoryId"); |
| HttpServletRequest request = (HttpServletRequest) req.getWrappedObject(); |
| |
| if (!isCategoryMapInitialed()) { |
| initCategoryMap(request); |
| } |
| |
| String catalogUrl = ""; |
| if (SeoConfigUtil.isCategoryUrlEnabled(request.getContextPath())) { |
| if (UtilValidate.isEmpty(productId)) { |
| catalogUrl = makeCategoryUrl(request, currentCategoryId, previousCategoryId, null, null, null, null); |
| } else { |
| catalogUrl = makeProductUrl(request, productId, currentCategoryId, previousCategoryId); |
| } |
| } else { |
| catalogUrl = CatalogUrlServlet.makeCatalogUrl(request, productId, currentCategoryId, previousCategoryId); |
| } |
| out.write(catalogUrl); |
| } |
| } catch (TemplateModelException e) { |
| throw new IOException(e.getMessage()); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Check whether the category map is initialed. |
| * |
| * @return a boolean value to indicate whether the category map has been initialized. |
| */ |
| public static boolean isCategoryMapInitialed() { |
| return categoryMapInitialed; |
| } |
| |
| /** |
| * Get the category name/id map. |
| * |
| * @return the category name/id map |
| */ |
| public static Map<String, String> getCategoryNameIdMap() { |
| return categoryNameIdMap; |
| } |
| |
| /** |
| * Get the category id/name map. |
| * |
| * @return the category id/name map |
| */ |
| public static Map<String, String> getCategoryIdNameMap() { |
| return categoryIdNameMap; |
| } |
| |
| /** |
| * Initial category-name/category-id map. |
| * Note: as a key, the category-name should be: |
| * 1. ascii |
| * 2. lower cased and use hyphen between the words. |
| * If not, the category id will be used. |
| * |
| */ |
| public static synchronized void initCategoryMap(HttpServletRequest request) { |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| initCategoryMap(request, delegator); |
| } |
| |
| public static synchronized void initCategoryMap(HttpServletRequest request, Delegator delegator) { |
| if (SeoConfigUtil.checkCategoryUrl()) { |
| categoryNameIdMap = new Hashtable<String, String>(); |
| categoryIdNameMap = new Hashtable<String, String>(); |
| Perl5Matcher matcher = new Perl5Matcher(); |
| |
| try { |
| Collection<GenericValue> allCategories = delegator.findList("ProductCategory", null, UtilMisc.toSet("productCategoryId", "categoryName"), null, null, false); |
| for (GenericValue category : allCategories) { |
| String categoryName = category.getString("categoryName"); |
| String categoryNameId = null; |
| String categoryIdName = null; |
| String categoryId = category.getString("productCategoryId"); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| categoryName = SeoUrlUtil.replaceSpecialCharsUrl(categoryName.trim()); |
| if (matcher.matches(categoryName, asciiPattern)) { |
| categoryIdName = categoryName.replaceAll(" ", URL_HYPHEN); |
| categoryNameId = categoryIdName + URL_HYPHEN + categoryId.trim().replaceAll(" ", URL_HYPHEN); |
| } else { |
| categoryIdName = categoryId.trim().replaceAll(" ", URL_HYPHEN); |
| categoryNameId = categoryIdName; |
| } |
| } else { |
| GenericValue productCategory = delegator.findOne("ProductCategory", UtilMisc.toMap("productCategoryId", categoryId), true); |
| CategoryContentWrapper wrapper = new CategoryContentWrapper(productCategory, request); |
| StringWrapper alternativeUrl = wrapper.get("ALTERNATIVE_URL", "url"); |
| if (UtilValidate.isNotEmpty(alternativeUrl) && UtilValidate.isNotEmpty(alternativeUrl.toString())) { |
| categoryIdName = SeoUrlUtil.replaceSpecialCharsUrl(alternativeUrl.toString()); |
| categoryNameId = categoryIdName + URL_HYPHEN + categoryId.trim().replaceAll(" ", URL_HYPHEN); |
| } else { |
| categoryNameId = categoryId.trim().replaceAll(" ", URL_HYPHEN); |
| categoryIdName = categoryNameId; |
| } |
| } |
| if (categoryNameIdMap.containsKey(categoryNameId)) { |
| categoryNameId = categoryId.trim().replaceAll(" ", URL_HYPHEN); |
| categoryIdName = categoryNameId; |
| } |
| if (!matcher.matches(categoryNameId, asciiPattern) || categoryNameIdMap.containsKey(categoryNameId)) { |
| continue; |
| } |
| categoryNameIdMap.put(categoryNameId, categoryId); |
| categoryIdNameMap.put(categoryId, categoryIdName); |
| } |
| } catch (GenericEntityException e) { |
| Debug.logError(e, module); |
| } |
| } |
| categoryMapInitialed = true; |
| } |
| |
| /** |
| * Make product url according to the configurations. |
| * |
| * @return String a catalog url |
| */ |
| public static String makeProductUrl(HttpServletRequest request, String productId, String currentCategoryId, String previousCategoryId) { |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| if (!isCategoryMapInitialed()) { |
| initCategoryMap(request); |
| } |
| |
| String contextPath = request.getContextPath(); |
| StringBuilder urlBuilder = new StringBuilder(); |
| GenericValue product = null; |
| urlBuilder.append((request.getSession().getServletContext()).getContextPath()); |
| if (urlBuilder.length() == 0 || urlBuilder.charAt(urlBuilder.length() - 1) != '/') { |
| urlBuilder.append("/"); |
| } |
| if (UtilValidate.isNotEmpty(productId)) { |
| try { |
| product = delegator.findOne("Product", UtilMisc.toMap("productId", productId), true); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Error looking up product info for productId [" + productId + "]: " + e.toString(), module); |
| } |
| } |
| if (product != null) { |
| urlBuilder.append(CatalogUrlServlet.PRODUCT_REQUEST + "/"); |
| } |
| |
| if (UtilValidate.isNotEmpty(currentCategoryId)) { |
| List<String> trail = CategoryWorker.getTrail(request); |
| trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId); |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| for (String trailCategoryId: trail) { |
| if ("TOP".equals(trailCategoryId)) continue; |
| urlBuilder.append("/"); |
| urlBuilder.append(trailCategoryId); |
| } |
| } else { |
| if (trail.size() > 1) { |
| String lastCategoryId = trail.get(trail.size() - 1); |
| if (!"TOP".equals(lastCategoryId)) { |
| if (SeoConfigUtil.isCategoryNameEnabled()) { |
| String categoryName = CatalogUrlSeoTransform.getCategoryIdNameMap().get(lastCategoryId); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| urlBuilder.append(categoryName); |
| if (product != null) { |
| urlBuilder.append(URL_HYPHEN); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (UtilValidate.isNotEmpty(productId)) { |
| if (product != null) { |
| String productName = product.getString("productName"); |
| productName = SeoUrlUtil.replaceSpecialCharsUrl(productName); |
| if (UtilValidate.isNotEmpty(productName)) { |
| urlBuilder.append(productName + URL_HYPHEN); |
| } else { |
| ProductContentWrapper wrapper = new ProductContentWrapper(product, request); |
| StringWrapper alternativeUrl = wrapper.get("ALTERNATIVE_URL", "url"); |
| if (UtilValidate.isNotEmpty(alternativeUrl) && UtilValidate.isNotEmpty(alternativeUrl.toString())) { |
| productName = SeoUrlUtil.replaceSpecialCharsUrl(alternativeUrl.toString()); |
| if (UtilValidate.isNotEmpty(productName)) { |
| urlBuilder.append(productName + URL_HYPHEN); |
| } |
| } |
| } |
| } |
| try { |
| urlBuilder.append(productId); |
| } catch (Exception e) { |
| urlBuilder.append(productId); |
| } |
| } |
| |
| if (!urlBuilder.toString().endsWith("/") && UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| urlBuilder.append(SeoConfigUtil.getCategoryUrlSuffix()); |
| } |
| |
| return urlBuilder.toString(); |
| } |
| |
| /** |
| * Make category url according to the configurations. |
| * |
| * @return String a category url |
| */ |
| public static String makeCategoryUrl(HttpServletRequest request, String currentCategoryId, String previousCategoryId, String viewSize, String viewIndex, String viewSort, String searchString) { |
| |
| if (!isCategoryMapInitialed()) { |
| initCategoryMap(request); |
| } |
| |
| StringBuilder urlBuilder = new StringBuilder(); |
| urlBuilder.append((request.getSession().getServletContext()).getContextPath()); |
| if (urlBuilder.length() == 0 || urlBuilder.charAt(urlBuilder.length() - 1) != '/') { |
| urlBuilder.append("/"); |
| } |
| urlBuilder.append(CatalogUrlServlet.CATEGORY_REQUEST + "/"); |
| |
| if (UtilValidate.isNotEmpty(currentCategoryId)) { |
| List<String> trail = CategoryWorker.getTrail(request); |
| trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId); |
| if (trail.size() > 1) { |
| String lastCategoryId = trail.get(trail.size() - 1); |
| if (!"TOP".equals(lastCategoryId)) { |
| String categoryName = CatalogUrlSeoTransform.getCategoryIdNameMap().get(lastCategoryId); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| urlBuilder.append(categoryName); |
| urlBuilder.append(URL_HYPHEN); |
| urlBuilder.append(lastCategoryId.trim().replaceAll(" ", URL_HYPHEN)); |
| } else { |
| urlBuilder.append(lastCategoryId.trim().replaceAll(" ", URL_HYPHEN)); |
| } |
| } |
| } |
| } |
| |
| if (!urlBuilder.toString().endsWith("/") && UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| urlBuilder.append(SeoConfigUtil.getCategoryUrlSuffix()); |
| } |
| |
| // append view index |
| if (UtilValidate.isNotEmpty(viewIndex)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewIndex=" + viewIndex + "&"); |
| } |
| // append view size |
| if (UtilValidate.isNotEmpty(viewSize)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewSize=" + viewSize + "&"); |
| } |
| // append view sort |
| if (UtilValidate.isNotEmpty(viewSort)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewSort=" + viewSort + "&"); |
| } |
| // append search string |
| if (UtilValidate.isNotEmpty(searchString)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("searchString=" + searchString + "&"); |
| } |
| if (urlBuilder.toString().endsWith("&")) { |
| return urlBuilder.toString().substring(0, urlBuilder.toString().length()-1); |
| } |
| |
| return urlBuilder.toString(); |
| } |
| |
| /** |
| * Make product url according to the configurations. |
| * |
| * @return String a catalog url |
| */ |
| public static String makeProductUrl(String contextPath, List<String> trail, String productId, String productName, String currentCategoryId, String previousCategoryId) { |
| StringBuilder urlBuilder = new StringBuilder(); |
| urlBuilder.append(contextPath); |
| if (urlBuilder.charAt(urlBuilder.length() - 1) != '/') { |
| urlBuilder.append("/"); |
| } |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| urlBuilder.append(CatalogUrlServlet.CATALOG_URL_MOUNT_POINT); |
| } else { |
| urlBuilder.append(CatalogUrlServlet.PRODUCT_REQUEST + "/"); |
| } |
| |
| if (UtilValidate.isNotEmpty(currentCategoryId)) { |
| trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId); |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| for (String trailCategoryId: trail) { |
| if ("TOP".equals(trailCategoryId)) continue; |
| urlBuilder.append("/"); |
| urlBuilder.append(trailCategoryId); |
| } |
| } else { |
| if (trail.size() > 1) { |
| String lastCategoryId = trail.get(trail.size() - 1); |
| if (!"TOP".equals(lastCategoryId)) { |
| if (SeoConfigUtil.isCategoryNameEnabled()) { |
| String categoryName = CatalogUrlSeoTransform.getCategoryIdNameMap().get(lastCategoryId); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| urlBuilder.append(categoryName + URL_HYPHEN); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (UtilValidate.isNotEmpty(productId)) { |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| urlBuilder.append("/p_"); |
| } else { |
| productName = SeoUrlUtil.replaceSpecialCharsUrl(productName); |
| if (UtilValidate.isNotEmpty(productName)) { |
| urlBuilder.append(productName + URL_HYPHEN); |
| } |
| } |
| urlBuilder.append(productId); |
| } |
| |
| if (!urlBuilder.toString().endsWith("/") && UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| urlBuilder.append(SeoConfigUtil.getCategoryUrlSuffix()); |
| } |
| |
| return urlBuilder.toString(); |
| } |
| |
| /** |
| * Get a string lower cased and hyphen connected. |
| * |
| * @param name a String to be transformed |
| * @return String nice name |
| */ |
| protected static String getNiceName(String name) { |
| Perl5Matcher matcher = new Perl5Matcher(); |
| String niceName = null; |
| if (UtilValidate.isNotEmpty(name)) { |
| name = name.trim().replaceAll(" ", URL_HYPHEN); |
| if (UtilValidate.isNotEmpty(name) && matcher.matches(name, asciiPattern)) { |
| niceName = name; |
| } |
| } |
| return niceName; |
| } |
| |
| public static boolean forwardProductUri(HttpServletRequest request, HttpServletResponse response, Delegator delegator) throws ServletException, IOException { |
| return forwardProductUri(request, response, delegator, null); |
| } |
| |
| public static boolean forwardProductUri(HttpServletRequest request, HttpServletResponse response, Delegator delegator, String controlServlet) throws ServletException, IOException { |
| return forwardUri(request, response, delegator, controlServlet); |
| } |
| |
| /** |
| * Forward a uri according to forward pattern regular expressions. |
| * |
| * @param uri |
| * String to reverse transform |
| * @return boolean to indicate whether the uri is forwarded. |
| * @throws IOException |
| * @throws ServletException |
| */ |
| public static boolean forwardUri(HttpServletRequest request, HttpServletResponse response, Delegator delegator, String controlServlet) throws ServletException, IOException { |
| String pathInfo = request.getRequestURI(); |
| String contextPath = request.getContextPath(); |
| if (!isCategoryMapInitialed()) { |
| initCategoryMap(request, delegator); |
| } |
| |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| return false; |
| } |
| List<String> pathElements = StringUtil.split(pathInfo, "/"); |
| if (UtilValidate.isEmpty(pathElements)) { |
| return false; |
| } |
| // remove context path |
| pathInfo = SeoUrlUtil.removeContextPath(pathInfo, contextPath); |
| // remove servlet path |
| pathInfo = SeoUrlUtil.removeContextPath(pathInfo, request.getServletPath()); |
| if (pathInfo.startsWith("/" + CatalogUrlServlet.CATEGORY_REQUEST + "/")) { |
| return forwardCategoryUri(request, response, delegator, controlServlet); |
| } |
| |
| String lastPathElement = pathElements.get(pathElements.size() - 1); |
| String categoryId = null; |
| String productId = null; |
| if (UtilValidate.isNotEmpty(lastPathElement)) { |
| if (UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| if (lastPathElement.endsWith(SeoConfigUtil.getCategoryUrlSuffix())) { |
| lastPathElement = lastPathElement.substring(0, lastPathElement.length() - SeoConfigUtil.getCategoryUrlSuffix().length()); |
| } else { |
| return false; |
| } |
| } |
| if (SeoConfigUtil.isCategoryNameEnabled() || pathInfo.startsWith("/" + CatalogUrlServlet.CATEGORY_REQUEST + "/")) { |
| for (String categoryName : categoryNameIdMap.keySet()) { |
| if (lastPathElement.startsWith(categoryName)) { |
| categoryId = categoryNameIdMap.get(categoryName); |
| if (!lastPathElement.equals(categoryName)) { |
| lastPathElement = lastPathElement.substring(categoryName.length() + URL_HYPHEN.length()); |
| } |
| break; |
| } |
| } |
| if (UtilValidate.isEmpty(categoryId)) { |
| categoryId = lastPathElement; |
| } |
| } |
| |
| if (UtilValidate.isNotEmpty(lastPathElement)) { |
| List<String> urlElements = StringUtil.split(lastPathElement, URL_HYPHEN); |
| if (UtilValidate.isEmpty(urlElements)) { |
| try { |
| if (delegator.findOne("Product", UtilMisc.toMap("productId", lastPathElement), true) != null) { |
| productId = lastPathElement; |
| } |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Error looking up product info for ProductUrl with path info [" + pathInfo + "]: " + e.toString(), module); |
| } |
| } else { |
| int i = urlElements.size() - 1; |
| String tempProductId = urlElements.get(i); |
| while (i >= 0) { |
| try { |
| List<EntityExpr> exprs = new LinkedList<EntityExpr>(); |
| exprs.add(EntityCondition.makeCondition("productId", EntityOperator.EQUALS, lastPathElement)); |
| exprs.add(EntityCondition.makeCondition("productId", EntityOperator.EQUALS, tempProductId)); |
| List<GenericValue> products = delegator.findList("Product", EntityCondition.makeCondition(exprs, EntityOperator.OR), UtilMisc.toSet("productId", "productName"), null, null, true); |
| |
| if (products != null && products.size() > 0) { |
| if (products.size() == 1) { |
| productId = products.get(0).getString("productId"); |
| break; |
| } else { |
| productId = tempProductId; |
| break; |
| } |
| } else if (i > 0) { |
| tempProductId = urlElements.get(i - 1) + URL_HYPHEN + tempProductId; |
| } |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Error looking up product info for ProductUrl with path info [" + pathInfo + "]: " + e.toString(), module); |
| } |
| i--; |
| } |
| } |
| } |
| } |
| |
| if (UtilValidate.isNotEmpty(productId) || UtilValidate.isNotEmpty(categoryId)) { |
| if (categoryId != null) { |
| request.setAttribute("productCategoryId", categoryId); |
| } |
| |
| if (productId != null) { |
| request.setAttribute("product_id", productId); |
| request.setAttribute("productId", productId); |
| } |
| |
| StringBuilder urlBuilder = new StringBuilder(); |
| if (UtilValidate.isNotEmpty(controlServlet)) { |
| urlBuilder.append("/" + controlServlet); |
| } |
| urlBuilder.append("/" + (productId != null ? CatalogUrlServlet.PRODUCT_REQUEST : CatalogUrlServlet.CATEGORY_REQUEST)); |
| UrlServletHelper.setViewQueryParameters(request, urlBuilder); |
| Debug.logInfo("[Filtered request]: " + pathInfo + " (" + urlBuilder + ")", module); |
| RequestDispatcher rd = request.getRequestDispatcher(urlBuilder.toString()); |
| rd.forward(request, response); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Forward a category uri according to forward pattern regular expressions. |
| * |
| * @param uri |
| * String to reverse transform |
| * @return String |
| * @throws IOException |
| * @throws ServletException |
| */ |
| public static boolean forwardCategoryUri(HttpServletRequest request, HttpServletResponse response, Delegator delegator, String controlServlet) throws ServletException, IOException { |
| String pathInfo = request.getRequestURI(); |
| String contextPath = request.getContextPath(); |
| if (!isCategoryMapInitialed()) { |
| initCategoryMap(request); |
| } |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| return false; |
| } |
| List<String> pathElements = StringUtil.split(pathInfo, "/"); |
| if (UtilValidate.isEmpty(pathElements)) { |
| return false; |
| } |
| String lastPathElement = pathElements.get(pathElements.size() - 1); |
| String categoryId = null; |
| if (UtilValidate.isNotEmpty(lastPathElement)) { |
| if (UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| if (lastPathElement.endsWith(SeoConfigUtil.getCategoryUrlSuffix())) { |
| lastPathElement = lastPathElement.substring(0, lastPathElement.length() - SeoConfigUtil.getCategoryUrlSuffix().length()); |
| } else { |
| return false; |
| } |
| } |
| for (String categoryName : categoryNameIdMap.keySet()) { |
| if (lastPathElement.startsWith(categoryName)) { |
| categoryId = categoryNameIdMap.get(categoryName); |
| break; |
| } |
| } |
| if (UtilValidate.isEmpty(categoryId)) { |
| categoryId = lastPathElement.trim(); |
| } |
| } |
| if (UtilValidate.isNotEmpty(categoryId)) { |
| request.setAttribute("productCategoryId", categoryId); |
| StringBuilder urlBuilder = new StringBuilder(); |
| if (UtilValidate.isNotEmpty(controlServlet)) { |
| urlBuilder.append("/" + controlServlet); |
| } |
| urlBuilder.append("/" + CatalogUrlServlet.CATEGORY_REQUEST); |
| UrlServletHelper.setViewQueryParameters(request, urlBuilder); |
| Debug.logInfo("[Filtered request]: " + pathInfo + " (" + urlBuilder + ")", module); |
| RequestDispatcher rd = request.getRequestDispatcher(urlBuilder.toString()); |
| rd.forward(request, response); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * This is used when building product url in services. |
| * |
| * @param delegator |
| * @param wrapper |
| * @param prefix |
| * @param contextPath |
| * @param productCategoryId |
| * @param previousCategoryId |
| * @param productId |
| * @return |
| */ |
| public static String makeProductUrl(Delegator delegator, ProductContentWrapper wrapper, String prefix, String contextPath, String currentCategoryId, String previousCategoryId, |
| String productId) { |
| StringBuilder urlBuilder = new StringBuilder(); |
| GenericValue product = null; |
| urlBuilder.append(prefix); |
| if (urlBuilder.charAt(urlBuilder.length() - 1) != '/') { |
| urlBuilder.append("/"); |
| } |
| if (UtilValidate.isNotEmpty(productId)) { |
| try { |
| product = delegator.findOne("Product", UtilMisc.toMap("productId", productId), true); |
| } catch (GenericEntityException e) { |
| Debug.logError(e, "Error looking up product info for productId [" + productId + "]: " + e.toString(), module); |
| } |
| } |
| if (product != null) { |
| urlBuilder.append(CatalogUrlServlet.PRODUCT_REQUEST + "/"); |
| } |
| |
| if (UtilValidate.isNotEmpty(currentCategoryId)) { |
| List<String> trail = null; |
| trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId); |
| if (!SeoConfigUtil.isCategoryUrlEnabled(contextPath)) { |
| for (String trailCategoryId: trail) { |
| if ("TOP".equals(trailCategoryId)) continue; |
| urlBuilder.append("/"); |
| urlBuilder.append(trailCategoryId); |
| } |
| } else { |
| if (trail != null && trail.size() > 1) { |
| String lastCategoryId = trail.get(trail.size() - 1); |
| if (!"TOP".equals(lastCategoryId)) { |
| if (SeoConfigUtil.isCategoryNameEnabled()) { |
| String categoryName = CatalogUrlSeoTransform.getCategoryIdNameMap().get(lastCategoryId); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| urlBuilder.append(categoryName); |
| if (product != null) { |
| urlBuilder.append(URL_HYPHEN); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (UtilValidate.isNotEmpty(productId)) { |
| if (product != null) { |
| String productName = product.getString("productName"); |
| productName = SeoUrlUtil.replaceSpecialCharsUrl(productName); |
| if (UtilValidate.isNotEmpty(productName)) { |
| urlBuilder.append(productName + URL_HYPHEN); |
| } else { |
| StringWrapper alternativeUrl = wrapper.get("ALTERNATIVE_URL", "url"); |
| if (UtilValidate.isNotEmpty(alternativeUrl) && UtilValidate.isNotEmpty(alternativeUrl.toString())) { |
| productName = SeoUrlUtil.replaceSpecialCharsUrl(alternativeUrl.toString()); |
| if (UtilValidate.isNotEmpty(productName)) { |
| urlBuilder.append(productName + URL_HYPHEN); |
| } |
| } |
| } |
| } |
| try { |
| urlBuilder.append(productId); |
| } catch (Exception e) { |
| urlBuilder.append(productId); |
| } |
| } |
| |
| if (!urlBuilder.toString().endsWith("/") && UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| urlBuilder.append(SeoConfigUtil.getCategoryUrlSuffix()); |
| } |
| |
| return urlBuilder.toString(); |
| } |
| |
| /** |
| * This is used when building category url in services. |
| * |
| * @param delegator |
| * @param wrapper |
| * @param prefix |
| * @param productCategoryId |
| * @param previousCategoryId |
| * @param productId |
| * @param viewSize |
| * @param viewIndex |
| * @param viewSort |
| * @param searchString |
| * @return |
| */ |
| public static String makeCategoryUrl(Delegator delegator, CategoryContentWrapper wrapper, String prefix, |
| String currentCategoryId, String previousCategoryId, String productId, String viewSize, String viewIndex, |
| String viewSort, String searchString) { |
| StringBuilder urlBuilder = new StringBuilder(); |
| urlBuilder.append(prefix); |
| if (urlBuilder.charAt(urlBuilder.length() - 1) != '/') { |
| urlBuilder.append("/"); |
| } |
| urlBuilder.append(CatalogUrlServlet.CATEGORY_REQUEST + "/"); |
| |
| if (UtilValidate.isNotEmpty(currentCategoryId)) { |
| List<String> trail = null; |
| trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId); |
| if (trail != null && trail.size() > 1) { |
| String lastCategoryId = trail.get(trail.size() - 1); |
| if (!"TOP".equals(lastCategoryId)) { |
| String categoryName = CatalogUrlSeoTransform.getCategoryIdNameMap().get(lastCategoryId); |
| if (UtilValidate.isNotEmpty(categoryName)) { |
| urlBuilder.append(categoryName); |
| urlBuilder.append(URL_HYPHEN); |
| urlBuilder.append(lastCategoryId.trim().replaceAll(" ", URL_HYPHEN)); |
| } else { |
| urlBuilder.append(lastCategoryId.trim().replaceAll(" ", URL_HYPHEN)); |
| } |
| } |
| } |
| } |
| |
| if (!urlBuilder.toString().endsWith("/") && UtilValidate.isNotEmpty(SeoConfigUtil.getCategoryUrlSuffix())) { |
| urlBuilder.append(SeoConfigUtil.getCategoryUrlSuffix()); |
| } |
| |
| // append view index |
| if (UtilValidate.isNotEmpty(viewIndex)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewIndex=" + viewIndex + "&"); |
| } |
| // append view size |
| if (UtilValidate.isNotEmpty(viewSize)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewSize=" + viewSize + "&"); |
| } |
| // append view sort |
| if (UtilValidate.isNotEmpty(viewSort)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("viewSort=" + viewSort + "&"); |
| } |
| // append search string |
| if (UtilValidate.isNotEmpty(searchString)) { |
| if (!urlBuilder.toString().endsWith("?") && !urlBuilder.toString().endsWith("&")) { |
| urlBuilder.append("?"); |
| } |
| urlBuilder.append("searchString=" + searchString + "&"); |
| } |
| if (urlBuilder.toString().endsWith("&")) { |
| return urlBuilder.toString().substring(0, urlBuilder.toString().length()-1); |
| } |
| |
| return urlBuilder.toString(); |
| } |
| } |