You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2003/08/22 00:42:47 UTC
cvs commit: jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io BeanReader.java BeanRuleSet.java
rdonkin 2003/08/21 15:42:47
Modified: betwixt/src/java/org/apache/commons/betwixt
BindingConfiguration.java
betwixt/src/java/org/apache/commons/betwixt/expression
Context.java
betwixt/src/java/org/apache/commons/betwixt/io
BeanReader.java BeanRuleSet.java
Log:
Refactored read bean creation into chain of independet creators. It can now be extended by users.
Revision Changes Path
1.2 +33 -6 jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/BindingConfiguration.java
Index: BindingConfiguration.java
===================================================================
RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/BindingConfiguration.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- BindingConfiguration.java 31 Jul 2003 21:35:42 -0000 1.1
+++ BindingConfiguration.java 21 Aug 2003 22:42:47 -0000 1.2
@@ -90,6 +90,8 @@
/** Converts objects <-> strings */
private ObjectStringConverter objectStringConverter;
+ private String classNameAttribute = "className";
+
/**
* Constructs a BindingConfiguration with default properties.
*/
@@ -118,7 +120,7 @@
/**
* Sets the Object <-> String converter.
- * @param the ObjectStringConverter to be used, not null
+ * @param objectStringConverter the ObjectStringConverter to be used, not null
*/
public void setObjectStringConverter(ObjectStringConverter objectStringConverter) {
this.objectStringConverter = objectStringConverter;
@@ -144,4 +146,29 @@
public void setMapIDs(boolean mapIDs) {
this.mapIDs = mapIDs;
}
+
+ /**
+ * The name of the attribute which can be specified in the XML to override the
+ * type of a bean used at a certain point in the schema.
+ *
+ * <p>The default value is 'className'.</p>
+ *
+ * @return The name of the attribute used to overload the class name of a bean
+ */
+ public String getClassNameAttribute() {
+ return classNameAttribute;
+ }
+
+ /**
+ * Sets the name of the attribute which can be specified in
+ * the XML to override the type of a bean used at a certain
+ * point in the schema.
+ *
+ * <p>The default value is 'className'.</p>
+ *
+ * @param classNameAttribute The name of the attribute used to overload the class name of a bean
+ */
+ public void setClassNameAttribute(String classNameAttribute) {
+ this.classNameAttribute = classNameAttribute;
+ }
}
1.6 +45 -8 jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/expression/Context.java
Index: Context.java
===================================================================
RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/expression/Context.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Context.java 31 Jul 2003 21:40:58 -0000 1.5
+++ Context.java 21 Aug 2003 22:42:47 -0000 1.6
@@ -127,12 +127,22 @@
*
* @param bean evaluate expressions against this bean
* @param log log to this logger
- * @param converter not null
+ * @param bindingConfiguration not null
*/
public Context(Object bean, Log log, BindingConfiguration bindingConfiguration) {
this( bean, new HashMap(), log, bindingConfiguration );
}
+ /**
+ * Construct a cloned context.
+ * The constructed context should share bean, variables, log and binding configuration.
+ * @param context duplicate the attributes of this bean
+ */
+ public Context( Context context ) {
+ this(context.bean, context.variables, context.log, context.bindingConfiguration);
+ }
+
+
/** Convenience constructor sets evaluted bean, context variables and log.
*
* @param bean evaluate expressions against this bean
@@ -149,7 +159,7 @@
* @param bean evaluate expressions against this bean
* @param variables context variables
* @param log log to this logger
- * @param converter not null
+ * @param bindingConfiguration not null
*/
public Context(Object bean, Map variables, Log log, BindingConfiguration bindingConfiguration) {
this.bean = bean;
@@ -164,7 +174,9 @@
* @return new Context with new bean but shared variables
*/
public Context newContext(Object newBean) {
- return new Context(newBean, variables, log, bindingConfiguration);
+ Context context = new Context(this);
+ context.setBean( newBean );
+ return context;
}
/**
@@ -252,5 +264,30 @@
*/
public boolean getMapIDs() {
return bindingConfiguration.getMapIDs();
+ }
+
+ /**
+ * The name of the attribute which can be specified in the XML to override the
+ * type of a bean used at a certain point in the schema.
+ *
+ * <p>The default value is 'className'.</p>
+ *
+ * @return The name of the attribute used to overload the class name of a bean
+ */
+ public String getClassNameAttribute() {
+ return bindingConfiguration.getClassNameAttribute();
+ }
+
+ /**
+ * Sets the name of the attribute which can be specified in
+ * the XML to override the type of a bean used at a certain
+ * point in the schema.
+ *
+ * <p>The default value is 'className'.</p>
+ *
+ * @param classNameAttribute The name of the attribute used to overload the class name of a bean
+ */
+ public void setClassNameAttribute(String classNameAttribute) {
+ bindingConfiguration.setClassNameAttribute( classNameAttribute );
}
}
1.15 +32 -10 jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanReader.java
Index: BeanReader.java
===================================================================
RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanReader.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- BeanReader.java 31 Jul 2003 21:40:58 -0000 1.14
+++ BeanReader.java 21 Aug 2003 22:42:47 -0000 1.15
@@ -72,6 +72,9 @@
import org.apache.commons.betwixt.ElementDescriptor;
import org.apache.commons.betwixt.XMLBeanInfo;
import org.apache.commons.betwixt.XMLIntrospector;
+import org.apache.commons.betwixt.io.read.ReadConfiguration;
+import org.apache.commons.betwixt.io.read.ReadContext;
+
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.logging.Log;
@@ -96,6 +99,8 @@
private Set registeredClasses = new HashSet();
/** Dynamic binding configuration settings */
private BindingConfiguration bindingConfiguration = new BindingConfiguration();
+ /** Reading specific configuration settings */
+ private ReadConfiguration readConfiguration = new ReadConfiguration();
/**
* Construct a new BeanReader with default properties.
@@ -328,11 +333,27 @@
/**
* Sets the dynamic configuration setting to be used for bean reading.
- * @param the BindingConfiguration settings, not null
+ * @param bindingConfiguration the BindingConfiguration settings, not null
*/
- public void setBindingConfiguration(BindingConfiguration bindingConfiguration) {
+ public void setBindingConfiguration( BindingConfiguration bindingConfiguration ) {
this.bindingConfiguration = bindingConfiguration;
}
+
+ /**
+ * Gets read specific configuration details.
+ * @return the ReadConfiguration, not null
+ */
+ public ReadConfiguration getReadConfiguration() {
+ return readConfiguration;
+ }
+
+ /**
+ * Sets the read specific configuration details.
+ * @param readConfiguration not null
+ */
+ public void setReadConfiguration( ReadConfiguration readConfiguration ) {
+ this.readConfiguration = readConfiguration;
+ }
// Implementation methods
//-------------------------------------------------------------------------
@@ -356,15 +377,16 @@
path ,
elementDescriptor,
beanClass,
- makeContext( null ));
+ makeContext());
addRuleSet( ruleSet );
}
/**
* Factory method for new contexts.
* Ensure that they are correctly configured.
+ * @return the ReadContext created, not null
*/
- private Context makeContext(Object bean) {
- return new Context( bean, log, bindingConfiguration );
+ private ReadContext makeContext() {
+ return new ReadContext( log, bindingConfiguration, readConfiguration );
}
}
1.11 +82 -114 jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java
Index: BeanRuleSet.java
===================================================================
RCS file: /home/cvs/jakarta-commons/betwixt/src/java/org/apache/commons/betwixt/io/BeanRuleSet.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- BeanRuleSet.java 11 Aug 2003 23:52:20 -0000 1.10
+++ BeanRuleSet.java 21 Aug 2003 22:42:47 -0000 1.11
@@ -73,9 +73,14 @@
import org.apache.commons.betwixt.XMLBeanInfo;
import org.apache.commons.betwixt.XMLIntrospector;
import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
-import org.apache.commons.betwixt.expression.Context;
import org.apache.commons.betwixt.expression.MethodUpdater;
import org.apache.commons.betwixt.expression.Updater;
+import org.apache.commons.betwixt.io.read.ReadContext;
+import org.apache.commons.betwixt.io.read.ReadConfiguration;
+import org.apache.commons.betwixt.io.read.BeanCreationChain;
+import org.apache.commons.betwixt.io.read.ElementMapping;
+
+
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSet;
@@ -110,8 +115,9 @@
private ElementDescriptor baseElementDescriptor;
/** The bean based */
private Class baseBeanClass;
- /** The (empty) base context from which all Contexts with beans are (directly or indirectly) obtained */
- private Context baseContext;
+ /** The (empty) base context from which all Contexts
+ with beans are (directly or indirectly) obtained */
+ private ReadContext baseContext;
/** allows an attribute to be specified to overload the types of beans used */
private String classNameAttribute = "className";
@@ -123,7 +129,7 @@
* @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
* @param baseBeanClass the <code>Class</code> whose mapping rules will be created
* @param matchIDs should ID/IDREFs be used to match beans?
- * @deprecated use constructor which takes a base Context
+ * @deprecated use constructor which takes a ReadContext instead
*/
public BeanRuleSet(
XMLIntrospector introspector,
@@ -137,7 +143,7 @@
this.baseBeanClass = baseBeanClass;
BindingConfiguration bindingConfiguration = new BindingConfiguration();
bindingConfiguration.setMapIDs( matchIDs );
- baseContext = new Context(null, log , bindingConfiguration);
+ baseContext = new ReadContext( log , bindingConfiguration, new ReadConfiguration() );
}
/**
@@ -149,20 +155,43 @@
* @param baseBeanClass the <code>Class</code> whose mapping rules will be created
* @param baseContext the root Context that bean carrying Contexts should be obtained from,
* not null
+ * @deprecated use the constructor which takes a ReadContext instead
*/
public BeanRuleSet(
XMLIntrospector introspector,
String basePath,
ElementDescriptor baseElementDescriptor,
Class baseBeanClass,
- Context baseContext) {
+ Context context) {
this.introspector = introspector;
this.basePath = basePath;
this.baseElementDescriptor = baseElementDescriptor;
this.baseBeanClass = baseBeanClass;
- this.baseContext = baseContext;
+ this.baseContext = new ReadContext( context, new ReadConfiguration() );
}
+ /**
+ * Base constructor.
+ *
+ * @param introspector the <code>XMLIntrospector</code> used to introspect
+ * @param basePath specifies the (Digester-style) path under which the rules will be attached
+ * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
+ * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
+ * @param baseContext the root Context that bean carrying Contexts should be obtained from,
+ * not null
+ */
+ public BeanRuleSet(
+ XMLIntrospector introspector,
+ String basePath,
+ ElementDescriptor baseElementDescriptor,
+ Class baseBeanClass,
+ ReadContext baseContext) {
+ this.introspector = introspector;
+ this.basePath = basePath;
+ this.baseElementDescriptor = baseElementDescriptor;
+ this.baseBeanClass = baseBeanClass;
+ this.baseContext = baseContext;
+ }
/**
* The name of the attribute which can be specified in the XML to override the
@@ -173,7 +202,7 @@
* @return The name of the attribute used to overload the class name of a bean
*/
public String getClassNameAttribute() {
- return classNameAttribute;
+ return baseContext.getClassNameAttribute();
}
/**
@@ -184,11 +213,11 @@
* <p>The default value is 'className'.</p>
*
* @param classNameAttribute The name of the attribute used to overload the class name of a bean
+ * @deprecated set the <code>ReadContext</code> property instead
*/
public void setClassNameAttribute(String classNameAttribute) {
- this.classNameAttribute = classNameAttribute;
+ baseContext.setClassNameAttribute(classNameAttribute);
}
-
//-------------------------------- Ruleset implementation
@@ -212,7 +241,8 @@
if (log.isTraceEnabled()) {
log.trace("Adding rules to:" + digester);
}
- ReadContext readContext = new ReadContext( digester );
+
+ ReadingContext readContext = new ReadingContext( digester );
}
/**
@@ -221,9 +251,8 @@
*
* <p>When an instance is constructed, rules are created and added to digester.</p>
*/
- private class ReadContext {
- /** The beans created by rules in this context indexed by id */
- private Map beansById = new HashMap();
+ private class ReadingContext {
+
/** The rules in this context indexed by path */
private Map rulesByPath = new HashMap();
@@ -232,10 +261,14 @@
* @param digester the <code>Digester</code>
* to which the bean mapping rules will be added
*/
- ReadContext(Digester digester) {
-
- BeanRule rule = new BeanRule( basePath + "/" , baseElementDescriptor, baseBeanClass );
- addRule( basePath, rule , baseElementDescriptor, rule.context );
+ ReadingContext(Digester digester) {
+ ReadContext context = new ReadContext( baseContext );
+ // if the classloader is not set, set to the digester classloader
+ if ( context.getClassLoader() == null ) {
+ context.setClassLoader( digester.getClassLoader() );
+ }
+ BeanRule rule = new BeanRule( basePath + "/" , baseElementDescriptor, baseBeanClass, context );
+ addRule( basePath, rule , baseElementDescriptor, context );
if ( log.isDebugEnabled() ) {
log.debug( "Added root rule to path: " + basePath + " class: " + baseBeanClass );
@@ -262,7 +295,7 @@
private void addChildRules(
String prefix,
ElementDescriptor currentDescriptor,
- Context context ) {
+ ReadContext context ) {
if (log.isTraceEnabled()) {
log.trace("Adding child rules for " + currentDescriptor + "@" + prefix);
@@ -425,12 +458,12 @@
*
* @param path digester path where this rule will be attached
* @param childDescriptor update this <code>ElementDescriptor</code> with the body text
- * @param context the <code>Context</code> against which the elements will be evaluated
+ * @param context the <code>ReadContext</code> against which the elements will be evaluated
*/
void addPrimitiveTypeRule(
String path,
final ElementDescriptor childDescriptor,
- final Context context) {
+ final ReadContext context) {
Rule rule = new Rule() {
public void body(String text) throws Exception {
@@ -445,9 +478,9 @@
*
* @param path digester path where this rule will be attached
* @param elementDescriptor update this <code>ElementDescriptor</code> with the body text
- * @param context the <code>Context</code> against which the elements will be evaluated
+ * @param context the <code>ReadContext</code> against which the elements will be evaluated
*/
- private void addRule( String path, ElementDescriptor elementDescriptor, Context context ) {
+ private void addRule( String path, ElementDescriptor elementDescriptor, ReadContext context ) {
BeanRule rule = new BeanRule( path + '/', elementDescriptor, context );
addRule( path, rule, elementDescriptor, context );
}
@@ -459,14 +492,14 @@
* @param rule the <code>Rule</code> to add
* @param elementDescriptor the <code>ElementDescriptor</code>
* associated with this rule
- * @param context the <code>Context</code> against which the elements
+ * @param context the <code>ReadContext</code> against which the elements
* will be evaluated
*/
private void addRule(
String path,
Rule rule,
ElementDescriptor elementDescriptor,
- Context context) {
+ ReadContext context) {
if ( add( path, rule ) ) {
// stop infinite recursion by allowing only one rule per path
addChildRules( path + '/', elementDescriptor, context );
@@ -512,7 +545,7 @@
/** The descriptor of this element */
private ElementDescriptor descriptor;
/** The Context used when evaluating Updaters */
- private Context context;
+ private ReadContext context;
/** In this begin-end loop did we actually create a new bean */
private boolean createdBean;
/** The type of the bean to create */
@@ -527,26 +560,8 @@
* @param descriptor the <code>ElementDescriptor</code> describing the element mapped
* @param beanClass the <code>Class</code> to be created
*/
- public BeanRule( ElementDescriptor descriptor, Class beanClass ) {
- this( descriptor.getQualifiedName() + "/", descriptor, beanClass );
- }
-
- /**
- * Construct a rule for given bean at given path.
- *
- * @param pathPrefix the digester style path
- * @param descriptor the <code>ElementDescriptor</code> describing the element mapped
- * @param beanClass the <code>Class</code> to be created
- */
- public BeanRule(
- String pathPrefix,
- ElementDescriptor descriptor,
- Class beanClass ) {
- this(
- pathPrefix,
- descriptor,
- beanClass,
- baseContext );
+ public BeanRule( ElementDescriptor descriptor, Class beanClass, ReadContext context ) {
+ this( descriptor.getQualifiedName() + "/", descriptor, beanClass, context );
}
/**
@@ -559,7 +574,7 @@
public BeanRule(
String pathPrefix,
ElementDescriptor descriptor,
- Context context ) {
+ ReadContext context ) {
this(
pathPrefix,
descriptor,
@@ -579,7 +594,7 @@
String pathPrefix,
ElementDescriptor descriptor,
Class beanClass,
- Context context ) {
+ ReadContext context ) {
this.descriptor = descriptor;
this.context = context;
this.beanClass = beanClass;
@@ -601,7 +616,7 @@
*
* @param attributes The attribute list of this element
*/
- public void begin(Attributes attributes) {
+ public void begin(String namespace, String name, Attributes attributes) {
log.debug( "Called with descriptor: " + descriptor
+ " propertyType: " + descriptor.getPropertyType() );
@@ -626,7 +641,7 @@
Object instance = null;
if ( beanClass != null ) {
- instance = createBean(attributes);
+ instance = createBean( namespace, name, attributes );
if ( instance != null ) {
createdBean = true;
@@ -690,7 +705,7 @@
// XXX so i'm leaving this till later
String id = attributes.getValue( "id" );
if ( id != null ) {
- getBeansById().put( id, instance );
+ context.putBean( id, instance );
}
}
}
@@ -702,7 +717,7 @@
*
* @param text the String comprising all the body text
*/
- public void body(String text) {
+ public void body(String namespace, String name, String text) {
log.trace("Body with text " + text);
if ( digester.getCount() > 0 ) {
@@ -767,7 +782,7 @@
//
// Clear indexed beans so that we're ready to process next document
//
- beansById.clear();
+ baseContext.clearBeans();
}
@@ -780,66 +795,19 @@
* @param attributes the <code>Attributes</code> used to match <code>ID/IDREF</code>
* @return the created bean
*/
- protected Object createBean(Attributes attributes) {
- //
- // See if we've got an IDREF
- //
- // XXX This should be customizable but i'm not really convinced by
- // XXX the existing system
- // XXX maybe it's going to have to change so i'll use 'idref' for nows
- //
+ protected Object createBean( String namespace, String name, Attributes attributes ) {
+ // todo: recycle element mappings
+ ElementMapping mapping = new ElementMapping();
+ mapping.setType( beanClass );
+ mapping.setNamespace( namespace );
+ mapping.setName( name );
+ mapping.setAttributes( attributes );
- /**
- * @todo this is a duplicate of the code in BeanCreateRule
- * we should try refactor to some common place
- */
- if ( context.getMapIDs() ) {
- String idref = attributes.getValue( "idref" );
- if ( idref != null ) {
- // XXX need to check up about ordering
- // XXX this is a very simple system that assumes that
- // XXX id occurs before idrefs
- // XXX would need some thought about how to implement a fuller system
- log.trace( "Found IDREF" );
- Object bean = getBeansById().get( idref );
- if ( bean != null ) {
- if (log.isTraceEnabled()) {
- log.trace( "Matched bean " + bean );
- }
- return bean;
- }
- log.trace( "No match found" );
- }
- }
+ Object newInstance = context.getBeanCreationChain().create( mapping, context );
- Class theClass = beanClass;
- try {
- String className = attributes.getValue(classNameAttribute);
- if (className != null) {
- // load the class we should instantiate
- theClass = getDigester().getClassLoader().loadClass(className);
- }
- if (log.isTraceEnabled()) {
- log.trace( "Creating instance of " + theClass );
- }
- return theClass.newInstance();
-
- } catch (Exception e) {
- log.warn( "Could not create instance of type: " + theClass.getName() );
- log.debug( "Create new instance failed: ", e );
- return null;
- }
+ return newInstance;
}
-
- /**
- * Get the map used to index beans (previously read in) by id.
- *
- * @return map indexing beans created by id
- */
- protected Map getBeansById() {
- return beansById;
- }
/**
* Return something meaningful for logging.