You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Jacques Le Roux <ja...@les7arts.com> on 2009/02/13 12:07:32 UTC

Re: svn commit: r743985 - in /ofbiz/trunk/applications: ecommerce/webapp/ecommerce/WEB-INF/ ecommerce/webapp/ecommerce/catalog/ order/webapp/ordermgr/entry/catalog/ product/src/org/ofbiz/product/category/

I like it (and above all, search engines will), thanks David

Jacques

From: <jo...@apache.org>
> Author: jonesde
> Date: Fri Feb 13 04:57:11 2009
> New Revision: 743985
>
> URL: http://svn.apache.org/viewvc?rev=743985&view=rev
> Log:
> Implemented servlet to handle custom catalog URLs, ie for categories and products; there is a servlet to process the URLs and a 
> method to generate them; added a couple of examples to use the static method to generate the URLs, used in sidedeepcategory and in 
> productsummary which are the major places, and can be moved to use in more places over time; these URLs should be far more search 
> engine and user friendly
>
> Added:
>    ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java   (with props)
> Modified:
>    ofbiz/trunk/applications/ecommerce/webapp/ecommerce/WEB-INF/web.xml
>    ofbiz/trunk/applications/ecommerce/webapp/ecommerce/catalog/sidedeepcategory.ftl
>    ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/productsummary.ftl
>    ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CategoryWorker.java
>
> Modified: ofbiz/trunk/applications/ecommerce/webapp/ecommerce/WEB-INF/web.xml
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/ecommerce/webapp/ecommerce/WEB-INF/web.xml?rev=743985&r1=743984&r2=743985&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/ecommerce/webapp/ecommerce/WEB-INF/web.xml (original)
> +++ ofbiz/trunk/applications/ecommerce/webapp/ecommerce/WEB-INF/web.xml Fri Feb 13 04:57:11 2009
> @@ -60,7 +60,7 @@
>         </init-param>
>         <init-param>
>             <param-name>allowedPaths</param-name>
> -            <param-value>/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images</param-value>
> +            <param-value>/control:/catalog:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images</param-value>
>         </init-param>
>         <init-param>
>             <param-name>errorCode</param-name>
> @@ -91,7 +91,7 @@
>         <description>Main Control Servlet</description>
>         <servlet-class>org.ofbiz.webapp.control.ControlServlet</servlet-class>
>         <load-on-startup>1</load-on-startup>
> -    </servlet>
> +    </servlet>
>     <!-- un-comment for Worldpay
>     <servlet>
>         <servlet-name>select</servlet-name>
> @@ -101,18 +101,29 @@
>         <load-on-startup>5</load-on-startup>
>     </servlet>
>     -->
> +    <servlet>
> +        <servlet-name>CatalogUrlServlet</servlet-name>
> +        <display-name>CatalogUrlServlet</display-name>
> +        <description>Catalog (Category/Product) URL Servlet</description>
> +        <servlet-class>org.ofbiz.product.category.CatalogUrlServlet</servlet-class>
> +        <load-on-startup>1</load-on-startup>
> +    </servlet>
>
>     <servlet-mapping>
>         <servlet-name>ControlServlet</servlet-name>
>         <url-pattern>/control/*</url-pattern>
> -    </servlet-mapping>
> +    </servlet-mapping>
>     <!-- un-comment for Worldpay
>     <servlet-mapping>
>         <servlet-name>select</servlet-name>
>         <url-pattern>/select/*</url-pattern>
>     </servlet-mapping>
>     -->
> -
> +    <servlet-mapping>
> +        <servlet-name>CatalogUrlServlet</servlet-name>
> +        <url-pattern>/catalog/*</url-pattern>
> +    </servlet-mapping>
> +
>     <session-config>
>         <session-timeout>60</session-timeout>
>     </session-config>
> @@ -121,5 +132,5 @@
>         <welcome-file>index.jsp</welcome-file>
>         <welcome-file>index.html</welcome-file>
>         <welcome-file>index.htm</welcome-file>
> -    </welcome-file-list>
> +    </welcome-file-list>
> </web-app>
>
> Modified: ofbiz/trunk/applications/ecommerce/webapp/ecommerce/catalog/sidedeepcategory.ftl
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/ecommerce/webapp/ecommerce/catalog/sidedeepcategory.ftl?rev=743985&r1=743984&r2=743985&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/ecommerce/webapp/ecommerce/catalog/sidedeepcategory.ftl (original)
> +++ ofbiz/trunk/applications/ecommerce/webapp/ecommerce/catalog/sidedeepcategory.ftl Fri Feb 13 04:57:11 2009
> @@ -22,9 +22,6 @@
>
> <#-- looping macro -->
> <#macro categoryList parentCategory category wrapInBox>
> -  <#if parentCategory.productCategoryId != category.productCategoryId>
> -    <#local pStr = "/~pcategory=" + parentCategory.productCategoryId>
> -  </#if>
>   <#if catContentWrappers?exists && catContentWrappers[category.productCategoryId]?exists && 
> catContentWrappers[category.productCategoryId].get("CATEGORY_NAME")?exists>
>       <#assign categoryName = catContentWrappers[category.productCategoryId].get("CATEGORY_NAME")>
>   <#else>
> @@ -49,7 +46,7 @@
>       <div class="browsecategorylist">
>   </#if>
>         <div class="browsecategorytext">
> -          <a href="<@o...@ofbizUrl>" 
> class="${browseCategoryButtonClass}"><#if 
> categoryName?has_content>${categoryName}<#else>${categoryDescription?default("")}</#if></a>
> +          <a href="${Static["org.ofbiz.product.category.CatalogUrlServlet"].makeCatalogUrl(request, "", 
> category.productCategoryId, parentCategory.productCategoryId)}" class="${browseCategoryButtonClass}"><#if 
> categoryName?has_content>${categoryName}<#else>${categoryDescription?default("")}</#if></a>
>         </div>
>   <#if (Static["org.ofbiz.product.category.CategoryWorker"].checkTrailItem(request, category.getString("productCategoryId"))) || 
> (curCategoryId?exists && curCategoryId == category.productCategoryId)>
>     <#local subCatList = Static["org.ofbiz.product.category.CategoryWorker"].getRelatedCategoriesRet(request, "subCatList", 
> category.getString("productCategoryId"), true)>
>
> Modified: ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/productsummary.ftl
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/productsummary.ftl?rev=743985&r1=743984&r2=743985&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/productsummary.ftl (original)
> +++ ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/productsummary.ftl Fri Feb 13 04:57:11 2009
> @@ -18,10 +18,8 @@
> -->
> <#if product?exists>
>     <#-- variable setup -->
> -    <#assign targetRequestName = "product">
> -    <#if requestAttributes.targetRequestName?has_content>
> -        <#assign targetRequestName = requestAttributes.targetRequestName>
> -    </#if>
> +    <#assign productUrl = Static["org.ofbiz.product.category.CatalogUrlServlet"].makeCatalogUrl(request, product.productId, 
> categoryId, "")/>
> +
>     <#if requestAttributes.productCategoryMember?exists>
>         <#assign prodCatMem = requestAttributes.productCategoryMember>
>     </#if>
> @@ -34,7 +32,7 @@
>     <#assign productDetailId = productDetailId + product.productId/>
>     <div class="productsummary">
>         <div class="smallimage">
> -            <a href="<@ofbizUrl>${targetRequestName}/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>">
> +            <a href="${productUrl}">
>                 <span id="${productInfoLinkId}" class="popup_link"><img 
> src="<@o...@ofbizContentUrl>" alt="Small Image"/></span>
>             </a>
>         </div>
> @@ -62,16 +60,16 @@
>             <div style="color: red;">${uiLabelMap.ProductNoLongerAvailable}</div>
>           <#-- check to see if it is a rental item; will enter parameters on the detail screen-->
>           <#elseif product.productTypeId?if_exists == "ASSET_USAGE">
> -            <a href="<@ofbizUrl>product/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>" 
> class="buttontext">${uiLabelMap.OrderMakeBooking}...</a>
> +            <a href="${productUrl}" class="buttontext">${uiLabelMap.OrderMakeBooking}...</a>
>           <#-- check to see if it is an aggregated or configurable product; will enter parameters on the detail screen-->
>           <#elseif product.productTypeId?if_exists == "AGGREGATED">
> -            <a href="<@ofbizUrl>product/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>" 
> class="buttontext">${uiLabelMap.OrderConfigure}...</a>
> +            <a href="${productUrl}" class="buttontext">${uiLabelMap.OrderConfigure}...</a>
>           <#-- check to see if the product is a virtual product -->
>           <#elseif product.isVirtual?exists && product.isVirtual == "Y">
> -            <a href="<@ofbizUrl>product/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>" 
> class="buttontext">${uiLabelMap.OrderChooseVariations}...</a>
> +            <a href="${productUrl}" class="buttontext">${uiLabelMap.OrderChooseVariations}...</a>
>           <#-- check to see if the product requires an amount -->
>           <#elseif product.requireAmount?exists && product.requireAmount == "Y">
> -            <a href="<@ofbizUrl>product/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>" 
> class="buttontext">${uiLabelMap.OrderChooseAmount}...</a>
> +            <a href="${productUrl}" class="buttontext">${uiLabelMap.OrderChooseAmount}...</a>
>           <#else>
>             <form method="post" action="<@ofbizUrl>additem<#if 
> requestAttributes._CURRENT_VIEW_?exists>/${requestAttributes._CURRENT_VIEW_}</#...@ofbizUrl>" 
> name="the${requestAttributes.formNamePrefix?if_exists}${requestAttributes.listIndex?if_exists}form" style="margin: 0;">
>               <input type="hidden" name="add_product_id" value="${product.productId}"/>
> @@ -102,7 +100,7 @@
>         </div>
>         <div class="productinfo">
>           <div>
> -            <a href="<@ofbizUrl>${targetRequestName}/<#if 
> categoryId?exists>~category_id=${categoryId}/</#...@ofbizUrl>" 
> class="linktext">${productContentWrapper.get("PRODUCT_NAME")?if_exists}</a>
> +            <a href="${productUrl}" class="linktext">${productContentWrapper.get("PRODUCT_NAME")?if_exists}</a>
>           </div>
>           <div>${productContentWrapper.get("DESCRIPTION")?if_exists}<#if 
> daysToShip?exists>&nbsp;-&nbsp;${uiLabelMap.ProductUsuallyShipsIn} <b>${daysToShip}</b> ${uiLabelMap.CommonDays}!</#if></div>
>
>
> Added: ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java?rev=743985&view=auto
> ==============================================================================
> --- ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java (added)
> +++ ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java Fri Feb 13 04:57:11 2009
> @@ -0,0 +1,170 @@
> +/*******************************************************************************
> + * 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.ofbiz.product.category;
> +
> +import java.io.IOException;
> +import java.util.List;
> +import java.util.Map;
> +
> +import javax.servlet.RequestDispatcher;
> +import javax.servlet.ServletConfig;
> +import javax.servlet.ServletException;
> +import javax.servlet.http.HttpServlet;
> +import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpServletResponse;
> +
> +import javolution.util.FastList;
> +
> +import org.ofbiz.base.util.Debug;
> +import org.ofbiz.base.util.StringUtil;
> +import org.ofbiz.base.util.UtilHttp;
> +import org.ofbiz.base.util.UtilMisc;
> +import org.ofbiz.base.util.UtilValidate;
> +import org.ofbiz.entity.GenericDelegator;
> +import org.ofbiz.entity.GenericEntityException;
> +
> +/**
> + * ControlServlet.java - Master servlet for the web application.
> + */
> +@SuppressWarnings("serial")
> +public class CatalogUrlServlet extends HttpServlet {
> +
> +    public static final String module = CatalogUrlServlet.class.getName();
> +
> +    public static final String CATALOG_URL_MOUNT_POINT = "catalog";
> +    public static final String CONTROL_MOUNT_POINT = "control";
> +    public static final String PRODUCT_REQUEST = "product";
> +    public static final String CATEGORY_REQUEST = "category";
> +
> +    public CatalogUrlServlet() {
> +        super();
> +    }
> +
> +    /**
> +     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
> +     */
> +    public void init(ServletConfig config) throws ServletException {
> +        super.init(config);
> +    }
> +
> +    /**
> +     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
> +     */
> +    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
> +        doGet(request, response);
> +    }
> +
> +    /**
> +     * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
> +     */
> +    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
> +        GenericDelegator delegator = (GenericDelegator) getServletContext().getAttribute("delegator");
> +
> +        String pathInfo = request.getPathInfo();
> +        List<String> pathElements = StringUtil.split(pathInfo, "/");
> +
> +        // look for productId
> +        String productId = null;
> +        try {
> +            String lastPathElement = pathElements.get(pathElements.size() - 1);
> +            if (lastPathElement.startsWith("p_") || delegator.findOne("Product", UtilMisc.toMap("productId", lastPathElement), 
> true) != null) {
> +                if (lastPathElement.startsWith("p_")) {
> +                    productId = lastPathElement.substring(2);
> +                } else {
> +                    productId = lastPathElement;
> +                }
> +                pathElements.remove(pathElements.size() - 1);
> +            }
> +        } catch (GenericEntityException e) {
> +            Debug.logError(e, "Error looking up product info for ProductUrl with path info [" + pathInfo + "]: " + e.toString(), 
> module);
> +        }
> +
> +        // get category info going with the IDs that remain
> +        String categoryId = null;
> +        if (pathElements.size() == 1) {
> +            CategoryWorker.setTrail(request, pathElements.get(0), null);
> +            categoryId = pathElements.get(0);
> +        } else if (pathElements.size() == 2) {
> +            CategoryWorker.setTrail(request, pathElements.get(1), pathElements.get(0));
> +            categoryId = pathElements.get(1);
> +        } else if (pathElements.size() > 2) {
> +            List<String> trail = CategoryWorker.getTrail(request);
> +            if (trail == null) {
> +                trail = FastList.newInstance();
> +            }
> +
> +            if (trail.contains(pathElements.get(0))) {
> +                // first category is in the trail, so remove it everything after that and fill it in with the list from the 
> pathInfo
> +                int firstElementIndex = trail.indexOf(pathElements.get(0));
> +                while (trail.size() > firstElementIndex) {
> +                    trail.remove(firstElementIndex);
> +                }
> +                trail.addAll(pathElements);
> +            } else {
> +                // first category is NOT in the trail, so clear out the trail and use the pathElements list
> +                trail.clear();
> +                trail.addAll(pathElements);
> +            }
> +            CategoryWorker.setTrail(request, trail);
> +            categoryId = pathElements.get(pathElements.size() - 1);
> +        }
> +
> +        if (categoryId != null) {
> +            request.setAttribute("productCategoryId", categoryId);
> +        }
> +        // setup the data and forward the request
> +        if (productId != null) {
> +            request.setAttribute("product_id", productId);
> +        }
> +
> +        RequestDispatcher rd = request.getRequestDispatcher("/" + CONTROL_MOUNT_POINT + "/" + (productId != null ? 
> PRODUCT_REQUEST : CATEGORY_REQUEST));
> +        rd.forward(request, response);
> +    }
> +
> +    /**
> +     * @see javax.servlet.Servlet#destroy()
> +     */
> +    public void destroy() {
> +        super.destroy();
> +    }
> +
> +    public static String makeCatalogUrl(HttpServletRequest request, String productId, String currentCategoryId, String 
> previousCategoryId) {
> +        StringBuilder urlBuilder = new StringBuilder();
> +        urlBuilder.append(request.getSession().getServletContext().getContextPath());
> +        urlBuilder.append("/");
> +        urlBuilder.append(CATALOG_URL_MOUNT_POINT);
> +
> +        if (UtilValidate.isNotEmpty(currentCategoryId)) {
> +            List<String> trail = CategoryWorker.getTrail(request);
> +            trail = CategoryWorker.adjustTrail(trail, currentCategoryId, previousCategoryId);
> +            for (String trailCategoryId: trail) {
> +                if ("TOP".equals(trailCategoryId)) continue;
> +                urlBuilder.append("/");
> +                urlBuilder.append(trailCategoryId);
> +            }
> +        }
> +
> +        if (UtilValidate.isNotEmpty(productId)) {
> +            urlBuilder.append("/p_");
> +            urlBuilder.append(productId);
> +        }
> +
> +        return urlBuilder.toString();
> +    }
> +}
>
> Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java
> ------------------------------------------------------------------------------
>    svn:keywords = "Date Rev Author URL Id"
>
> Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CatalogUrlServlet.java
> ------------------------------------------------------------------------------
>    svn:mime-type = text/plain
>
> Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CategoryWorker.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CategoryWorker.java?rev=743985&r1=743984&r2=743985&view=diff
> ==============================================================================
> --- ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CategoryWorker.java (original)
> +++ ofbiz/trunk/applications/product/src/org/ofbiz/product/category/CategoryWorker.java Fri Feb 13 04:57:11 2009
> @@ -58,7 +58,7 @@
>
>     public static String getCatalogTopCategory(ServletRequest request, String defaultTopCategory) {
>         HttpServletRequest httpRequest = (HttpServletRequest) request;
> -        Map requestParameters = UtilHttp.getParameterMap(httpRequest);
> +        Map<String, Object> requestParameters = UtilHttp.getParameterMap(httpRequest);
>         String topCatName = null;
>         boolean fromSession = false;
>
> @@ -274,74 +274,78 @@
>     public static void setTrail(ServletRequest request, String currentCategory) {
>         Map<String, Object> requestParameters = UtilHttp.getParameterMap((HttpServletRequest) request);
>         String previousCategory = (String) requestParameters.get("pcategory");
> -
> -        if (Debug.verboseOn()) Debug.logVerbose("[CategoryWorker.setTrail] Start: previousCategory=" + previousCategory +
> -                " currentCategory=" + currentCategory, module);
> +        setTrail(request, currentCategory, previousCategory);
> +    }
> +
> +    public static void setTrail(ServletRequest request, String currentCategory, String previousCategory) {
> +        if (Debug.verboseOn()) Debug.logVerbose("[CategoryWorker.setTrail] Start: previousCategory=" + previousCategory + " 
> currentCategory=" + currentCategory, module);
>
>         // if there is no current category, just return and do nothing to that the last settings will stay
> -        if (currentCategory == null || currentCategory.length() <= 0)
> +        if (UtilValidate.isEmpty(currentCategory)) {
>             return;
> +        }
>
>         // always get the last crumb list
>         List<String> crumb = getTrail(request);
> -
> -        if (crumb == null) {
> -            crumb = FastList.newInstance();
> +        crumb = adjustTrail(crumb, currentCategory, previousCategory);
> +        setTrail(request, crumb);
> +    }
> +
> +    public static List<String> adjustTrail(List<String> origTrail, String currentCategoryId, String previousCategoryId) {
> +        List<String> trail = FastList.newInstance();
> +        if (origTrail != null) {
> +            trail.addAll(origTrail);
>         }
>
>         // if no previous category was specified, check to see if currentCategory is in the list
> -        if (previousCategory == null || previousCategory.length() <= 0) {
> -            if (crumb.contains(currentCategory)) {
> +        if (UtilValidate.isEmpty(previousCategoryId)) {
> +            if (trail.contains(currentCategoryId)) {
>                 // if cur category is in crumb, remove everything after it and return
> -                int cindex = crumb.lastIndexOf(currentCategory);
> +                int cindex = trail.lastIndexOf(currentCategoryId);
>
> -                if (cindex < (crumb.size() - 1)) {
> -                    for (int i = crumb.size() - 1; i > cindex; i--) {
> -                        String deadCat = crumb.remove(i);
> -
> -                        if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Removed after current category index: " + i 
> +
> -                                " catname: " + deadCat, module);
> +                if (cindex < (trail.size() - 1)) {
> +                    for (int i = trail.size() - 1; i > cindex; i--) {
> +                        String deadCat = trail.remove(i);
> +                        //if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Removed after current category index: " + 
> i + " catname: " + deadCat, module);
>                     }
>                 }
> -                return;
> +                return trail;
>             } else {
>                 // current category is not in the list, and no previous category was specified, go back to the beginning
> -                crumb.clear();
> -                crumb.add("TOP");
> -                if (UtilValidate.isNotEmpty(previousCategory)) {
> -                    crumb.add(previousCategory);
> +                trail.clear();
> +                trail.add("TOP");
> +                if (UtilValidate.isNotEmpty(previousCategoryId)) {
> +                    trail.add(previousCategoryId);
>                 }
> -                if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Starting new list, added TOP and previousCategory: " 
> + previousCategory, module);
> +                //if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Starting new list, added TOP and previousCategory: 
> " + previousCategoryId, module);
>             }
>         }
>
> -        if (!crumb.contains(previousCategory)) {
> +        if (!trail.contains(previousCategoryId)) {
>             // previous category was NOT in the list, ERROR, start over
> -            if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] ERROR: previousCategory (" + previousCategory +
> -                    ") was not in the crumb list, position is lost, starting over with TOP", module);
> -            crumb.clear();
> -            crumb.add("TOP");
> -            if (UtilValidate.isNotEmpty(previousCategory)) {
> -                crumb.add(previousCategory);
> +            //if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] previousCategory (" + previousCategoryId + ") was not 
> in the crumb list, position is lost, starting over with TOP", module);
> +            trail.clear();
> +            trail.add("TOP");
> +            if (UtilValidate.isNotEmpty(previousCategoryId)) {
> +                trail.add(previousCategoryId);
>             }
>         } else {
>             // remove all categories after the previous category, preparing for adding the current category
> -            int index = crumb.indexOf(previousCategory);
> +            int index = trail.indexOf(previousCategoryId);
>
> -            if (index < (crumb.size() - 1)) {
> -                for (int i = crumb.size() - 1; i > index; i--) {
> -                    String deadCat = crumb.remove(i);
> -
> -                    if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Removed after previous category index: " + i +
> -                            " catname: " + deadCat, module);
> +            if (index < (trail.size() - 1)) {
> +                for (int i = trail.size() - 1; i > index; i--) {
> +                    String deadCat = trail.remove(i);
> +                    //if (Debug.infoOn()) Debug.logInfo("[CategoryWorker.setTrail] Removed after previous category index: " + i + 
> " catname: " + deadCat, module);
>                 }
>             }
>         }
>
>         // add the current category to the end of the list
> -        crumb.add(currentCategory);
> -        if (Debug.verboseOn()) Debug.logVerbose("[CategoryWorker.setTrail] Continuing list: Added currentCategory: " + 
> currentCategory, module);
> -        setTrail(request, crumb);
> +        trail.add(currentCategoryId);
> +        if (Debug.verboseOn()) Debug.logVerbose("[CategoryWorker.setTrail] Continuing list: Added currentCategory: " + 
> currentCategoryId, module);
> +
> +        return trail;
>     }
>
>     /** @deprecated */
> @@ -374,10 +378,11 @@
>     public static boolean checkTrailItem(ServletRequest request, String category) {
>         List<String> crumb = getTrail(request);
>
> -        if (crumb != null && crumb.contains(category))
> +        if (crumb != null && crumb.contains(category)) {
>             return true;
> -        else
> +        } else {
>             return false;
> +        }
>     }
>
>     /** @deprecated */
>
>