KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jfun > yan > Monad


1 /*****************************************************************************
2  * Copyright (C) Codehaus.org. All rights reserved. *
3  * ------------------------------------------------------------------------- *
4  * The software in this package is published under the terms of the BSD *
5  * style license a copy of which has been included with this distribution in *
6  * the LICENSE.txt file. *
7  *****************************************************************************/

8 /*
9  * Created on Mar 21, 2005
10  *
11  * Author Ben Yu
12  * ZBS
13  */

14 package jfun.yan;
15
16
17 /**
18  * The facade class to provide monadic combinators for Component.
19  * <p>
20  * {@link jfun.yan.Monad#map(jfun.yan.Creator, jfun.yan.Map)} only maps one Creator,
21  * this class provides additional map combinator to map 2, 3, 4, 5 Creators to a Component.
22  * </p>
23  * <p>
24  * For mapping for more than 5 Creator objects,
25  * use {@link jfun.yan.Component#map(jfun.yan.Map)} together with
26  * {@link jfun.yan.Components#array(jfun.yan.Component[])}
27  * or {@link jfun.yan.Components#list(jfun.yan.Creator[])}
28  * or {@link jfun.yan.Components#list(java.util.List)}.
29  * </p>
30  * <p>
31  * The bind() combinator is the ultimate resort to get flexibility.
32  * </p>
33  * Codehaus.org.
34  *
35  * @author Ben Yu
36  *
37  */

