1 package jfun.yan.xml.nuts; 2 3 import java.beans.IntrospectionException ; 4 import java.util.ArrayList ; 5 import java.util.HashMap ; 6 import java.util.HashSet ; 7 import java.util.Iterator ; 8 import java.util.List ; 9 import java.util.Map ; 10 import java.util.Set ; 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 34 public abstract class ArgumentsAndPropertiesNut extends ComponentNut { 35 private Class [] param_types; 36 private Object [] args; 37 private Args sub_args; 38 private final java.util.List arglist = new ArrayList (); 39 private final HashMap table = new HashMap (); 40 private int max_arg_num = -1; 41 private String 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 54 public int getMaxArgsCount(){ 55 return max_arg_num; 56 } 57 public Object [] getArgs() { 58 return args; 59 } 60 public List getArgList(){ 61 return arglist; 62 } 63 public void setArgs(Object [] args) { 64 this.args = args; 65 withMaxNum(args.length); 66 } 67 68 public Class [] getParameterTypes() { 69 return param_types; 70 } 71 72 public void setParams(Class [] param_types) { 73 this.param_types = param_types; 74 } 75 76 public void addArgs(Args a){ 77 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 type, Object obj){ 102 if(obj instanceof Creator){ 103 return Components.adapt((Creator)obj); 104 } 105 else return NutsUtils.asComponent(convert(type, obj)); 106 } 107 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 indmap = new HashMap (); 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 (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 type) { 129 if(args!=null && ind < args.length){ 130 return toComponent(type, args[ind]); 131 } 132 final Arg a = (Arg)indmap.get(new Integer (ind)); 133 if(a!=null){ 134 Component val = a.getVal(type); 135 if(val == null){ 136 val = Components.value(null); } 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 [] prop_names; 162 private String prop_autowire_str; 163 private final ArrayList prop_elements = new ArrayList (); 164 private PropertyBinder prop_autowire_mode; 165 private boolean optional_properties = false; 166 private boolean validate_property_names = true; 167 168 172 public boolean containsExplicitProperty(String key){ 173 if(prop_names!=null){ 174 for(int i=0; i<prop_names.length; i++){ 175 final String 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 PROP_TAG_NAME = "prop"; 197 public void setProps(Map props){ 198 int i=0; 199 for(Iterator it = props.keySet().iterator(); it.hasNext();i++){ 200 final Object key = it.next(); 201 final Object 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 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 228 } 229 232 public PropertyBinder getAutoWire(){ 233 return prop_autowire_mode; 234 } 235 public void setProperty_names(String [] 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 [] 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 257 protected Component defineBean(Component c, boolean isAll) 258 throws IntrospectionException { 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 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 return c.bean(); 278 } 279 else{ 280 return c; 282 } 283 } 284 288 protected boolean isBeanByDefault(){ 289 return false; 290 } 291 297 protected Component applyProperties(Component component){ 298 final boolean isAll = isAllProperties(); 299 final HashMap valnames = checkPropertyNames(isAll); 300 if(valnames==null && (prop_names==null || prop_names.length==0) 301 && !isBeanByDefault()){ 302 return component; 304 } 305 try{ 306 component = defineBean(component, isAll); 307 } 308 catch(IntrospectionException e){ 309 throw raise(e); 310 } 311 if(!prop_elements.isEmpty()){ 312 component = component.bindProperties(new PropertyBinder(){ 313 public Creator bind(Class component_type, Object key, Class 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); } 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 349 protected Component informAwares(Component c){ 350 return c; 351 } 352 356 public PropertyBinder getPropertyAutowireMode(){ 357 if(prop_autowire_str==null){ 358 return getPropertyWiring(null); 360 } 361 else return prop_autowire_mode; 362 } 363 367 public ParameterBinder getParameterAutowireMode(){ 368 if(param_autowire_str==null){ 369 return getParameterWiring(null); 370 } 371 else return param_autowire_mode; 372 } 373 376 public boolean isAllProperties(){ 377 return(prop_names!=null && prop_names.length==1 378 && Constants.WILDCARD.equals(prop_names[0])); 379 } 380 381 388 private HashMap checkPropertyNames(final boolean isAll){ 389 HashSet prop_name_set = null; 390 if(!isAll && prop_names!=null){ 391 prop_name_set = new HashSet (prop_names.length); 392 for(int i=0; i<prop_names.length; i++){ 393 final String 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 valnames = new HashMap (sz); 403 for(int i=0; i<sz; i++){ 404 final Prop prop = (Prop)prop_elements.get(i); 405 final String 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 if(prop_names==null){ 421 prop_names = new String [valnames.size()]; 422 valnames.keySet().toArray(prop_names); 423 } 424 } 425 return valnames; 426 } 427 432 protected Component decorateComponent(Component component){ 433 return applyProperties(applyArguments(informAwares(component))); 434 } 435 } 436 | Popular Tags |