package jfun.yan;
import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import jfun.util.beans.BeanType;
/**
* The default PropertiesInjector implementation that uses java.beans introspection
* mechanism and injects properties by property names.
* <p>
* @author Ben Yu
* Dec 16, 2005 1:16:32 PM
*/
public class DefaultPropertiesInjector implements PropertiesInjector {
/*The meta information of the bean. null if unknown*/
private final BeanType btype;
/*The set of properties to set, null if every property is needed*/
private final java.util.Set props;
/**
* Create an instance of PropertiesInjector.
* If type is null, dynamic binding will be used.
* @param type the bean class.
* @return the instance.
* @throws IntrospectionException
*/
public static PropertiesInjector instance(Class type)
throws IntrospectionException{
final BeanType bt =jfun.yan.util.Utils.toBeanType(type);
return new DefaultPropertiesInjector(bt, null);
}
/**
* Create an instance of PropertiesInjector.
* @param type the bean class. null if unknown.
* @param props the set of properties to set. null indicates all.
* @return the new component that handles property setting.
* @throws IntrospectionException
*/
public static PropertiesInjector instance(final Class type, final java.util.Set props)
throws IntrospectionException{
final BeanType bt = jfun.yan.util.Utils.toBeanType(type);
checkIncludes(bt, props);
return new DefaultPropertiesInjector(bt, props);
}
/**
* Create an instance of DefaultPropertiesInjector using a BeanType object.
* @param btype the BeanType object.
* @param props the property names. Note, the constructor does not validate the property names.
*/
public DefaultPropertiesInjector(final BeanType btype,
final Set props){
this.btype = btype;
this.props = props;
}
//make sure the property names contained in the set are all valid properties.
private static void checkIncludes(BeanType btype, java.util.Set s2){
//skip checking for dynamic binding.
if(btype==null) return;
for(Iterator it=s2.iterator(); it.hasNext();){
final Object name = it.next();
final java.beans.PropertyDescriptor desc =
btype.getPropertyDescriptor(""+name);
if(desc==null){
throw new IllegalPropertyNameException(btype.getType(), ""+name);
}
else{
if(desc.getWriteMethod()==null){
if(desc instanceof IndexedPropertyDescriptor){
final IndexedPropertyDescriptor idesc = (IndexedPropertyDescriptor)desc;
if(idesc.getIndexedWriteMethod()!=null){
return;
}
}
throw new NonWritablePropertyException(btype.getType(), ""+name);
}
}
}
}
private BeanType obtainBeanType(Class type){
//dynamically get the bean type.
//if the bean type is not early bound,
//use the object type to dynamically create it.
if(btype!=null) return btype;
else{
return jfun.yan.util.Utils.toBeanType(type);
}
}
private Set getProperties(BeanType bt){
//if the property set is null, get all the properties
//or, if the bean type is dynamically bound,
//check the validity of the pre-defined property names.
if(props==null){
final HashSet props = new HashSet();
for(Iterator it=bt.getPropertyNames().iterator();it.hasNext();){
final String name = (String)it.next();
if(bt.getWriter(name)!=null||bt.getIndexedWriter(name)!=null){
props.add(name);
}
}
return props;
}
else{
if(this.btype==null){
//dynamic binding
checkIncludes(bt, props);
}
return props;
}
}
public void injectProperties(Object obj, Dependency dep){
//if empty properties, do nothing.
if(props!=null && props.isEmpty()) return;
if(obj==null){
throw new NullBeanObjectException("null component");
}
//dynamically resolve bean type and properties if necessary.
final Class objtype = obj.getClass();
final BeanType btype = obtainBeanType(objtype);
final Set props = getProperties(btype);
jfun.yan.util.Utils.injectProperties(btype, obj, props, dep);
}
public void verifyProperties(Class type, Dependency dep){
//dynamically resolve bean type and properties if necessary.
//the type cannot be null now.
final BeanType btype = obtainBeanType(type);
final Set props = getProperties(btype);
jfun.yan.util.Utils.verifyProperties(btype, props, dep);
}
public String toString(){
return "bean";
}
}