View Javadoc

1   /**
2    * Licensed under the Artistic License; you may not use this file
3    * except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *      http://displaytag.sourceforge.net/license.html
7    *
8    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
9    * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10   * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11   */
12  package org.displaytag.util;
13  
14  import java.util.HashMap;
15  import java.util.Iterator;
16  import java.util.Map;
17  import java.util.Set;
18  import java.util.StringTokenizer;
19  
20  import org.apache.commons.lang.ObjectUtils;
21  import org.apache.commons.lang.StringEscapeUtils;
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.commons.lang.UnhandledException;
24  import org.apache.commons.lang.builder.EqualsBuilder;
25  import org.apache.commons.lang.builder.HashCodeBuilder;
26  
27  
28  /**
29   * @author Fabrizio Giustina
30   * @version $Revision$ ($Author$)
31   */
32  public class DefaultHref implements Href
33  {
34  
35      /**
36       * D1597A17A6.
37       */
38      private static final long serialVersionUID = 899149338534L;
39  
40      /**
41       * Base url for the href.
42       */
43      private String url;
44  
45      /**
46       * Url parameters.
47       */
48      private Map parameters;
49  
50      /**
51       * Anchor (to be added at the end of URL).
52       */
53      private String anchor;
54  
55      /**
56       * Construct a new Href parsing a URL. Parameters are stripped from the base url and saved in the parameters map.
57       * @param baseUrl String
58       */
59      public DefaultHref(String baseUrl)
60      {
61          this.parameters = new HashMap();
62          setFullUrl(baseUrl);
63      }
64  
65      /**
66       * @see org.displaytag.util.Href#setFullUrl(java.lang.String)
67       */
68      public void setFullUrl(String baseUrl)
69      {
70          this.url = null;
71          this.anchor = null;
72          String noAnchorUrl;
73          int anchorposition = baseUrl.indexOf('#');
74  
75          // extract anchor from url
76          if (anchorposition != -1)
77          {
78              noAnchorUrl = baseUrl.substring(0, anchorposition);
79              this.anchor = baseUrl.substring(anchorposition + 1);
80          }
81          else
82          {
83              noAnchorUrl = baseUrl;
84          }
85  
86          if (noAnchorUrl.indexOf('?') == -1)
87          {
88              // simple url, no parameters
89              this.url = noAnchorUrl;
90              return;
91          }
92  
93          // the Url already has parameters, put them in the parameter Map
94          StringTokenizer tokenizer = new StringTokenizer(noAnchorUrl, "?"); //$NON-NLS-1$
95  
96          if (baseUrl.startsWith("?")) //$NON-NLS-1$
97          {
98              // support fake URI's which are just parameters to use with the current uri
99              url = TagConstants.EMPTY_STRING;
100         }
101         else
102         {
103             // base url (before "?")
104             url = tokenizer.nextToken();
105         }
106 
107         if (!tokenizer.hasMoreTokens())
108         {
109             return;
110         }
111 
112         // process parameters
113         StringTokenizer paramTokenizer = new StringTokenizer(tokenizer.nextToken(), "&"); //$NON-NLS-1$
114 
115         // split parameters (key=value)
116         while (paramTokenizer.hasMoreTokens())
117         {
118             // split key and value ...
119             String[] keyValue = StringUtils.split(paramTokenizer.nextToken(), '=');
120 
121             // encode name/value to prevent css
122             String escapedKey = StringEscapeUtils.escapeHtml(keyValue[0]);
123             String escapedValue = keyValue.length > 1
124                 ? StringEscapeUtils.escapeHtml(keyValue[1])
125                 : TagConstants.EMPTY_STRING;
126 
127             if (!this.parameters.containsKey(escapedKey))
128             {
129                 // ... and add it to the map
130                 this.parameters.put(escapedKey, escapedValue);
131             }
132             else
133             {
134                 // additional value for an existing parameter
135                 Object previousValue = this.parameters.get(escapedKey);
136                 if (previousValue != null && previousValue.getClass().isArray())
137                 {
138                     Object[] previousArray = (Object[]) previousValue;
139                     Object[] newArray = new Object[previousArray.length + 1];
140 
141                     int j;
142 
143                     for (j = 0; j < previousArray.length; j++)
144                     {
145                         newArray[j] = previousArray[j];
146                     }
147 
148                     newArray[j] = escapedValue;
149                     this.parameters.put(escapedKey, newArray);
150                 }
151                 else
152                 {
153                     this.parameters.put(escapedKey, new Object[]{previousValue, escapedValue});
154                 }
155             }
156         }
157     }
158 
159     /**
160      * Adds a parameter to the href.
161      * @param name String
162      * @param value Object
163      * @return this Href instance, useful for concatenation.
164      */
165     public Href addParameter(String name, Object value)
166     {
167         this.parameters.put(name, ObjectUtils.toString(value, null));
168         return this;
169     }
170 
171     /**
172      * Removes a parameter from the href.
173      * @param name String
174      */
175     public void removeParameter(String name)
176     {
177         // warning, param names are escaped
178         this.parameters.remove(StringEscapeUtils.escapeHtml(name));
179     }
180 
181     /**
182      * Adds an int parameter to the href.
183      * @param name String
184      * @param value int
185      * @return this Href instance, useful for concatenation.
186      */
187     public Href addParameter(String name, int value)
188     {
189         this.parameters.put(name, new Integer(value));
190         return this;
191     }
192 
193     /**
194      * Getter for the map containing link parameters. The returned map is always a copy and not the original instance.
195      * @return parameter Map (copy)
196      */
197     public Map getParameterMap()
198     {
199         Map copyMap = new HashMap(this.parameters.size());
200         copyMap.putAll(this.parameters);
201         return copyMap;
202     }
203 
204     /**
205      * Adds all the parameters contained in the map to the Href. The value in the given Map will be escaped before
206      * added. Any parameter already present in the href object is removed.
207      * @param parametersMap Map containing parameters
208      */
209     public void setParameterMap(Map parametersMap)
210     {
211         // create a new HashMap
212         this.parameters = new HashMap(parametersMap.size());
213 
214         // copy the parameters
215         addParameterMap(parametersMap);
216     }
217 
218     /**
219      * Adds all the parameters contained in the map to the Href. The value in the given Map will be escaped before
220      * added. Parameters in the original href are kept and not overridden.
221      * @param parametersMap Map containing parameters
222      */
223     public void addParameterMap(Map parametersMap)
224     {
225         // handle nulls
226         if (parametersMap == null)
227         {
228             return;
229         }
230 
231         // copy value, escaping html
232         Iterator mapIterator = parametersMap.entrySet().iterator();
233         while (mapIterator.hasNext())
234         {
235             Map.Entry entry = (Map.Entry) mapIterator.next();
236             String key = StringEscapeUtils.escapeHtml((String) entry.getKey());
237 
238             // don't overwrite parameters
239             if (!this.parameters.containsKey(key))
240             {
241                 Object value = entry.getValue();
242 
243                 if (value != null)
244                 {
245                     if (value.getClass().isArray())
246                     {
247                         String[] values = (String[]) value;
248                         for (int i = 0; i < values.length; i++)
249                         {
250                             values[i] = StringEscapeUtils.escapeHtml(values[i]);
251                         }
252                     }
253                     else
254                     {
255                         value = StringEscapeUtils.escapeHtml(value.toString());
256                     }
257                 }
258 
259                 this.parameters.put(key, value);
260             }
261         }
262     }
263 
264     /**
265      * Getter for the base url (without parameters).
266      * @return String
267      */
268     public String getBaseUrl()
269     {
270         return this.url;
271     }
272 
273     /**
274      * Returns the URI anchor.
275      * @return anchor or <code>null</code> if no anchor has been set.
276      */
277     public String getAnchor()
278     {
279         return this.anchor;
280     }
281 
282     /**
283      * Setter for the URI anchor.
284      * @param name string to be used as anchor name (without #).
285      */
286     public void setAnchor(String name)
287     {
288         this.anchor = name;
289     }
290 
291     /**
292      * toString: output the full url with parameters.
293      * @return String
294      */
295     public String toString()
296     {
297         StringBuffer buffer = new StringBuffer(30);
298 
299         buffer.append(this.url);
300 
301         if (this.parameters.size() > 0)
302         {
303             buffer.append('?');
304             Set parameterSet = this.parameters.entrySet();
305 
306             Iterator iterator = parameterSet.iterator();
307 
308             while (iterator.hasNext())
309             {
310                 Map.Entry entry = (Map.Entry) iterator.next();
311 
312                 Object key = entry.getKey();
313                 Object value = entry.getValue();
314 
315                 if (value == null)
316                 {
317                     buffer.append(key).append('='); // no value
318                 }
319                 else if (value.getClass().isArray())
320                 {
321                     Object[] values = (Object[]) value;
322                     for (int i = 0; i < values.length; i++)
323                     {
324                         if (i > 0)
325                         {
326                             buffer.append(TagConstants.AMPERSAND);
327                         }
328 
329                         buffer.append(key).append('=').append(values[i]);
330                     }
331                 }
332                 else
333                 {
334                     buffer.append(key).append('=').append(value);
335                 }
336 
337                 if (iterator.hasNext())
338                 {
339                     buffer.append(TagConstants.AMPERSAND);
340                 }
341             }
342         }
343 
344         if (this.anchor != null)
345         {
346             buffer.append('#');
347             buffer.append(this.anchor);
348         }
349 
350         return buffer.toString();
351     }
352 
353     /**
354      * @see java.lang.Object#clone()
355      */
356     public Object clone()
357     {
358         final DefaultHref href;
359         try
360         {
361             href = (DefaultHref) super.clone();
362         }
363         catch (CloneNotSupportedException e)
364         {
365             throw new UnhandledException(e);
366         }
367 
368         href.parameters = new HashMap(this.parameters);
369         return href;
370     }
371 
372     /**
373      * @see java.lang.Object#equals(Object)
374      */
375     public boolean equals(Object object)
376     {
377         if (!(object instanceof DefaultHref))
378         {
379             return false;
380         }
381         DefaultHref rhs = (DefaultHref) object;
382         return new EqualsBuilder().append(this.parameters, rhs.parameters).append(this.url, rhs.url).append(
383             this.anchor,
384             rhs.anchor).isEquals();
385     }
386 
387     /**
388      * @see java.lang.Object#hashCode()
389      */
390     public int hashCode()
391     {
392         return new HashCodeBuilder(1313733113, -431360889)
393             .append(this.parameters)
394             .append(this.url)
395             .append(this.anchor)
396             .toHashCode();
397     }
398 }