KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > fluent > FluentConfigurator


1 package org.directwebremoting.fluent;
2
3 import java.util.ArrayList JavaDoc;
4 import java.util.Collections JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.List JavaDoc;
8 import java.util.Map JavaDoc;
9
10 import org.directwebremoting.AjaxFilter;
11 import org.directwebremoting.Container;
12 import org.directwebremoting.extend.AccessControl;
13 import org.directwebremoting.extend.AjaxFilterManager;
14 import org.directwebremoting.extend.Configurator;
15 import org.directwebremoting.extend.Converter;
16 import org.directwebremoting.extend.ConverterManager;
17 import org.directwebremoting.extend.Creator;
18 import org.directwebremoting.extend.CreatorManager;
19 import org.directwebremoting.impl.SignatureParser;
20 import org.directwebremoting.util.LocalUtil;
21 import org.directwebremoting.util.Logger;
22
23 /**
24  * A {@link Configurator} that used the FluentInterface style as
25  * <a HREF="http://www.martinfowler.com/bliki/FluentInterface.html">described by
26  * Martin Fowler</a>.
27  *
28  * <p>To wire up the configuration programatically rather than having to use
29  * <code>dwr.xml</code>. In order to use this style, you'll need to:</p>
30  *
31  * <ul>
32  * <li>Create a concrete implementation of {@link FluentConfigurator} which
33  * implements the {@link #configure()} method.</li>
34  * <li>Add an init param '<code>customConfigurator</code>' to the DWR servlet in
35  * <code>web.xml</code> to point at your new class.</li>
36  * </ul>
37  *
38  * <p>The implementation of {@link #configure()} will look something like
39  * this:</p>
40  *
41  * <pre>
42  * public void configure() {
43  * withConverterType("dog", "com.yourcompany.beans.Dog");
44  * withCreatorType("ejb", "com.yourcompany.dwr.creator.EJBCreator");
45  * withCreator("new", "ApartmentDAO")
46  * .addParam("scope", "session")
47  * .addParam("class", "com.yourcompany.dao.ApartmentDAO")
48  * .exclude("saveApartment")
49  * .withAuth("method", "role");
50  * withCreator("struts", "DogDAO")
51  * .addParam("clas", "com.yourcompany.dao.DogDAO")
52  * .include("getDog")
53  * .include("getColor");
54  * withConverter("dog", "*.Dog")
55  * .addParam("name", "value");
56  * withSignature()
57  * .addLine("import java.util.List;")
58  * .addLine("import com.example.Check;")
59  * .addLine("Check.setLotteryResults(List<Integer> nos);");
60  * }
61  * </pre>
62  * @author Aaron Johnson [ajohnson at cephas dot net / <a HREF="http://cephas.net/blog">http://cephas.net/blog</a>]
63  * @author Joe Walker [joe at getahead dot ltd dot uk]
64  */

