View Javadoc

1   package org.apache.velocity.tools.view;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  import javax.servlet.http.Cookie;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  import org.apache.velocity.runtime.log.Log;
28  import org.apache.velocity.tools.config.DefaultKey;
29  import org.apache.velocity.tools.config.ValidScope;
30  import org.apache.velocity.tools.ConversionUtils;
31  import org.apache.velocity.tools.Scope;
32  
33  /**
34   * <p>View tool for convenient cookie access and creation.</p>
35   * <p><pre>
36   * Template example(s):
37   *  $cookie.foo
38   *  $cookie.add("bar",'woogie')
39   *
40   * tools.xml configuration:
41   * &lt;tools&gt;
42   *   &lt;toolbox scope="request"&gt;
43   *     &lt;tool class="org.apache.velocity.tools.view.CookieTool"/&gt;
44   *   &lt;/toolbox&gt;
45   * &lt;/tools&gt;
46   * </pre></p>
47   *
48   * <p>This class is only designed for use as a request-scope tool.</p>
49   *
50   * @author <a href="mailto:dim@colebatch.com">Dmitri Colebatch</a>
51   * @author Nathan Bubna
52   * @since VelocityTools 2.0
53   * @version $Id: CookieTool.java 740389 2009-02-03 19:38:36Z nbubna $
54   */
55  @DefaultKey("cookies")
56  @ValidScope(Scope.REQUEST)
57  public class CookieTool
58  {
59      protected HttpServletRequest request;
60      protected HttpServletResponse response;
61      protected Log log;
62      private List<Cookie> jar;
63  
64      // --------------------------------------- Setup Methods -------------
65  
66      /**
67       * Sets the current {@link HttpServletRequest}. This is required
68       * for this tool to operate and will throw a NullPointerException
69       * if this is not set or is set to {@code null}.
70       */
71      public void setRequest(HttpServletRequest request)
72      {
73          if (request == null)
74          {
75              throw new NullPointerException("request should not be null");
76          }
77          this.request = request;
78      }
79  
80      /**
81       * Sets the current {@link HttpServletResponse}. This is required
82       * for this tool to operate and will throw a NullPointerException
83       * if this is not set or is set to {@code null}.
84       */
85      public void setResponse(HttpServletResponse response)
86      {
87          if (response == null)
88          {
89              throw new NullPointerException("response should not be null");
90          }
91          this.response = response;
92      }
93  
94      /**
95       * Sets the {@link Log} used for logging messages when Cookie
96       * creation fails due to an invalid name.
97       */
98      public void setLog(Log log)
99      {
100         this.log = log;
101     }
102 
103     // --------------------------------------- Setup Methods -------------
104 
105     /**
106      * Expose array of Cookies for this request to the template.
107      *
108      * <p>This is equivalent to <code>$request.cookies</code>.</p>
109      *
110      * @return list of Cookie objects for this request
111      */
112     public List<Cookie> getAll()
113     {
114         if (jar == null) {
115             Cookie[] array = request.getCookies();
116             if (array == null)
117             {
118                 return null;
119             }
120 
121             jar = new ArrayList<Cookie>(array.length);
122             for (Cookie c : array)
123             {
124                 Cookie sc = new SugarCookie(c);
125                 jar.add(sc);
126             }
127         }
128         return jar;
129     }
130 
131     /**
132      * Returns the Cookie with the specified name, if it exists.
133      *
134      * <p>So, if you had a cookie named 'foo', you'd get it's value
135      * by <code>$cookies.foo.value</code> or it's max age
136      * by <code>$cookies.foo.maxAge</code></p>
137      */
138     public Cookie get(String name)
139     {
140         List<Cookie> all = getAll();
141         if (all != null)
142         {
143             for (Cookie c : all)
144             {
145                 if (c.getName().equals(name))
146                 {
147                     return c;
148                 }
149             }
150         }
151         return null;
152     }
153 
154     /**
155      * Adds the specified Cookie to the HttpServletResponse.
156      * This does *not* add the Cookie to the current request.
157      *
158      * @param c is for cookie (that's good enough for me)
159      * @since VelocityTools 2.0
160      * @return an empty String to prevent the reference from rendering
161      *         unless the cookie passed in is null, then it returns null
162      */
163     public String add(Cookie c)
164     {
165         if (c == null)
166         {
167             return null;
168         }
169         response.addCookie(c);
170         return "";
171     }
172 
173     /**
174      * Adds a new Cookie with the specified name and value
175      * to the HttpServletResponse.  This does *not* add a Cookie
176      * to the current request.
177      *
178      * @param name the name to give this cookie
179      * @param value the value to be set for this cookie
180      * @return an empty String to prevent the reference from rendering
181      */
182     public String add(String name, String value)
183     {
184         return add(create(name, value));
185     }
186 
187     /**
188      * Convenience method to add a new Cookie to the response
189      * and set an expiry time for it.
190      *
191      * @param name the name to give this cookie
192      * @param value the value to be set for this cookie
193      * @param maxAge the expiry to be set for this cookie
194      * @return an empty String to prevent the reference from rendering
195      */
196     public String add(String name, String value, Object maxAge)
197     {
198         return add(create(name, value, maxAge));
199     }
200 
201     /**
202      * Creates a new Cookie with the specified name and value.
203      * This does *not* add the Cookie to the response, so the
204      * created Cookie will not be set unless you do
205      * <code>$cookies.add($myCookie)</code>.
206      *
207      * @param name the name to give this cookie
208      * @param value the value to be set for this cookie
209      * @return The new SugarCookie object.
210      * @since VelocityTools 1.3
211      */
212     public Cookie create(String name, String value)
213     {
214         try
215         {
216             return new SugarCookie(name, value);
217         }
218         catch (IllegalArgumentException iae)
219         {
220             if (log != null && log.isDebugEnabled())
221             {
222                 log.debug("CookieTool: Could not create cookie with name \""+name+"\"", iae);
223             }
224             return null;
225         }
226     }
227 
228     /**
229      * Convenience method to create a new Cookie
230      * and set an expiry time for it.
231      *
232      * @param name the name to give this cookie
233      * @param value the value to be set for this cookie
234      * @param maxAge the expiry to be set for this cookie
235      * @return The new SugarCookie object.
236      * @since VelocityTools 1.3
237      */
238     public Cookie create(String name, String value, Object maxAge)
239     {
240         SugarCookie sc = (SugarCookie)create(name, value);
241         if (sc == null)
242         {
243             return null;
244         }
245         return sc.maxAge(maxAge);
246     }
247 
248     /**
249      * Retrieves the specified cookie and sets the Max-Age to 0
250      * to tell the browser to delete the cookie.  Then this returns
251      * an empty string to make this render silently. If no such cookie
252      * exists, then it returns null to show the error.
253      *
254      * @param name the name of the cookie to be eaten
255      * @return empty string, or null if no such cookie exists
256      * @see Cookie#setMaxAge
257      * @see #add(Cookie)
258      * @see #get(String)
259      */
260     public String delete(String name)
261     {
262         Cookie c = get(name);
263         if (c == null)
264         {
265             return null;
266         }
267         c.setMaxAge(0);
268         return add(c);
269     }
270 
271     @Override
272     public String toString()
273     {
274         List<Cookie> all = getAll();
275         if (all == null)
276         {
277             return super.toString();
278         }
279         StringBuilder out = new StringBuilder();
280         out.append('[');
281         for (int i=0; i < all.size(); i++)
282         {
283             if (i != 0)
284             {
285                 out.append(", ");
286             }
287             Cookie c = all.get(i);
288             out.append(c.getName());
289             out.append('=');
290             out.append(c.getValue());
291         }
292         out.append(']');
293         return out.toString();
294     }
295 
296 
297     /**
298      * Extends {@link Cookie} to add some fluid API sugar and
299      * a toString() method that renders the Cookie's value
300      * instead of the usual Object.toString() shenanigans.
301      */
302     public static class SugarCookie extends Cookie
303     {
304         private Cookie plain;
305 
306         /* c is for cookie. that's good enough for me. */
307         public SugarCookie(Cookie c)
308         {
309             this(c.getName(), c.getValue());
310             setMaxAge(c.getMaxAge());
311             setComment(c.getComment());
312             setPath(c.getPath());
313             setVersion(c.getVersion());
314             setSecure(c.getSecure());
315             // avoid setDomain NPE
316             if (c.getDomain() != null)
317             {
318                 setDomain(c.getDomain());
319             }
320             this.plain = c;
321         }
322 
323         public SugarCookie(String name, String value)
324         {
325             super(name, value);
326         }
327 
328         public SugarCookie value(Object obj)
329         {
330             String value = ConversionUtils.toString(obj);
331             setValue(value);
332             if (plain != null)
333             {
334                 plain.setValue(value);
335             }
336             return this;
337         }
338 
339         public SugarCookie maxAge(Object obj)
340         {
341             Number maxAge = ConversionUtils.toNumber(obj);
342             if (maxAge == null)
343             {
344                 return null;
345             }
346             setMaxAge(maxAge.intValue());
347             if (plain != null)
348             {
349                 plain.setMaxAge(maxAge.intValue());
350             }
351             return this;
352         }
353 
354         public SugarCookie comment(Object obj)
355         {
356             String comment = ConversionUtils.toString(obj);
357             setComment(comment);
358             if (plain != null)
359             {
360                 plain.setComment(comment);
361             }
362             return this;
363         }
364 
365         public SugarCookie domain(Object obj)
366         {
367             String domain = ConversionUtils.toString(obj);
368             if (domain == null)
369             {
370                 return null;
371             }
372             setDomain(domain);
373             if (plain != null)
374             {
375                 plain.setDomain(domain);
376             }
377             return this;
378         }
379 
380         public SugarCookie path(Object obj)
381         {
382             String path = ConversionUtils.toString(obj);
383             setPath(path);
384             if (plain != null)
385             {
386                 plain.setPath(path);
387             }
388             return this;
389         }
390 
391         public SugarCookie version(Object obj)
392         {
393             Number version = ConversionUtils.toNumber(obj);
394             if (version == null)
395             {
396                 return null;
397             }
398             setVersion(version.intValue());
399             if (plain != null)
400             {
401                 plain.setVersion(version.intValue());
402             }
403             return this;
404         }
405 
406         public SugarCookie secure(Object obj)
407         {
408             Boolean secure = ConversionUtils.toBoolean(obj);
409             if (secure == null)
410             {
411                 return null;
412             }
413             setSecure(secure.booleanValue());
414             if (plain != null)
415             {
416                 plain.setSecure(secure.booleanValue());
417             }
418             return this;
419         }
420 
421         public Cookie getPlain()
422         {
423             return plain;
424         }
425 
426         @Override
427         public String toString()
428         {
429             return getValue();
430         }
431     }
432 
433 }