KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jfun > yan > xml > nuts > ArgumentsAndPropertiesNut


1 package jfun.yan.xml.nuts;
2
3 import java.beans.IntrospectionException JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.HashSet JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Map JavaDoc;
10 import java.util.Set JavaDoc;
11
12 import jfun.yan.Component;
13 import jfun.yan.Components;
14 import jfun.yan.Creator;
15 import jfun.yan.FilteredPropertiesInjector;
16 import jfun.yan.Monad;
17 import jfun.yan.ParameterBinder;
18 import jfun.yan.PropertyBinder;
19 import jfun.yan.function.Signature;
20 import jfun.yan.util.NameFilteredMemberPredicate;
21 import jfun.yan.xml.Constants;
22 import jfun.yan.xml.NutsUtils;
23 import jfun.yan.xml.nut.ComponentNut;
24 import jfun.yan.xml.nut.Nut;
25
26
27 /**
28  * Super class for any Nut that supports <arg>,
29  * <args>,<prop> and <props> sub-elements.
30  * <p>
31  * @author Ben Yu
32  * Nov 9, 2005 11:38:43 PM
33  */

34 public abstract class ArgumentsAndPropertiesNut extends ComponentNut {
35   private Class JavaDoc[] param_types;
36   private Object JavaDoc[] args;
37   private Args sub_args;
38   private final java.util.List JavaDoc arglist = new ArrayList JavaDoc();
39   private final HashMap JavaDoc table = new HashMap JavaDoc();
40   private int max_arg_num = -1;
41   private String JavaDoc param_autowire_str;
42   private ParameterBinder param_autowire_mode;
43   private void withMaxNum(int max){
44     if(max > max_arg_num){
45       this.max_arg_num = max;
46     }
47   }
48   /**
49    * Get the maximum number of the arguments.
50    * @return the value of the maximal 1-based ordinal position of
51    * arguments.
52    * -1 is returned if no "args" or "arg" is specified.
53    */

54   public int getMaxArgsCount(){
55     return max_arg_num;
56   }
57   public Object JavaDoc[] getArgs() {
58     return args;
59   }
60   public List JavaDoc getArgList(){
61     return arglist;
62   }
63   public void setArgs(Object JavaDoc[] args) {
64     this.args = args;
65     withMaxNum(args.length);
66   }
67
68   public Class JavaDoc[] getParameterTypes() {
69     return param_types;
70   }
71
72   public void setParams(Class JavaDoc[] param_types) {
73     this.param_types = param_types;
74   }
75
76   public void addArgs(Args a){
77     //checkSingleChild(a.getArgs());
78
checkDuplicate("args", this.args);
79     final int sz = arglist.size();
80     for(int i=0; i<sz; i++){
81       final Arg x = (Arg)arglist.get(i);
82       if(x.getInd() < a.getArgs().length){
83         throw x.raise("overlapping index: "+x.getInd());
84       }
85     }
86     this.args = a.getArgs();
87     this.sub_args = a;
88     withMaxNum(this.args.length);
89   }
90   public void addArg(Arg a){
91     if(args!=null && a.getInd()<args.length){
92       throw a.raise("overlapping index: "+a.getInd());
93     }
94     if(table.containsKey(a)){
95       throw a.raise("duplicate index: "+a.getInd());
96     }
97     table.put(a, a);
98     arglist.add(a);
99     withMaxNum(a.getInd()+1);
100   }
101   private final Component toComponent(Class JavaDoc type, Object JavaDoc obj){
102     if(obj instanceof Creator){
103       return Components.adapt((Creator)obj);
104     }
105     else return NutsUtils.asComponent(convert(type, obj));
106   }
107   /**
108    * Apply the specified parameters if any.
109    * @param component the component to apply parameters.
110    * @return the result.
111    */

112   protected Component applyArguments(Component component){
113     if(args != null){
114       Nut n = this;
115       if(sub_args!=null)
116         n = sub_args;
117       checkIndex(n, args.length-1);
118     }
119     final int sz = arglist.size();
120     final HashMap JavaDoc indmap = new HashMap JavaDoc();
121     for(int i=0; i<sz; i++){
122       final Arg a = (Arg)arglist.get(i);
123       checkIndex(a, a.getInd());
124       indmap.put(new Integer JavaDoc(a.getInd()), a);
125     }
126     if(args != null || !arglist.isEmpty()){
127       component = component.bindArguments(new ParameterBinder(){
128         public Creator bind(Signature src, int ind, Class JavaDoc type) {
129           if(args!=null && ind < args.length){
130             return toComponent(type, args[ind]);
131           }
132           final Arg a = (Arg)indmap.get(new Integer JavaDoc(ind));
133           if(a!=null){
134             Component val = a.getVal(type);
135             if(val == null){
136               val = Components.value(null);//Components.useArgument(src, ind, type);
137
}
138             final Component def = a.getDefault(type);
139             if(def!=null){
140               return Monad.mplus(val, def);
141             }
142             else return val;
143           }
144           return Components.useArgument(src, ind, type);
145         }
146       });
147     }
148     return component;
149   }
150   private void checkIndex(Nut nut, int ind){
151     if(param_types==null) return;
152     if(ind >= param_types.length){
153       throw nut.raise("argument index out of bounds: "+
154           ind);
155     }
156   }
157   
158   
159   
160   
161   private String JavaDoc[] prop_names;
162   private String JavaDoc prop_autowire_str;
163   private final ArrayList JavaDoc prop_elements = new ArrayList JavaDoc();
164   private PropertyBinder prop_autowire_mode;
165   private boolean optional_properties = false;
166   private boolean validate_property_names = true;
167
168   /**
169    * Is the a property explicitly specified?
170    * @param key the property key.
171    */

172   public boolean containsExplicitProperty(String JavaDoc key){
173     if(prop_names!=null){
174       for(int i=0; i<prop_names.length; i++){
175         final String JavaDoc name = prop_names[i];
176         if(name!=null && name.equals(key)){
177           return true;
178         }
179       }
180     }
181     final int sz = prop_elements.size();
182     for(int i=0; i<sz; i++){
183       final Prop prop = (Prop)prop_elements.get(i);
184       if(prop.getKey().equals(key)){
185         return true;
186       }
187     }
188     return false;
189   }
190   public boolean isValidate_property_names() {
191     return validate_property_names;
192   }
193   public void setValidate_property_names(boolean check_property_names) {
194     this.validate_property_names = check_property_names;
195   }
196   private static final String JavaDoc PROP_TAG_NAME = "prop";
197   public void setProps(Map JavaDoc props){
198     int i=0;
199     for(Iterator JavaDoc it = props.keySet().iterator(); it.hasNext();i++){
200       final Object JavaDoc key = it.next();
201       final Object JavaDoc val = props.get(key);
202       final Prop prop = new Prop();
203       prop.initNutEnvironment(this.getNutEnvironment());
204       prop.initTagLocation(this.getTagLocation());
205       prop.initSequenceNumber(i);
206       prop.initTagName(PROP_TAG_NAME);
207       prop.setKey(key.toString());
208       prop.setVal(val);
209       addProp(prop);
210     }
211   }
212   public void setAutowire(String JavaDoc mode){
213     this.prop_autowire_mode = getPropertyWiring(mode);
214     this.prop_autowire_str = mode;
215     this.param_autowire_mode = getParameterWiring(mode);
216     this.param_autowire_str = mode;
217     /*
218     PropertyBinder res = (PropertyBinder)auto_resolutions.get(strategy);
219     if(res == null){
220       if(!manual_names.containsKey(strategy)){
221         throw raise("unknown autowire strategy: "+ strategy);
222       }
223     }
224     else{
225       this.resolution = res;
226       this.resolution_name = strategy;
227     }*/

228   }
229   /**
230    * Get the specified autowire mode.
231    */

232   public PropertyBinder getAutoWire(){
233     return prop_autowire_mode;
234   }
235   public void setProperty_names(String JavaDoc[] names){
236     prop_names = names;
237     for(int i=0; i<prop_names.length; i++){
238       prop_names[i] = prop_names[i].replace('-', '_');
239     }
240   }
241   public String JavaDoc[] getPropertyNames(){
242     return prop_names;
243   }
244   public void addProp(Prop prop){
245     prop_elements.add(prop);
246   }
247   public void setOptional_properties(boolean flag){
248     this.optional_properties = flag;
249   }
250   /**
251    * Create a bean component and filter out the undesired properties.
252    * @param c the Component to inject properties.
253    * @param isAll whether we want all properties.
254    * @return the bean Component.
255    * @throws IntrospectionException when introspection failed.
256    */

257   protected Component defineBean(Component c, boolean isAll)
258   throws IntrospectionException JavaDoc{
259     if(isAll){
260       return c.bean();
261     }
262     else if(prop_names!=null){
263       if(validate_property_names){
264         return c.bean(prop_names);
265       }
266       else{
267         final Set JavaDoc propkeys = jfun.yan.util.Utils.toSet(
268             this.prop_names, "property name");
269         return Components.makeBean(c,
270             FilteredPropertiesInjector.instance(c.getType(),
271                 new NameFilteredMemberPredicate(propkeys))
272         );
273       }
274     }
275     else if(getPropertyAutowireMode()!=null){
276       //autowire
277
return c.bean();
278     }
279     else{
280       //manual wire
281
return c;
282     }
283   }
284   /**
285    * When no property names is specified, no property values are set,
286    * do we by default create a bean component?
287    */

288   protected boolean isBeanByDefault(){
289     return false;
290   }
291   /**
292    * Create bean component is any property name is specified or any property
293    * value is specified.
294    * @param component the component to apply properties.
295    * @return the result.
296    */

297   protected Component applyProperties(Component component){
298     final boolean isAll = isAllProperties();
299     final HashMap JavaDoc valnames = checkPropertyNames(isAll);
300     if(valnames==null && (prop_names==null || prop_names.length==0)
301         && !isBeanByDefault()){
302       //not wildcard and no property value specified.
303
return component;
304     }
305     try{
306       component = defineBean(component, isAll);
307     }
308     catch(IntrospectionException JavaDoc e){
309       throw raise(e);
310     }
311     if(!prop_elements.isEmpty()){
312       component = component.bindProperties(new PropertyBinder(){
313         public Creator bind(Class JavaDoc component_type, Object JavaDoc key, Class JavaDoc type) {
314           final Prop prop = (Prop)valnames.get(key);
315           if(prop!=null){
316             Component result = prop.getVal(type);
317             if(result==null){
318               result = Components.value(null);//Components.useProperty(component_type, key, type);
319
}
320             final Component def = prop.getDefault(type);
321             if(def!=null){
322               result = Monad.mplus(result, def);
323             }
324             else if(prop.isOptional()){
325               result = result.optional();
326             }
327             return result;
328           }
329           else return Components.useProperty(component_type, key, type);
330         }
331       });
332     }
333     if(optional_properties){
334       component = component.optionalProperties();
335     }
336     final PropertyBinder autowiring = getPropertyAutowireMode();
337     if(autowiring!=null){
338       component = component.bindProperties(autowiring);
339     }
340     return component;
341   }
342   /**
343    * In case the component implements any marker interface or has any specific
344    * method signature that is used to automatically set property, call them
345    * and set the corresponding properties.
346    * @param c the component.
347    * @return the Component object that informs the "aware"s.
348    */

349   protected Component informAwares(Component c){
350     return c;
351   }
352   /**
353    * Get the auto wire mode for properties.
354    * If not specified, use the global default setting.
355    */

356   public PropertyBinder getPropertyAutowireMode(){
357     if(prop_autowire_str==null){
358       //use default
359
return getPropertyWiring(null);
360     }
361     else return prop_autowire_mode;
362   }
363   /**
364    * Get the auto wire mode for parameters.
365    * If not specified, use the global default setting.
366    */

367   public ParameterBinder getParameterAutowireMode(){
368     if(param_autowire_str==null){
369       return getParameterWiring(null);
370     }
371     else return param_autowire_mode;
372   }
373   /**
374    * Is wildcard used?
375    */

376   public boolean isAllProperties(){
377     return(prop_names!=null && prop_names.length==1
378         && Constants.WILDCARD.equals(prop_names[0]));
379   }
380
381   /**
382    * Check the validity of property names and property values.
383    * populate property names if manual-wiring and property values are specified.
384    * @param isAll whether wildcard is used for property-names.
385    * @return null is returned if no property value is specified.
386    * the key-value map is returned for the specified property values.
387    */

388   private HashMap JavaDoc checkPropertyNames(final boolean isAll){
389     HashSet JavaDoc prop_name_set = null;
390     if(!isAll && prop_names!=null){
391       prop_name_set = new HashSet JavaDoc(prop_names.length);
392       for(int i=0; i<prop_names.length; i++){
393         final String JavaDoc name = prop_names[i];
394         if(prop_name_set.contains(name)){
395           throw raise("duplicate property name: "+name);
396         }
397         prop_name_set.add(name);
398       }
399     }
400     final int sz = prop_elements.size();
401     if(sz==0) return null;
402     final HashMap JavaDoc valnames = new HashMap JavaDoc(sz);
403     for(int i=0; i<sz; i++){
404       final Prop prop = (Prop)prop_elements.get(i);
405       final String JavaDoc key = prop.getKey();
406       if(valnames.containsKey(key)){
407         throw prop.raise("duplicate property key: "
408             + key);
409       }
410       if(this.validate_property_names && !isAll && prop_name_set!=null){
411         if(!prop_name_set.contains(key)){
412           throw prop.raise("unused property key: "
413               + key);
414         }
415       }
416       valnames.put(key, prop);
417     }
418     if(getPropertyAutowireMode() == null){
419       //manual wire
420
if(prop_names==null){
421         prop_names = new String JavaDoc[valnames.size()];
422         valnames.keySet().toArray(prop_names);
423       }
424     }
425     return valnames;
426   }
427   /**
428    * Apply arguments and then properties to the component.
429    * @param component the component to apply arguments and properties.
430    * @return the result.
431    */

432   protected Component decorateComponent(Component component){
433     return applyProperties(applyArguments(informAwares(component)));
434   }
435 }
436
Popular Tags