65 public abstract class FluentConfigurator implements Configurator
66 {
67     /**
68      * This method is used to configure DWR using the fluent style.
69      */

70     public abstract void configure();
71
72     /**
73      * Add a new {@link Converter} definition.
74      * @param id The id referred to by the {@link #withConverter(String, String)}
75      * @param converterClassName The implementation of {@link Converter} to instansitate.
76      * @return <code>this</code> to continue the fluency
77      */

78     public FluentConfigurator withConverterType(String JavaDoc id, String JavaDoc converterClassName)
79     {
80         setState(STATE_INIT_CONVERT);
81         converterManager.addConverterType(id, converterClassName);
82         return this;
83     }
84
85     /**
86      * Use a {@link Converter} to instansiate a class
87      * @param newConverter A predefined {@link Converter} or one defined by
88      * {@link #withConverterType(String, String)}.
89      * @param newMatch The javascript name of this component
90      * @return <code>this</code> to continue the fluency
91      */

92     public FluentConfigurator withConverter(String JavaDoc newConverter, String JavaDoc newMatch)
93     {
94         setState(STATE_ALLOW_CONVERT);
95         this.converter = newConverter;
96         this.match = newMatch;
97         return this;
98     }
99
100     /**
101      * Add a new {@link Creator} definition.
102      * @param id The id referred to by the {@link #withCreator(String, String)}
103      * @param creatorClassName The implementation of {@link Creator} to instansitate.
104      * @return <code>this</code> to continue the fluency
105      */

106     public FluentConfigurator withCreatorType(String JavaDoc id, String JavaDoc creatorClassName)
107     {
108         setState(STATE_INIT_CREATE);
109         creatorManager.addCreatorType(id, creatorClassName);
110         return this;
111     }
112
113     /**
114      * Use a {@link Creator} to instansiate a class
115      * @param newTypeName A predefined {@link Creator} or one defined by
116      * {@link #withCreatorType(String, String)}.
117      * @param newScriptName The javascript name of this component
118      * @return <code>this</code> to continue the fluency
119      */

120     public FluentConfigurator withCreator(String JavaDoc newTypeName, String JavaDoc newScriptName)
121     {
122         setState(STATE_ALLOW_CREATE);
123         this.typeName = newTypeName;
124         this.scriptName = newScriptName;
125         return this;
126     }
127     
128     /**
129      * @param newFilterClassName filter class name
130      * @return <code>this</code> to continue the fluency
131      */

132     public FluentConfigurator withFilter(String JavaDoc newFilterClassName)
133     {
134         setState(STATE_ALLOW_FILTER);
135         this.filterClassName = newFilterClassName;
136         return this;
137     }
138
139     /**
140      * Add a parameter to whatever is being configured.
141      * @param name The name of the parameter
142      * @param value The value of the parameter
143      * @return <code>this</code> to continue the fluency
144      */

145     public FluentConfigurator addParam(String JavaDoc name, String JavaDoc value)
146     {
147         if (params == null)
148         {
149             params = new HashMap JavaDoc();
150         }
151
152         params.put(name, value);
153         return this;
154     }
155
156     /**
157      * Add a filter to whatever is being configured.
158      * @param newFilterClassName The class to add as a filter
159      * @return <code>this</code> to continue the fluency
160      */

161     public FluentConfigurator addFilter(String JavaDoc newFilterClassName)
162     {
163         if (filters == null)
164         {
165             filters = new ArrayList JavaDoc();
166         }
167
168         filters.add(newFilterClassName);
169         return this;
170     }
171
172     /**
173      * Add an include rule to a {@link Creator}.
174      * This should be used during a {@link #withCreator(String, String)} call.
175      * @param methodName The method name to be allowed
176      * @return <code>this</code> to continue the fluency
177      */

178     public FluentConfigurator include(String JavaDoc methodName)
179     {
180         accessControl.addIncludeRule(scriptName, methodName);
181         return this;
182     }
183
184     /**
185      * Add an exclude rule to a {@link Creator}
186      * This should be used during a {@link #withCreator(String, String)} call.
187      * @param methodName The method name to be dis-allowed
188      * @return <code>this</code> to continue the fluency
189      */

190     public FluentConfigurator exclude(String JavaDoc methodName)
191     {
192         accessControl.addExcludeRule(scriptName, methodName);
193         return this;
194     }
195
196     /**
197      * Add an authorization rule to a {@link Creator}
198      * This should be used during a {@link #withCreator(String, String)} call.
199      * @param methodName The method name to have a required role
200      * @param role The required role for the given method
201      * @return <code>this</code> to continue the fluency
202      */

203     public FluentConfigurator withAuth(String JavaDoc methodName, String JavaDoc role)
204     {
205         accessControl.addRoleRestriction(scriptName, methodName, role);
206         return this;
207     }
208
209     /**
210      * Add lines to a signature.
211      * @return <code>this</code> to continue the fluency
212      */

213     public FluentConfigurator withSignature()
214     {
215         setState(STATE_SIGNATURE);
216         return this;
217     }
218
219     /**
220      * Add lines to a signature.
221      * @param line The line of text to add to the signature configuration
222      * @return <code>this</code> to continue the fluency
223      */

224     public FluentConfigurator addLine(String JavaDoc line)
225     {
226         if (null == line)
227         {
228             return this;
229         }
230
231         if (null == signature)
232         {
233             signature = new StringBuffer JavaDoc();
234         }
235
236         signature.append(line);
237         signature.append(System.getProperty("line.separator"));
238
239         return this;
240     }
241
242     /**
243      * Because some parts of the configuration require multiple steps, the instance
244      * needs to maintain a state across invocations. Whenever the state is changed
245      * by calling this method, the instance will 'flush' anything in the queue
246      * applicable to that state EVEN IF the state itself doesn't change. Thus, it's
247      * important that the child methods don't call setState() when being invoked.
248      * @param state The new state. See the STATE_* constants.
249      */

250     private void setState(int state)
251     {
252         flush();
253         this.state = state;
254     }
255
256     /**
257      * Takes and configuration that is in progress and calls methods on the
258      * various objects to enable that configuration.
259      */

260     private void flush()
261     {
262         switch (state)
263         {
264         case STATE_INIT_CONVERT:
265             // do nothing;
266
break;
267
268         case STATE_INIT_CREATE:
269             // do nothing;
270
break;
271
272         case STATE_ALLOW_CONVERT:
273             try
274             {
275                 if (params == null)
276                 {
277                     converterManager.addConverter(match, converter, EMPTY_MAP);
278                 }
279                 else
280                 {
281                     converterManager.addConverter(match, converter, params);
282                 }
283             }
284             catch (Exception JavaDoc e)
285             {
286                 log.warn("Failed to add converter of type='" + converter + "', match=" + match + ": ", e);
287             }
288             params = null;
289             match = null;
290             converter = null;
291             break;
292
293         case STATE_ALLOW_CREATE:
294             try
295             {
296                 if (params == null)
297                 {
298                     creatorManager.addCreator(scriptName, typeName, EMPTY_MAP);
299                 }
300                 else
301                 {
302                     creatorManager.addCreator(scriptName, typeName, params);
303                 }
304                 
305                 if (filters != null)
306                 {
307                     for (Iterator JavaDoc it = filters.iterator(); it.hasNext();)
308                     {
309                         String JavaDoc className = (String JavaDoc) it.next();
310                         AjaxFilter filter = (AjaxFilter) LocalUtil.classNewInstance(scriptName, className, AjaxFilter.class);
311
312                         if (filter != null)
313                         {
314                             LocalUtil.setParams(filter, Collections.EMPTY_MAP, Collections.EMPTY_LIST);
315                             ajaxFilterManager.addAjaxFilter(filter, scriptName);
316                         }
317
318                     }
319                 }
320             }
321             catch (Exception JavaDoc e)
322             {
323                 log.warn("Failed to add creator of type='" + typeName + "', scriptName=" + scriptName + ": ", e);
324             }
325             params = null;
326             scriptName = null;
327             typeName = null;
328             filters = null;
329             break;
330             
331         case STATE_ALLOW_FILTER:
332             try
333             {
334                 Class JavaDoc impl = LocalUtil.classForName(filterClassName);
335                 AjaxFilter object = (AjaxFilter) impl.newInstance();
336
337                 if (params != null) {
338                     LocalUtil.setParams(object, params, Collections.EMPTY_LIST);
339                 }
340                 
341                 ajaxFilterManager.addAjaxFilter(object);
342             }
343             catch (ClassCastException JavaDoc ex)
344             {
345                 log.error(filterClassName + " does not implement " + AjaxFilter.class.getName(), ex);
346             }
347             catch (NoClassDefFoundError JavaDoc ex)
348             {
349                 log.info("Missing class for filter (class='" + filterClassName + "'). Cause: " + ex.getMessage());
350             }
351             catch (Exception JavaDoc ex)
352             {
353                 log.error("Failed to add filter: class=" + filterClassName, ex);
354             }
355             
356             params = null;
357             filterClassName = null;
358             
359             break;
360
361         case STATE_SIGNATURE:
362             if (signature != null && signature.length() > 0)
363             {
364                 SignatureParser sigp = new SignatureParser(converterManager, creatorManager);
365                 sigp.parse(signature.toString());
366             }
367             break;
368
369         default:
370             break;
371         }
372     }
373
374     /* (non-Javadoc)
375      * @see org.directwebremoting.Configurator#configure(org.directwebremoting.Container)
376      */

377     public void configure(Container container)
378     {
379         converterManager = (ConverterManager) container.getBean(ConverterManager.class.getName());
380         ajaxFilterManager = (AjaxFilterManager) container.getBean(AjaxFilterManager.class.getName());
381         accessControl = (AccessControl) container.getBean(AccessControl.class.getName());
382         creatorManager = (CreatorManager) container.getBean(CreatorManager.class.getName());
383
384         configure();
385
386         setState(STATE_COMPLETE);
387     }
388
389     /**
390      * Used for <allow create .../>
391      */

392     private String JavaDoc typeName = null;
393
394     /**
395      * Used for <allow create .../>
396      */

397     private String JavaDoc scriptName = null;
398
399     /**
400      * Used for <allow filter .../>
401      */

402     private String JavaDoc filterClassName = null;
403     
404     /**
405      * Used for <allow convert .../>
406      */

407     private String JavaDoc converter = null;
408
409     /**
410      * Used for <allow convert .../>
411      */

412     private String JavaDoc match = null;
413
414     /**
415      * holds name / value pairs used in <allow create|convert ... />
416      */

417     private Map JavaDoc params = null;
418     
419     /**
420      * holds classNames of filters used in <allow create/ filter />
421      */

422     private List JavaDoc filters = null;
423
424     /**
425      * holds signature lines
426      */

427     private StringBuffer JavaDoc signature = null;
428
429     /**
430      * What section of a configuration are we in?
431      */

432     private int state = -1;
433
434     /**
435      * JDK5: we can convert this to Collections.emptyMap();
436      */

437     private static final Map JavaDoc EMPTY_MAP = Collections.unmodifiableMap(new HashMap JavaDoc());
438
439     /**
440      * What AjaxFilters apply to which Ajax calls?
441      */

442     private AjaxFilterManager ajaxFilterManager = null;
443     
444     /**
445      * The ConverterManager that we are configuring
446      */

447     private ConverterManager converterManager = null;
448
449     /**
450      * The AccessControl that we are configuring
451      */

452     private AccessControl accessControl = null;
453
454     /**
455      * The CreatorManager that we are configuring
456      */

457     private CreatorManager creatorManager = null;
458
459     /**
460      * {@link #state} to say we are working in {@link #withCreatorType(String, String)}
461      */

462     private static final int STATE_INIT_CREATE = 0;
463
464     /**
465      * {@link #state} to say we are working in {@link #withConverterType(String, String)}
466      */

467     private static final int STATE_INIT_CONVERT = 1;
468
469     /**
470      * {@link #state} to say we are working in {@link #withCreator(String, String)}
471      */

472     private static final int STATE_ALLOW_CREATE = 2;
473     
474     /**
475      * {@link #state} to say we are working in {@link #withFilter(String)}
476      */

477     private static final int STATE_ALLOW_FILTER = 3;
478
479     /**
480      * {@link #state} to say we are working in {@link #withConverter(String, String)}
481      */

482     private static final int STATE_ALLOW_CONVERT = 4;
483
484     /**
485      * {@link #state} to say we are working in {@link #withSignature()}
486      */

487     private static final int STATE_SIGNATURE = 5;
488
489     /**
490      * {@link #state} to say {@link #configure()} has completed
491      */

492     private static final int STATE_COMPLETE = 6;
493
494     /**
495      * The log stream
496      */

497     private static final Logger log = Logger.getLogger(FluentConfigurator.class);
498 }
499
Popular Tags