I have a pretty large velocity page that needs to generate a lot of urls, and I noticed that the roughly 4000 urls generated with the URLBean class took about two seconds to generate. I took a look at the code and saw that it creates and throws away a StringBuffer AND a HashMap every single iteration. The URLTag class has the exact same issue (since it's a copy paste instead of a reuse of the same code, blech). I have attached the updated code, which is roughly twice as fast on this perticular page at least.

I looked at com.opensymphony.webwork.views.util.UrlHelper.java and it seems to have the exact same issue, although in this case it's not as easy a fix since it's not claiming to be a bean.

Anders Hovmöller
/*
 * WebWork, Web Application Framework
 *
 * Distributable under Apache license.
 * See terms of license at opensource.org
 */
package webwork.view.taglib;

import org.apache.commons.logging.*;

import javax.servlet.http.*;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import webwork.util.TextUtil;
import webwork.util.BeanUtil;

/**
 * This tag is used to create a URL. You can use the "param" tag inside the body to 
provide
 *      additional request parameters.
 *
 * @see ParamTag
 * @author Rickard Öberg ([EMAIL PROTECTED])
 * @version $Revision: 1.18 $
 */
public class URLTag
      extends WebWorkBodyTagSupport
      implements ParamTag.Parametric {
   // Attributes ----------------------------------------------------
   protected String page;
   protected String valueAttr;
   protected String value;
   protected Map params = new HashMap();
         protected StringBuffer link = new StringBuffer();

   // Public --------------------------------------------------------
   /**
    * @deprecated use value instead
    */
   public void setPage(String aName) {
      page = aName;
   }

   public void setValue(String aName) {
      valueAttr = aName;
   }

   public void addParameter(String name, Object value) {
      if (params == null)
         params = new HashMap();

      if (value == null)
         params.remove(name);
      else {
         params.put(name, BeanUtil.toStringValue(value));
      }
   }

   // BodyTag implementation ----------------------------------------
   public int doStartTag() throws JspException {
      if (page == null) {
         if (valueAttr != null)
            value = findString(valueAttr);
      } else {
         value = page;
      }
      this.params.clear();
      this.page=null;

                        link.delete(0, link.length());

      //no explicit url set so attach params from current url, do
      //this at start so body params can override any of these they wish.
      if (value==null) {
         try {
            // Parse the query string to make sure that the parameters come from the 
query, and not some posted data
            HttpServletRequest req = ((HttpServletRequest) pageContext.getRequest());
            String query = req.getQueryString();
            if (query != null)
            {
               // Remove possible #foobar suffix
               int idx = query.lastIndexOf('#');
               if (idx != -1)
                  query = query.substring(0, idx-1);
               params.putAll(HttpUtils.parseQueryString(query));
            }
         } catch (Exception e) {
            LogFactory.getLog(this.getClass()).warn("Unable to put request parameters 
("+((HttpServletRequest) pageContext.getRequest()).getQueryString()+") into parameter 
map.", e);
         }
      }
      return EVAL_BODY_TAG;
   }

   public int doEndTag() throws JspException {
      HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
      HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();

      if (value != null) {
         // Check if context path needs to be added
         // Add path to absolute links
         if (value.startsWith("/")) {
            link.append(request.getContextPath());
         }

         // Add page
         link.append(value);
      } else {
         // Go to "same page"
         String requestURI = (String) request.getAttribute("webwork.request_uri");
//         String contextPath=(String)request.getAttribute("webwork.context_path");
         if (requestURI == null) requestURI = request.getRequestURI();
//         if(contextPath==null) contextPath=request.getContextPath();
         link.append(requestURI);
      }

      //if the value was not explicitly set grab the params from the request

      if (params != null && params.size() > 0) {
         if (link.toString().indexOf("?") == -1) {
            link.append('?');
         } else {
            link.append("&");
         }

         // Set parameters
         Iterator enum = params.entrySet().iterator();
         while (enum.hasNext()) {
            Map.Entry entry = (Map.Entry) enum.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            if (value != null) {
               if (value instanceof String) {
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode((String) value));
               } else {
                  String[] values = (String[]) value;
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode(values[0]));
               }
            }

            if (enum.hasNext())
               link.append("&");
         }
      }

      String result;
      try {
         //Category.getInstance(this.getClass().getName()).debug(link.toString());
         result = response.encodeURL(link.toString());
      } catch (Exception e) {
         // Could not encode URL for some reason
         // Use it unchanged
         result = link.toString();
      }

      String id = getId();
      if(id != null) {
         pageContext.setAttribute(id, result);
         pageContext.setAttribute(id, result, PageContext.REQUEST_SCOPE);
      } else {
         try {
            pageContext.getOut().write(result);
         } catch (IOException _ioe) {
            throw new JspException("IOError: " + _ioe.getMessage());
                 }
      }

      return EVAL_PAGE;
   }
}








