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