KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > widget > Widget


1 /*
2  * Copyright (c) 1998-2004 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Sam
27  */

28
29
30 package com.caucho.widget;
31
32 import com.caucho.lifecycle.Lifecycle;
33 import com.caucho.util.L10N;
34
35 import java.io.IOException JavaDoc;
36 import java.util.AbstractMap JavaDoc;
37 import java.util.Collections JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41 import java.util.logging.Level JavaDoc;
42 import java.util.logging.Logger JavaDoc;
43
44 /**
45  * A Widget stores request specific state (S).
46  */

47 abstract public class Widget<S extends WidgetState>
48   extends AbstractMap JavaDoc<String JavaDoc, Widget>
49 {
50   private static L10N L = new L10N( Widget.class );
51
52   static protected final Logger JavaDoc log =
53     Logger.getLogger( Widget.class.getName() );
54
55   private String JavaDoc _id;
56   private String JavaDoc _clientId;
57   private String JavaDoc _parameterName;
58   private String JavaDoc _modeParameterName;
59   private String JavaDoc _preferencePrefix;
60   private String JavaDoc _cssClass;
61   private WidgetPreferences _widgetPreferences;
62   private WidgetMode _widgetMode;
63   private HashSet JavaDoc<WidgetMode> _allowedWidgetModesSet;
64
65   private Widget _parent;
66
67   private Lifecycle _lifecycle = new Lifecycle();
68
69   private RendererCache _rendererCache = new RendererCache();
70
71
72   public Widget()
73   {
74   }
75
76   public Widget( String JavaDoc id )
77   {
78     setId( id );
79   }
80
81   public Widget( Widget parent )
82   {
83     setParent( parent );
84     parent.put( null, this );
85   }
86
87   public Widget( Widget parent, String JavaDoc id )
88   {
89     setParent( parent );
90     setId( id );
91     parent.put( getId(), this );
92   }
93
94   public void setParent( Widget parent )
95   {
96     _parent = parent;
97   }
98
99   public Widget getParent()
100   {
101     return _parent;
102   }
103
104   public void setId( String JavaDoc id )
105   {
106     _id = id;
107   }
108
109   public String JavaDoc getId()
110   {
111     return _id;
112   }
113
114   protected String JavaDoc calculateId( Widget child )
115   {
116     return "x" + size();
117   }
118
119   /**
120    * Default is a concatentation of all parent id's separated
121    * by `_'.
122    */

123   public void setClientId( String JavaDoc clientId )
124   {
125     _clientId = clientId;
126   }
127
128   public String JavaDoc getClientId()
129   {
130     if ( _clientId == null ) {
131       if ( _parent == null )
132         _clientId = getId();
133       else {
134         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
135
136         appendId( buf, _parent, '_' );
137         buf.append( getId() );
138
139         _clientId = buf.toString();
140       }
141     }
142
143     return _clientId;
144   }
145
146   private static void appendId( StringBuffer JavaDoc buf, Widget w, char sep )
147   {
148     if ( w == null )
149       return;
150
151     if ( w._parent != null ) {
152       appendId( buf, w._parent, sep );
153     }
154
155     if ( w.getId() != null ) {
156       buf.append( w.getId() );
157       buf.append( sep );
158     }
159   }
160
161   /**
162    * Default is a concatentation of all parent id's separated
163    * by `.'.
164    */

165   public void setParameterName( String JavaDoc parameterName )
166   {
167     _parameterName = parameterName;
168   }
169
170   public String JavaDoc getParameterName()
171   {
172     if ( _parameterName == null ) {
173       if ( _parent == null )
174         _parameterName = getId();
175       else {
176         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
177
178         appendId( buf, _parent, '.' );
179         buf.append( getId() );
180
181         _parameterName = buf.toString();
182       }
183     }
184
185     return _parameterName;
186   }
187
188   /**
189    * Set a css class for renders that use it, the default is
190    * to use the value of "<code>getId()</code> <code>shortClassName</code>"
191    * where <i>shortClassName</i> is the classname portion (no package) of the
192    * widget's class.
193    *
194    * If the passed string starts with "+", for example "+clear",
195    * then the string is appended to the current cssClass.
196    *
197    * If the passed string starts with "-", for example "-clear",
198    * then the string is removed from the current cssClass.
199    *
200    * For example, a TextWidget with id "phoneNumber" and clientId
201    * "form.phoneNumber" will have a default cssClass of
202    * "textWidget * phoneNumber".
203    */

204   public void setCssClass( String JavaDoc cssClass )
205   {
206     boolean add = cssClass.charAt( 0 ) == '+';
207     boolean del = cssClass.charAt( 0 ) == '-';
208
209     if ( add || del ) {
210       cssClass = cssClass.substring(1);
211       String JavaDoc current = getCssClass();
212
213       StringBuffer JavaDoc cssClassBuf = new StringBuffer JavaDoc();
214
215       if ( current != null && current.length() > 0 ) {
216         String JavaDoc[] split = current.split( "\\s*" );
217
218         for ( int i = 0; i < split.length; i++ ) {
219           String JavaDoc token = split[i];
220
221           if ( token.equals( cssClass ) )
222             continue;
223
224           cssClassBuf.append( token );
225         }
226       }
227
228       if ( add )
229         cssClassBuf.append( cssClass );
230
231       _cssClass = cssClassBuf.toString();
232     }
233     else {
234       _cssClass = cssClass;
235     }
236   }
237
238   /**
239    * Used for information purposes
240    */

241   public String JavaDoc getLogId()
242   {
243     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
244
245     String JavaDoc classname = getClass().getName();
246     classname = classname.substring( classname.lastIndexOf('.') + 1);
247     buf.append( classname );
248     buf.append('[');
249
250     appendLogId( buf, this );
251
252     if ( _parent == null )
253       buf.append('/');
254
255     buf.append(']');
256
257     return buf.toString();
258   }
259
260   private static void appendLogId( StringBuffer JavaDoc buf, Widget w )
261   {
262     if ( w._parent != null ) {
263       appendLogId( buf, w._parent );
264       buf.append( '/' );
265     }
266
267     if ( w.getId() != null )
268       buf.append( w.getId() );
269   }
270
271
272   /**
273    * Used by implementing classes to get a css class
274    * appropriate for this widget.
275    */

276   public String JavaDoc getCssClass()
277   {
278     if ( _cssClass == null ) {
279       StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
280
281       String JavaDoc shortName = getClass().getName();
282
283       int i = shortName.lastIndexOf( '.' ) + 1;
284
285       for ( ; i < shortName.length(); i++ )
286         buf.append( shortName.charAt( i ) );
287
288       buf.append(' ');
289       buf.append( getId() );
290
291       _cssClass = buf.toString();
292     }
293
294     return _cssClass;
295   }
296
297   /**
298    * Default is to the parameterName with a prefix of "_" and a suffix
299    * of "_".
300    */

301   public void setModeParameterName( String JavaDoc modeParameterName )
302   {
303     _modeParameterName = modeParameterName;
304   }
305
306   public String JavaDoc getModeParameterName()
307   {
308     if ( _modeParameterName == null )
309       _modeParameterName = "_" + getParameterName() + "_";
310
311     return _modeParameterName;
312   }
313
314   public WidgetPreferences createWidgetPreferences()
315   {
316     if ( _widgetPreferences == null ) {
317       _widgetPreferences = new WidgetPreferences();
318     }
319
320     return _widgetPreferences;
321   }
322
323   public void addPreference( WidgetPreference widgetPreference )
324   {
325     WidgetPreferences widgetPreferences = createWidgetPreferences();
326
327     widgetPreferences.addPreference( widgetPreference );
328   }
329
330   /**
331    * If a preference "pref" is not found as a preference
332    * specifically set for this widget, the prefix is prepended
333    * and the connection preferences are checked; the default is "<i>id.</i>",
334    * for example connection.getPreferenceValue("<i>id.</i>pref").
335    */

336   public void setPreferencePrefix( String JavaDoc preferencePrefix )
337   {
338     _preferencePrefix = preferencePrefix;
339   }
340
341   /**
342    * Return a preference value.
343    */

344   public String JavaDoc getPreferenceValue( WidgetConnection connection, String JavaDoc key )
345   {
346     String JavaDoc[] values = getPreferenceValues( connection, key );
347
348     if ( values == null )
349       return null;
350     else if ( values.length == 0 )
351       return "";
352     else
353       return values[0];
354   }
355
356   /**
357    * Return preference values.
358    */

359   public String JavaDoc[] getPreferenceValues( WidgetConnection connection, String JavaDoc key )
360   {
361     WidgetPreference widgetPreference = getWidgetPreference( key );
362
363     boolean isReadOnly = widgetPreference != null
364                          && !widgetPreference.isReadOnly();
365
366     String JavaDoc[] values = null;
367
368     if ( widgetPreference != null )
369         values = widgetPreference.getValues();
370
371     if ( !isReadOnly ) {
372       key = key + _preferencePrefix;
373       values = connection.getPreferenceValues( key, values );
374     }
375
376     return values;
377   }
378
379   protected WidgetPreference getWidgetPreference( String JavaDoc key )
380   {
381     if ( _widgetPreferences == null )
382       return null;
383     else
384       return _widgetPreferences.get( key );
385
386   }
387
388   /**
389    * The default mode to use unless it specified in the State,
390    * default is WidgetMode.VIEW.
391    */

392   public void setWidgetMode( WidgetMode widgetMode )
393   {
394     _widgetMode = widgetMode;
395   }
396
397   WidgetMode getWidgetMode()
398   {
399     return _widgetMode;
400   }
401
402   /**
403    * Default is to allow all widget modes.
404    */

405   public void addAllowedWidgetMode( WidgetMode widgetMode )
406   {
407     if ( _allowedWidgetModesSet == null )
408       _allowedWidgetModesSet = new HashSet JavaDoc<WidgetMode>();
409
410     _allowedWidgetModesSet.add( widgetMode );
411   }
412
413   public boolean isWidgetModeAllowed( WidgetMode widgetMode )
414   {
415     if ( _allowedWidgetModesSet == null )
416       return true;
417     else
418       return _allowedWidgetModesSet.contains( widgetMode );
419   }
420
421   public void init()
422     throws WidgetException
423   {
424   }
425
426   private void initAll()
427     throws WidgetException
428   {
429     if ( !_lifecycle.toInitializing() )
430       return;
431
432     if ( _id == null && _parent != null )
433         throw new IllegalStateException JavaDoc( L.l( "`{0}' is required", "id" ) );
434
435     if ( _preferencePrefix == null )
436       _preferencePrefix = _id + ".";
437
438     init();
439
440     _lifecycle.toActive();
441   }
442
443   public Set JavaDoc<Map.Entry JavaDoc<String JavaDoc,Widget>> entrySet()
444   {
445     return (Set JavaDoc<Map.Entry JavaDoc<String JavaDoc,Widget>>) Collections.EMPTY_SET;
446   }
447
448   public Widget put( String JavaDoc id, Widget value )
449   {
450     throw new UnsupportedOperationException JavaDoc();
451   }
452
453   /**
454    * Called once for each request to restore the state of the widget
455    * for the request.
456    */

457   protected S decode( WidgetConnection connection )
458     throws WidgetException
459   {
460     if ( log.isLoggable( Level.FINER ) )
461       log.finer( L.l( "decode {0}", getLogId() ) );
462
463     S state = createState( connection );
464     state.setWidget( this );
465
466     String JavaDoc parameterName = getParameterName();
467
468     if ( parameterName == null && getParent() != null )
469       throw new IllegalStateException JavaDoc(
470           L.l("`{0}' cannot be null", "parameter-name" ) );
471
472     if ( parameterName != null ) {
473       String JavaDoc[] data = connection.getParameterValues( getParameterName() );
474
475       if ( log.isLoggable( Level.FINEST ) )
476         log.finest( L.l( "data from parameter {0} is {1}",
477                          getParameterName(), data ) );
478
479       state.decode( data );
480     }
481
482     decodeChildren( connection, state );
483
484     return state;
485   }
486
487   protected void decodeChildren( WidgetConnection connection,
488                                  WidgetState state )
489     throws WidgetException
490   {
491     if ( !isEmpty() ) {
492       for ( Widget child : values() ) {
493         decodeChild( connection, state, child );
494       }
495     }
496   }
497
498   protected WidgetState decodeChild( WidgetConnection connection,
499                                      WidgetState thisState,
500                                      Widget child )
501     throws WidgetException
502   {
503     WidgetState childState = child.decode( connection );
504     childState.setParent( thisState );
505
506     thisState.put( child.getId(), childState );
507
508     return childState;
509   }
510
511   abstract protected S createState( WidgetConnection connection )
512     throws WidgetException;
513
514   private void encodeTree( WidgetURL url,
515                            WidgetState state,
516                            Widget target )
517     throws WidgetException
518   {
519     encodeTree( url, state, target, false, false );
520   }
521
522   private void encodeTree( WidgetURL url,
523                            WidgetState state,
524                            Widget target,
525                            boolean isAction,
526                            boolean sawTarget )
527     throws WidgetException
528   {
529     if ( target == this ) {
530       sawTarget = true;
531       isAction = isAction( state );
532     }
533
534     encode( url, state, isAction );
535
536     if ( !isEmpty() ) {
537       for ( Widget child : values() ) {
538         WidgetState childState = state.get( child.getId() );
539
540         if ( childState == null ) {
541           throw new IllegalStateException JavaDoc(
542               L.l( "no state for `{0}', missing decode()?",
543                    child.getLogId() ) );
544         }
545
546         child.encodeTree( url, childState, target, isAction, sawTarget );
547       }
548     }
549   }
550
551   protected void encode( WidgetURL url,
552                          WidgetState state,
553                          boolean isAction )
554     throws WidgetException
555   {
556     if ( log.isLoggable( Level.FINEST ) )
557       log.finest( L.l( "encode {0}", getLogId() ) );
558
559     WidgetMode widgetMode = state._widgetMode;
560
561     if ( widgetMode != null ) {
562       if ( widgetMode == WidgetMode.VIEW
563           || widgetMode.equals( WidgetMode.VIEW ) )
564       {
565         if ( state.getParent() != null )
566           url.setParameter( getModeParameterName(), widgetMode.toString() );
567       }
568       else {
569         url.setParameter( getModeParameterName(), widgetMode.toString() );
570       }
571     }
572
573     if ( isAction && isActionParameter( state ) ) {
574       url.setAction( true );
575     }
576     else {
577       String JavaDoc[] data = state.encode();
578
579       if ( data != null )
580         url.setParameter( getParameterName(), data );
581     }
582   }
583
584   /**
585    * Does this widget submit a value directly, s
586    * in some manner other than a parameter to the url?
587    *
588    * This value only has an effect if a url is being made
589    * from a widget that has a true value
590    * for isAction().
591    *
592    * For example, HTML fields like &lt;input&gt; return true.
593    */

594   protected boolean isActionParameter( WidgetState state )
595   {
596     return false;
597   }
598
599   /**
600    * Does this widget make it so that children with isActionParameter()
601    * can submit values without encoding them?
602    *
603    * For example, an HTML &lt;form&gt; does this.
604    */

605   protected boolean isAction( WidgetState state )
606   {
607     return false;
608   }
609
610   /**
611    * Derived classes use this to create a url.
612    *
613    * The widget tree is followed parent by parent until the top is reached,
614    * and then the connection is used to create a url for that widget.
615    */

616   protected WidgetURL createURL( WidgetConnection connection )
617     throws WidgetException
618   {
619     Widget target = this;
620     Widget top = this;
621
622     while ( top.getParent() != null )
623       top = top.getParent();
624
625     WidgetURL url = connection.createURL();
626     WidgetState state = connection.prepare( top );
627
628     top.encodeTree( url, state, target );
629
630     return url;
631   }
632
633   public void render( WidgetConnection connection, S widgetState )
634     throws WidgetException, IOException JavaDoc
635   {
636     if ( ! _lifecycle.isActive() )
637       initAll();
638
639     WidgetRenderer<S> widgetRenderer
640       = _rendererCache.getRenderer( connection, this, widgetState );
641
642     widgetRenderer.render( connection, widgetState );
643   }
644
645   public void destroy()
646   {
647     if ( !_lifecycle.toDestroying() )
648       return;
649
650     _lifecycle.toDestroy();
651   }
652 }
653
Popular Tags