38 public class Monad {
39   /**
40    * Monadic 'bind' operation.
41    * It creates a new Component object.
42    * Upon instance creation, this Component object will
43    * <p>
44    * 1. invokes the Creator object to create an instance. <br>
45    * 2. feed the instance to the Binder object to get a second Creator object. <br>
46    * 3. Invoke the second Creator object to get a second instance. <br>
47    * 4. return the second instance as the instance of this Component. <br>
48    * </p>
49    * Since the actual component type is not known until creation time,
50    * null is returned for getType().
51    * @param c1 the Component object.
52    * @param binder the Binder object that also takes care of dynamic verification.
53    * @return the new Component object.
54    */

55   public static <From,To> Component<To> bind(Creator<From> c1, ComponentBinder<From,To> binder){
56     return new MbindComponent<From,To>(c1, binder).label();
57   }
58   /**
59    * Monadic 'bind' operation.
60    * It creates a new Component object.
61    * Upon instance creation, this Component object will
62    * <p>
63    * 1. invokes the Creator object to create an instance. <br>
64    * 2. feed the instance to the Binder object to get a second Creator object. <br>
65    * 3. Invoke the second Creator object to get a second instance. <br>
66    * 4. return the second instance as the instance of this Component. <br>
67    * </p>
68    * Since the actual component type is not known until creation time,
69    * null is returned for getType().
70    * <br>
71    * This version does not dynamically verifies the result type from the first component.
72    * @param c1 the Creator object.
73    * @param binder the Binder object.
74    * @return the new Component object.
75    */

76   public static <From,To> Component<To> bind(Creator<From> c1, Binder<From,To> binder){
77     return bind(c1, toComponentBinder(binder));
78   }
79   /**
80    * Monadic 'sequence' operation.
81    * It sequentially execute two components and keep the result of
82    * the second component.
83    * @param c1 the first component.
84    * @param c2 the second component.
85    * @return the new Component object.
86    */

87   public static <A,B> Component<B> seq(final Creator<A> c1, final Creator<B> c2){
88     //return new SeqComponent(c1, c2).label();
89
//return bind(c1, toVerificationBinder(c2)).label("seq("+c1+","+c2+")");
90
return sequence(new Creator[]{c1, c2});
91   }
92   
93   /**
94    * Monadic 'sequence' operator that sequentially execute an array
95    * of components and keep the result of the last one.
96    * @param ccs the array of the components.
97    * @return the new Component object.
98    */

99   public static <T> Component<T> sequence(final Creator<T>... ccs){
100     if(ccs.length==0) return Components.value(null);
101     if(ccs.length==1) return Components.adapt(ccs[0]);
102     return new SequenceComponent<T>(ccs).label();
103   }
104   /**
105    * Customizes a Component object so that upon creation,
106    * the new Component object transforms the result component instance to another instance.
107    * @param cc the Component object to customize.
108    * @param m the Map object to transform component instance.
109    * @return the new Component object.
110    */

111   public static <From,To> Component<To> map(final Creator<From> cc, final jfun.yan.Map<From,To> m){
112     return new MappedComponent<From,To>(cc, m)
113     .label();
114   }
115   /**
116    * Creates a Component object which takes instances
117    * created from two other Creator object and transforms them
118    * to a new Object.
119    * @param c1 the first Creator object.
120    * @param c2 the second Creator object.
121    * @param m the Map2 object to transform.
122    * @return the Component object.
123    */

124   public static <A,B,R> Component<R> map(Creator<A> c1, Creator<B> c2, Map2<A,B,R> m){
125     return new MappedComponent2<A,B,R>(c1, c2, m)
126     .label();
127   }
128   /**
129    * Creates a Component object which takes instances
130    * created from three other Creator object and transforms them
131    * to a new Object.
132    * @param c1 the first Creator object.
133    * @param c2 the second Creator object.
134    * @param c3 the third Creator object.
135    * @param m the Map3 object to transform.
136    * @return the Component object.
137    */

138   public static <A,B,C,R> Component<R> map(Creator<A> c1, Creator<B> c2, Creator<C> c3,
139       Map3<A,B,C,R> m){
140     return new MappedComponent3<A,B,C,R>(c1, c2, c3, m)
141     .label();
142   }
143   /**
144    * Creates a Component object which takes instances
145    * created from four other Creator object and transforms them
146    * to a new Object.
147    * @param c1 the first Creator object.
148    * @param c2 the second Creator object.
149    * @param c3 the third Creator object.
150    * @param c4 the fourth Creator object.
151    * @param m the Map4 object to transform.
152    * @return the Component object.
153    */

154   public static <A,B,C,D,R> Component<R> map(Creator<A> c1, Creator<B> c2, Creator<C> c3,
155       Creator<D> c4, Map4<A,B,C,D,R> m){
156     return new MappedComponent4<A,B,C,D,R>(c1, c2, c3, c4, m)
157     .label();
158   }
159   /**
160    * Creates a Component object which takes instances
161    * created from five other Creator object and transforms them
162    * to a new Object.
163    * @param c1 the first Creator object.
164    * @param c2 the second Creator object.
165    * @param c3 the third Creator object.
166    * @param c4 the fourth Creator object.
167    * @param c5 the fifth Creator object.
168    * @param m the Map5 object to transform.
169    * @return the Component object.
170    */

171   public static <A,B,C,D,E,R> Component<R> map(Creator<A> c1, Creator<B> c2, Creator<C> c3,
172       Creator<D> c4, Creator<E> c5, Map5<A,B,C,D,E,R> m){
173     return new MappedComponent5<A,B,C,D,E,R>(c1, c2, c3, c4, c5, m)
174     .label();
175   }
176   
177   /**
178    * The monadic mplus operation,
179    * when the first component fails with resolution error,
180    * an alternative component is tried instead.
181    * @param c1 the first creator.
182    * @param c2 the alternative creator.
183    * @return the new Component.
184    */

185   public static <T> Component<T> mplus(Creator<T> c1, Creator<T> c2){
186     //return new MplusComponent(c1, c2).label();
187
return recover(c1,
188         onException(ComponentResolutionException.class, c2));
189   }
190   /**
191    * Create a Component that always fails.
192    * @param msg the error message when fails.
193    * @return the new Component object.
194    */

195   public static Component fail(String JavaDoc msg){
196     return new FailComponent(msg).label();
197   }
198   /**
199    * Create a monadic mzero Component that always fails.
200    * @return the new Component object.
201    */

202   public static Component mzero(){
203     return _zero;
204   }
205   
206   /**
207    * Create a new Component object that will recover errors
208    * happened from the provided Component.
209    * @param c1 the Component to recover.
210    * @param r the Recovery object.
211    * @return the new Component object.
212    */

213   public static <T> Component<T> recover(Creator<T> c1, Recovery<T> r){
214     return new RecoveredComponent<T>(c1, r).label();
215   }
216   /**
217    * Create a Recovery object that will
218    * recover from a provided exception type
219    * by returning an alternative Creator object.
220    * @param type the exception type.
221    * @param creator the alternative Creator object.
222    * @return the new Recovery object.
223    */

224   public static <T> Recovery<T> onException(Class JavaDoc<? extends Throwable JavaDoc> type, Creator<T> creator){
225     return new OnException<T>(creator, type);
226   }
227
228   /**
229    * Create a staged component.
230    * On instantiation, it first creates the base object using one component,
231    * then the {@link jfun.yan.ComponentBinder} object is used
232    * to do certain side-effect to complete the work.
233    * The object created by the base component is finally returned as the instance.
234    * <br>
235    * Bean component, for example, is an application of staged component.
236    * <br>
237    * The {@link jfun.yan.ComponentBinder} object also takes care of verification
238    * of the base component type.
239    * @param c1 the base component.
240    * @param binder the ComponentBinder object to do the side effect.
241    * @return the new Component object.
242    */

243   public static <T> Component<T> followedBy(Component<T> c1, ComponentBinder<T,?> binder){
244     return new StagedComponent<T>(c1, binder).guard()
245     ;
246   }
247   /**
248    * Create a staged component.
249    * On instantiation, it first creates the base object using one component,
250    * then the {@link jfun.yan.Binder} object is used
251    * to do certain side-effect to complete the work.
252    * The object created by the base component is finally returned as the instance.
253    * <br>
254    * Bean component, for example, is an application of staged component.
255    * @param c1 the base component.
256    * @param binder the Binder object to do the side effect.
257    * @return the new Component object.
258    */

259   public static <T> Component<T> followedBy(Component<T> c1, Binder<T,?> binder){
260     return followedBy(c1, toComponentBinder(binder));
261   }
262   /**
263    * Create a staged component.
264    * On instantiation, it first creates the base object using one component,
265    * then another Creator object is used
266    * to do certain side-effect to complete the work.
267    * The object created by the base component is finally returned as the instance.
268    * <br>
269    * Bean component, for example, is an application of staged component.
270    * @param c1 the base component.
271    * @param c2 the Component object to do the side-effect.
272    * @return the new Component object.
273    */

274   public static <T> Component<T> followedBy(Component<T> c1, Creator<?> c2){
275     return followedBy(c1, (ComponentBinder<T,?>)toVerificationBinder(c2));
276   }
277   /*
278   public static Component followedBy(
279       final Component c1, final Creator c2){
280     return followedBy(c1, toVerificationBinder(c2));
281   }*/

282
283   /**
284    * Create a ComponentBinder object that always
285    * returns the same object passed in.
286    * @return the ComponentBinder object.
287    */

288   public static ComponentBinder pass(){
289     return _pass;
290   }
291   /**
292    * To create a ComponentBinder object that instantiates
293    * the Creator object created from the previous step.
294    * @return the ComponentBinder object.
295    */

296   public static ComponentBinder instantiator(){
297     return _instantiator;
298   }
299   /**
300    * Convert a Binder object to a ComponentBinder object
301    * by making the verification do nothing.
302    * @param b the Binder object.
303    * @return the ComponentBinder object,
304    * or the parameter b if it is already a ComponentBinder.
305    */

306   public static <From,To> ComponentBinder<From,To> toComponentBinder(final Binder<From,To> b){
307     if(b instanceof ComponentBinder){
308       return (ComponentBinder<From,To>)b;
309     }
310     return new DynamicBinder<From,To>(b);
311   }
312
313   /**
314    * Create a ComponentBinder object that
315    * uses a Creator object for instantiation and verification
316    * regardless of the input.
317    * @param c the Component object.
318    * @return the ComponentBinder object.
319    */

320   public static <x,T> ComponentBinder<x, T> toVerificationBinder(final Creator<T> c){
321     return new ConstComponentBinder(c);
322   }
323   
324   /**
325    * Create a Component object according to the boolean value returned from another Component.
326    * @param cond the Component returning a Boolean value.
327    * @param a the Component when the condition is true.
328    * @param b the Component when the condition is false;
329    * @return the conditional Component.
330    */

331   public static <T> Component<T> ifelse(Creator<Boolean JavaDoc> cond,
332       final Component<T> a, final Component<T> b){
333     return bind(cond, new Binder<Boolean JavaDoc,T>(){
334       public Creator<T> bind(Boolean JavaDoc c){
335         if(c instanceof Boolean JavaDoc){
336           final boolean v = c.booleanValue();
337           return v?a:b;
338         }
339         else{
340           throw new IllegalArgumentException JavaDoc("boolean expected for ifelse");
341         }
342       }
343     }).label("ifelse");
344   }
345   private static final Component _zero = fail("mzero");
346   private static ComponentBinder getPass(final String JavaDoc name){
347     return new ComponentBinder(){
348       public Creator bind(Object JavaDoc obj){
349         return Components.value(obj);
350       }
351       public Verifiable verify(Class JavaDoc t){
352         return verifyAs(t);
353       }
354       public Class JavaDoc bindType(Class JavaDoc t){
355         return t;
356       }
357       public String JavaDoc toString(){
358         return name;
359       }
360     };
361   }
362   private static final ComponentBinder _pass = getPass("pass");
363   private static ComponentBinder getInstantiator(final String JavaDoc name, final Class JavaDoc target_type){
364     return new ComponentBinder(){
365       public Creator bind(Object JavaDoc obj){
366         if(obj instanceof Creator){
367           return (Creator)obj;
368         }
369         else{
370           return Components.value(obj);
371         }
372       }
373       public Verifiable verify(Class JavaDoc t){
374         checkCreator(t);
375         return verifyAs(target_type);
376       }
377       public Class JavaDoc bindType(Class JavaDoc t){
378         return target_type;
379       }
380       private void checkCreator(Class JavaDoc t){
381         if(!t.isAssignableFrom(Creator.class)&&!Creator.class.isAssignableFrom(t)){
382           //stupid cast. void.class is not allowed because it indicates null.
383
throw new TypeMismatchException(Creator.class, t);
384         }
385       }
386       public String JavaDoc toString(){
387         return name;
388       }
389     };
390   }
391   private static final ComponentBinder _instantiator = getInstantiator("instantiator", Object JavaDoc.class);
392   /**
393    * Create a Verifiable object that always succeed with a given result type.
394    * @param t the result type.
395    * @return the Verifiable object.
396    */

397   public static Verifiable verifyAs(final Class JavaDoc t){
398     return new Verifiable(){
399       public Class JavaDoc verify(Dependency dep){
400         return t;
401       }
402       public String JavaDoc toString(){
403         return "verifyAs " + jfun.util.Misc.getTypeName(t);
404       }
405     };
406   }
407 }
408
Popular Tags