/*
* WebWork, Web Application Framework
*
* Distributable under Apache license.
* See terms of license at opensource.org
*/
package webwork.view.velocity;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.net.URLEncoder;

/**
 * A utility class that is used to URL-encode links
 * in Velocity templates.
 *
 * @author Dave Bryson ([EMAIL PROTECTED])
 */
public class URLBean
{
   /** Http Request */
   private HttpServletRequest request = null;
   /** Http Response */
   private HttpServletResponse response = null;
   /** Content name */
   private String page = null;
   /** Path info parameters */
   private Map params = new HashMap();

         private StringBuffer link = new StringBuffer();

   public URLBean()
   {

   }

   /**
    *  @return String the page name
    */
   public String getPage()
   {
      return page;
   }

   /**
    * Set the page.
    * @param String the page name
    * @return URLBean this
    */
   public URLBean setPage(String page)
   {
      this.page = page;
      return this;
   }

   /**
    * Add a parameter to the URL.
    * Cut and paste from the UrlTag in WebWork
    * @param String name
    * @param Object value
    * @return URLBean this
    */
   public URLBean addParameter(String name, Object value)
   {
      if (params == null)
         params = new HashMap();

      if (value == null)
         params.remove(name);
      else
         params.put(name, value.toString());
      return this;
   }

   /**
    * Set the HttpRequest
    * @param HttpSevletRequest the request
    */
   public void setRequest(HttpServletRequest req)
   {
      this.request = req;
   }

   /**
    * Set the HttpServletResponse
    * @param HttpServlet the response
    */
   public void setResponse(HttpServletResponse resp)
   {
      this.response = resp;
   }

   /**
    * Generates the URL. This is called automatically
    * in the Velocity template. In otherwords, you do not
    * need to explicitly call toString()
    * This is pretty much a cut and paste of code from the URLTag
    * in Webwork
    * @return String the generated URI
    */
   public String getURL()
   {
      if (page == null)
      {
         // No particular page requested, so go to "same page"
         // Add query params to parameters
         params = request.getParameterMap();
      }

      if (page != null)
      {
         if ( page.startsWith("/") )
         {
            // Add context to the front of the URI
            String appContext = request.getContextPath();
            link.append(appContext);
         }

         link.append(page);
      }
      else
      {
         // Go to "same page"
         String requestURI = (String) request.getAttribute("webwork.request_uri");

         if (requestURI == null) requestURI = request.getRequestURI();
         link.append(requestURI);
      }

      if (params != null && params.size() > 0)
      {
         link.append('?');

         // Set parameters
         Iterator enum = params.entrySet().iterator();
         while (enum.hasNext())
         {
            Map.Entry entry = (Map.Entry) enum.next();
            String name = (String) entry.getKey();
            Object value = entry.getValue();
            if (value != null)
            {
               if (value instanceof String)
               {
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode((String) value));
               }
               else
               {
                  String[] values = (String[]) value;
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode(values[0]));
               }
            }

            if (enum.hasNext())
               link.append("&");
         }
      }

      String result;
      try
      {
         result = response.encodeURL(link.toString());
      }
      catch (Exception e)
      {
         // Could not encode URL for some reason
         // Use it unchanged
         result = link.toString();
      }

      // Reset params and page
      this.params.clear();
      this.page=null;
                        link.delete(0, link.length());

      return result;
   }

   public String toString()
   {
      return getURL();
   }
}

Reply via email to