Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/clra/web/NameSelectorTag.java


1   /*
2    * Copyright (c) Carnegie Lake Rowing Association 2002. All rights reserved.
3    * Distributed under the GPL license. See doc/COPYING.
4    * $RCSfile: NameSelectorTag.java,v $
5    * $Date: 2003/02/26 03:38:46 $
6    * $Revision: 1.4 $
7    */
8   
9   package com.clra.web;
10  
11  import com.clra.util.ErrorUtils;
12  import java.io.IOException;
13  import java.io.Serializable;
14  import java.util.HashMap;
15  import java.util.Hashtable;
16  import java.util.Iterator;
17  import java.util.Map;
18  import javax.servlet.http.HttpServletRequest;
19  import javax.servlet.http.HttpServletResponse;
20  import javax.servlet.http.HttpUtils;
21  import javax.servlet.jsp.JspException;
22  import javax.servlet.jsp.JspWriter;
23  import javax.servlet.jsp.PageContext;
24  import javax.servlet.jsp.tagext.TagSupport;
25  import org.apache.log4j.Category;
26  import org.apache.struts.util.MessageResources;
27  import org.apache.struts.util.ResponseUtils;
28  
29  /**
30   * Allows the user to choose a group of items, selected by the first
31   * letter of their name.</p>
32   *
33   * <p>Selection is case-insensitive and limited to 8 predefined groups,
34   * like the buttons on a telephone:<ol start="2">
35   * <li> ABC  - names less than 'D'</li>
36   * <li> DEF  - names greater than 'D' and less than 'G'</li>
37   * <li> GHI  - names greater than 'G' and less than 'J'</li>
38   * <li> JKL  - names greater than 'J' and less than 'M'</li>
39   * <li> MNO  - names greater than 'M' and less than 'P'</li>
40   * <li> PQRS - names greater than 'P' and less than 'T'</li>
41   * <li> TUV  - names greater than 'T' and less than 'W'</li>
42   * <li> WXYZ - names greater than or equal to 'W'</li>
43   * </ol>
44   * Note that the first group, <tt>ABC</tt>, may contain names like "3Com",
45   * whereas the last group, <tt>WXYZ</tt>, may contain names like "Ėtvos".
46   * Also note that the group is indexed from '2', not '0'.</p>
47   *
48   * @author <a mailto:"rphall@pluto.njcc.com">Rick Hall</a>
49   * @version $Revision: 1.4 $ $Date: 2003/02/26 03:38:46 $
50   */
51  public class NameSelectorTag extends TagSupport {
52  
53    private final static String base = NameSelectorTag.class.getName();
54    private final static Category theLog = Category.getInstance( base );
55  
56    /** The message resources for this package */
57    protected static MessageResources messages =
58      MessageResources.getMessageResources("com.clra.web.clra");
59  
60    /** The cached value of the groups used by this selector */
61    private static Map _groups = null;
62    static {
63      _groups = new HashMap();
64      final String PN_GROUP_PREFIX = "nameselector.group.0";
65      for ( int i=2; i<10; i++ ) {
66        Integer key = new Integer( i );
67        String PN = PN_GROUP_PREFIX + i;
68        String lbl = messages.getMessage( PN );
69        _groups.put( key, lbl );
70      }
71    }
72  
73    /** The groups used by this selector */
74    protected static Map groups() {
75      return _groups;
76    }
77  
78    /** The context-relative URI */
79    protected String page = null;
80  
81    /** The currently selected group (2 - 9) */
82    private Integer currentGroup = null;
83  
84    /** Return the context-relative URI */
85    public String getPage() {
86      return (this.page);
87    }
88  
89    /** Set the context-relative URI */
90    public void setPage(String page) {
91      this.page = page;
92    }
93  
94    /** Return the currently selected group (2 - 9, or null) */
95    public Integer getCurrentGroup() {
96      return this.currentGroup;
97    }
98  
99    /** Set the currently selected group (2 - 9, or null) */
100   public void setCurrentGroup( Integer currentGroup ) throws JspException {
101     if ( currentGroup != null ) {
102         if ( currentGroup.intValue() < 2 || currentGroup.intValue() > 9 ) {
103         String msg = messages.getMessage(
104             "nameselector.badcurrentGroup", currentGroup );
105         throw new JspException(msg);
106       }
107     }
108     this.currentGroup = currentGroup;
109   }
110 
111   /**
112    * A utility which determines what group should be currently selected
113    * based on the page context. The algorithm is:<ol>
114    * <li>Check for a request parameter named INameList.AN_GROUP. If
115    * found, and it is a valid Integer in the range 2 - 9, use it.</li>
116    * <li>Check for a request attribute named INameList.AN_GROUP. If
117    * found, and it is valid, use it.</li>
118    * <li>Check for a session attribute named INameList.AN_GROUP. If
119    * found, and it is valid, use it.</li>
120    * <li>If a valid group hasn't been determined yet, return the index
121    * of the first group, <tt>ABC</tt> (index 2).</li>
122    * </ol>
123    */
124   public static Integer groupFromContext( PageContext context ) {
125 
126     final String NAME = INameList.AN_GROUP;
127     Integer retVal = null;
128 
129     // Try request parameter first
130     try {
131       String s = context.getRequest().getParameter(NAME);
132       if ( s != null ) {
133         retVal = Integer.valueOf(s);
134         if ( retVal.intValue() < 2 || retVal.intValue() > 9 ) {
135           throw new IllegalArgumentException( "bad group == " + retVal );
136         }
137       }
138     }
139     catch( Exception x ) {
140       String msg = ErrorUtils.createDbgMsg( "requestParameter: " + NAME, x );
141       theLog.error( msg, x );
142     }
143 
144     // Try request attribute second
145     try {
146       if ( retVal == null ) {
147         Object o = context.getRequest().getAttribute(NAME);
148         if ( o != null && o instanceof Integer ) {
149           retVal = (Integer) o;
150           if ( retVal.intValue() < 2 || retVal.intValue() > 9 ) {
151             throw new IllegalArgumentException( "bad group == " + retVal );
152           } // if invalid Integer
153         } // if o
154       } // if null retVal
155     } // try
156     catch( Exception x ) {
157       String msg = ErrorUtils.createDbgMsg( "requestAttribute: " + NAME, x );
158       theLog.error( msg, x );
159     }
160     
161     // Try session attribute third
162     try {
163       if ( retVal == null ) {
164         Object o = context.getSession().getAttribute(NAME);
165         if ( o != null && o instanceof Integer ) {
166           retVal = (Integer) o;
167           if ( retVal.intValue() < 2 || retVal.intValue() > 9 ) {
168             throw new IllegalArgumentException( "bad group == " + retVal );
169           } // if valid Integer
170         } // if o
171       } // if null retVal
172     } // try
173     catch( Exception x ) {
174       String msg = ErrorUtils.createDbgMsg( "sessionAttribute: " + NAME, x );
175       theLog.error( msg, x );
176     }
177 
178     // Use the first group as a fallback
179     if ( retVal == null ) {
180       retVal = new Integer( 2 );
181     }
182 
183     return retVal;
184   } // groupFromContext(PageContext)
185 
186   /**
187    * A utility which resets request and session attributes so that only
188    * the session attribute AN_GROUP holds the currently selected name.
189    * The algorithm is:<ol>
190    * <li>Check for a request attribute named INameList.AN_GROUP. If
191    * found, remove it.</li>
192    * <li>Check for a session attribute named INameList.AN_GROUP. If
193    * found, reset to the specified value; otherwise create and set it.</li>
194    * </ol>
195    * If the specified name is invalid (not between 2 - 9, inclusive),
196    * no action is taken and an error is logged.
197    */
198   public static void resetGroupInContexts(PageContext context, Integer group) {
199 
200     // Check the context and group.
201     // If either is invalid, log an error and null both as a flag.
202     if ( context == null || group == null
203         || group.intValue() < 2 || group.intValue() > 9 ) {
204       theLog.error( "invalid context/group == " + context + "/" + group );
205       context = null;
206       group = null;
207     }
208 
209     final String NAME = INameList.AN_GROUP;
210 
211     // Reset the request attribute
212     if ( context != null ) {
213       context.getRequest().removeAttribute(NAME);
214     }
215 
216     // Set the session attribute
217     if ( context != null ) {
218       context.getSession().setAttribute(NAME,group);
219     }
220 
221     return;
222   } // resetGroupInContexts(PageContext,Integer)
223 
224   /** Form a query string from current parameter and the specified group */
225   protected String createQueryString( int group, Hashtable queryParams ) {
226 
227     // Preconditions
228     if ( group < 2 || group > 9 ) {
229       throw new IllegalArgumentException( "invalid group == " + group );
230     }
231     if ( queryParams == null ) {
232       throw new IllegalArgumentException( "null queryParams" );
233     }
234 
235     StringBuffer sb = new StringBuffer();
236     sb.append( "?" );
237 
238     // Overwrite existing query params related to this control
239     queryParams.put(
240       INameList.AN_ISRESTRICTED, new Boolean(true).toString() );
241     queryParams.put(
242       INameList.AN_GROUP, new Integer(group).toString() );
243     
244     // Form the query string
245     boolean isFirst = true;
246     Iterator keys = queryParams.keySet().iterator();
247     while ( keys.hasNext() ) {
248 
249       if ( isFirst ) {
250         isFirst = false;
251       }
252       else {
253         sb.append( "&" );
254       }
255 
256       String key = (String) keys.next();
257       Object value = queryParams.get( key );
258       if ( value instanceof String ) {
259         sb.append( key + "=" + value );
260       }
261       else {
262         String[] values = (String[]) value;
263         for ( int i=0; i<values.length; i++ ) {
264           if ( i > 0 ) {
265             sb.append( "&" );
266           }
267           sb.append( key + "=" + values[i] );
268         } // for String[]
269       } // else String[]
270 
271     } // while keys
272 
273     return sb.toString();
274   } // createQueryString(int,Hashtable)
275 
276   /** Create a link from the specified page */
277   protected String createLink( int group,
278     String contextPath, String page ) throws JspException {
279 
280     // Preconditions
281     if ( contextPath == null ) {
282       throw new IllegalArgumentException( "null contextPath" );
283     }
284     if ( page == null ) {
285       throw new IllegalArgumentException( "null page" );
286     }
287 
288     StringBuffer sb = new StringBuffer( contextPath );
289     sb.append(page);
290 
291     Hashtable queryParams;
292     String tmp = sb.toString();
293     int idx = tmp.indexOf("?");
294     if ( idx > -1 && idx < page.length()-1 ) {
295       String s = tmp.substring( idx+1 );
296       queryParams = HttpUtils.parseQueryString(s);
297     }
298     else {
299       queryParams = new Hashtable();
300     }
301     String queryString = createQueryString( group, queryParams );
302 
303     String url;
304     if ( idx < 0 ) {
305       url = tmp + "?";
306     }
307     else {
308       url = sb.substring( 0, idx );
309     }
310     url = url + queryString;
311 
312     return url;
313   } // createLink(int,String,String)
314 
315   /** Creates a link from the currentGroup request */
316   protected String createLink( int group, HttpServletRequest request ) {
317 
318     StringBuffer url = HttpUtils.getRequestURL( request );
319 
320     String s = request.getQueryString();
321     Hashtable queryParams;
322     if ( s != null ) {
323       queryParams = HttpUtils.parseQueryString(s);
324     }
325     else {
326       queryParams = new Hashtable();
327     }
328 
329     String queryString = createQueryString( group, queryParams );
330     url.append( queryString );
331 
332     return url.toString();
333   } // createLink(int,HttpServletRequest)
334 
335   protected void doStartLink( int group ) throws JspException {
336 
337     // Create a link
338     HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
339     String url = null;
340     if ( this.page != null ) {
341       // Use the specified page
342       String contextPath = request.getContextPath();
343       url = createLink( group, contextPath, page );
344     }
345     else {
346       // Link back to the currentGroup page by default
347       url = createLink( group, request );
348     }
349 
350     // Generate the hyperlink start element
351     HttpServletResponse response =
352       (HttpServletResponse) pageContext.getResponse();
353     StringBuffer results = new StringBuffer("<a href=\"");
354     results.append( response.encodeURL(url) );
355     results.append("\">");
356 
357     // Print this element to our output writer
358     JspWriter writer = pageContext.getOut();
359     try {
360       writer.print(results.toString());
361     } catch (IOException e) {
362       throw new JspException
363           (messages.getMessage("nameselector.io", e.toString()));
364     }
365 
366     return;
367   } // doStartLink(int)
368 
369   protected void doEndLink() throws JspException {
370 
371     // Print the ending element to our output writer
372     JspWriter writer = pageContext.getOut();
373     try {
374       writer.print("</a>");
375     } catch (IOException e) {
376       throw new JspException
377           (messages.getMessage("nameselector.io", e.toString()));
378     }
379 
380     return;
381   } // doEndLink()
382 
383   /** Writes a Integer-based group (2 - 9) as user-friendly text */
384   protected void doGroupText( int group ) throws JspException {
385 
386     if ( group < 2 || group > 9 ) {
387       throw new IllegalArgumentException( "bad index == " + group );
388     }
389 
390     JspWriter writer = pageContext.getOut();
391     try {
392       String lbl = (String) groups().get( new Integer(group) );
393       if ( lbl == null ) {
394         throw new IllegalStateException( "null label for " + group );
395       }
396       writer.print( lbl );
397     } catch (IOException e) {
398       throw new JspException(
399         messages.getMessage("nameselector.io", e.toString()) );
400     }
401 
402     return;
403   } // doGroupText(int)
404 
405   /** Writes the text that separates group links */
406   protected void doGroupLeadingSeparationText(int unused) throws JspException{
407 
408     JspWriter writer = pageContext.getOut();
409     try {
410       writer.print( "&nbsp;" );
411     } catch (IOException e) {
412       throw new JspException(
413         messages.getMessage("nameselector.io", e.toString()) );
414     }
415 
416     return;
417   } // doGroupLeadingSeparationText(int)
418 
419   /** Writes the text that separates group links */
420   protected void doGroupTrailingSeparationText(int unused) throws JspException{
421 
422     JspWriter writer = pageContext.getOut();
423     try {
424       writer.print( "&nbsp;" );
425     } catch (IOException e) {
426       throw new JspException(
427         messages.getMessage("nameselector.io", e.toString()) );
428     }
429 
430     return;
431   } // doGroupTrailingSeparationText(int)
432 
433   /** Write a group link */
434   protected void doGroupLink( int group ) throws JspException {
435 
436     doGroupLeadingSeparationText( group );
437     if ( currentGroup == null ) {
438       doStartLink( group );
439     }
440     else if ( currentGroup != null && group != currentGroup.intValue() ) {
441       doStartLink( group );
442     }
443     doGroupText( group );
444     if ( currentGroup == null ) {
445       doEndLink();
446     }
447     else if ( currentGroup != null && group != currentGroup.intValue() ) {
448       doEndLink();
449     }
450     doGroupTrailingSeparationText( group );
451 
452     return;
453   } // doGroupLink(int)
454 
455   /** Writes an alphabet's worth of group links */
456   protected void doGroupLinks() throws JspException {
457 
458     for ( int group=2; group<10; group++ ) {
459       doGroupLink( group );
460     }
461 
462     return;
463   } // doGroupLinks()
464 
465   /** Render the beginning of the selector */
466   public int doStartTag() throws JspException {
467     return (EVAL_BODY_INCLUDE);
468   }
469 
470   /** Render the end of the selector */
471   public int doEndTag() throws JspException {
472     doGroupLinks();
473     return (EVAL_PAGE);
474   }
475 
476   /**
477    * Release any acquired resources.
478    */
479   public void release() {
480     super.release();
481     this.page = null;
482     return;
483   }
484 
485 } // NameSelector
486 
487 /*
488  * $Log: NameSelectorTag.java,v $
489  * Revision 1.4  2003/02/26 03:38:46  rphall
490  * Added copyright and GPL license
491  *
492  * Revision 1.3  2002/02/24 21:18:06  rphall
493  * Fixed bug #501041
494  *
495  * Revision 1.2  2002/02/18 18:06:41  rphall
496  * Ran dos2unix to remove ^M (carriage return) from end of lines
497  *
498  * Revision 1.1.1.1  2002/01/03 21:57:28  rphall
499  * Initial load, 5th try, Jan-03-2002 4:57 PM
500  *
501  * Revision 1.2  2002/01/01 03:40:33  rphall
502  * Moved getName() from MemberName to MemberView
503  *
504  * Revision 1.1  2002/01/01 00:52:22  rphall
505  * *** empty log message ***
506  *
507  */
508 
509