KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > betwixt > io > BeanRuleSet


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.betwixt.io;
18
19 import org.apache.commons.betwixt.BindingConfiguration;
20 import org.apache.commons.betwixt.ElementDescriptor;
21 import org.apache.commons.betwixt.XMLIntrospector;
22 import org.apache.commons.betwixt.expression.Context;
23 import org.apache.commons.betwixt.io.read.BeanBindAction;
24 import org.apache.commons.betwixt.io.read.MappingAction;
25 import org.apache.commons.betwixt.io.read.ReadConfiguration;
26 import org.apache.commons.betwixt.io.read.ReadContext;
27 import org.apache.commons.digester.Digester;
28 import org.apache.commons.digester.Rule;
29 import org.apache.commons.digester.RuleSet;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.xml.sax.Attributes JavaDoc;
33
34 /** <p>Sets <code>Betwixt</code> digestion rules for a bean class.</p>
35   *
36   * @author <a HREF="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
37   * @author <a HREF="mailto:martin@mvdb.net">Martin van den Bemt</a>
38   * @since 0.5
39   */

40 public class BeanRuleSet implements RuleSet {
41
42     /** Logger */
43     private static Log log = LogFactory.getLog(BeanRuleSet.class);
44
45     /**
46     * Set log to be used by <code>BeanRuleSet</code> instances
47     * @param aLog the <code>Log</code> implementation for this class to log to
48     */

49     public static void setLog(Log aLog) {
50         log = aLog;
51     }
52
53     /** The base path under which the rules will be attached */
54     private String JavaDoc basePath;
55     /** The element descriptor for the base */
56     private ElementDescriptor baseElementDescriptor;
57     /** The (empty) base context from which all Contexts
58     with beans are (directly or indirectly) obtained */

59     private DigesterReadContext context;
60     /** allows an attribute to be specified to overload the types of beans used */
61     private String JavaDoc classNameAttribute = "className";
62
63     /**
64      * Base constructor.
65      *
66      * @param introspector the <code>XMLIntrospector</code> used to introspect
67      * @param basePath specifies the (Digester-style) path under which the rules will be attached
68      * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
69      * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
70      * @param matchIDs should ID/IDREFs be used to match beans?
71      * @deprecated 0.5 use constructor which takes a ReadContext instead
72      */

73     public BeanRuleSet(
74         XMLIntrospector introspector,
75         String JavaDoc basePath,
76         ElementDescriptor baseElementDescriptor,
77         Class JavaDoc baseBeanClass,
78         boolean matchIDs) {
79         this.basePath = basePath;
80         this.baseElementDescriptor = baseElementDescriptor;
81         BindingConfiguration bindingConfiguration = new BindingConfiguration();
82         bindingConfiguration.setMapIDs(matchIDs);
83         context =
84             new DigesterReadContext(
85                 log,
86                 bindingConfiguration,
87                 new ReadConfiguration());
88         context.setRootClass(baseBeanClass);
89         context.setXMLIntrospector(introspector);
90     }
91
92     /**
93      * Base constructor.
94      *
95      * @param introspector the <code>XMLIntrospector</code> used to introspect
96      * @param basePath specifies the (Digester-style) path under which the rules will be attached
97      * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
98      * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
99      * @param context the root Context that bean carrying Contexts should be obtained from,
100      * not null
101      * @deprecated 0.6 use the constructor which takes a ReadContext instead
102      */

103     public BeanRuleSet(
104         XMLIntrospector introspector,
105         String JavaDoc basePath,
106         ElementDescriptor baseElementDescriptor,
107         Context context) {
108
109         this.basePath = basePath;
110         this.baseElementDescriptor = baseElementDescriptor;
111         this.context =
112             new DigesterReadContext(context, new ReadConfiguration());
113         this.context.setRootClass(
114             baseElementDescriptor.getSingularPropertyType());
115         this.context.setXMLIntrospector(introspector);
116     }
117
118     /**
119      * Base constructor.
120      *
121      * @param introspector the <code>XMLIntrospector</code> used to introspect
122      * @param basePath specifies the (Digester-style) path under which the rules will be attached
123      * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
124      * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
125      * @param context the root Context that bean carrying Contexts should be obtained from,
126      * not null
127      * @deprecated 0.5 use the constructor which takes a ReadContext instead
128      */

129     public BeanRuleSet(
130                         XMLIntrospector introspector,
131                         String JavaDoc basePath,
132                         ElementDescriptor baseElementDescriptor,
133                         Class JavaDoc baseBeanClass,
134                         Context context) {
135         this(
136             introspector,
137             basePath,
138             baseElementDescriptor,
139             baseBeanClass,
140             new ReadContext( context, new ReadConfiguration() ));
141     }
142
143     /**
144      * Base constructor.
145      *
146      * @param introspector the <code>XMLIntrospector</code> used to introspect
147      * @param basePath specifies the (Digester-style) path under which the rules will be attached
148      * @param baseElementDescriptor the <code>ElementDescriptor</code> used to create the rules
149      * @param baseBeanClass the <code>Class</code> whose mapping rules will be created
150      * @param baseContext the root Context that bean carrying Contexts should be obtained from,
151      * not null
152      */

153     public BeanRuleSet(
154         XMLIntrospector introspector,
155         String JavaDoc basePath,
156         ElementDescriptor baseElementDescriptor,
157         Class JavaDoc baseBeanClass,
158         ReadContext baseContext) {
159         this.basePath = basePath;
160         this.baseElementDescriptor = baseElementDescriptor;
161         this.context = new DigesterReadContext(baseContext);
162         this.context.setRootClass(baseBeanClass);
163         this.context.setXMLIntrospector(introspector);
164     }
165
166     /**
167      * The name of the attribute which can be specified in the XML to override the
168      * type of a bean used at a certain point in the schema.
169      *
170      * <p>The default value is 'className'.</p>
171      *
172      * @return The name of the attribute used to overload the class name of a bean
173      */

174     public String JavaDoc getClassNameAttribute() {
175         return context.getClassNameAttribute();
176     }
177
178     /**
179      * Sets the name of the attribute which can be specified in
180      * the XML to override the type of a bean used at a certain
181      * point in the schema.
182      *
183      * <p>The default value is 'className'.</p>
184      *
185      * @param classNameAttribute The name of the attribute used to overload the class name of a bean
186      * @deprecated 0.5 set the <code>ReadContext</code> property instead
187      */

188     public void setClassNameAttribute(String JavaDoc classNameAttribute) {
189         context.setClassNameAttribute(classNameAttribute);
190     }
191
192     //-------------------------------- Ruleset implementation
193

194     /**
195      * <p>Return namespace associated with this ruleset</p>
196      *
197      * <p><strong>Note</strong> namespaces are not currently supported.</p>
198      *
199      * @return null
200      */

201     public String JavaDoc getNamespaceURI() {
202         return null;
203     }
204
205     /**
206      * Add rules for bean to given <code>Digester</code>.
207      *
208      * @param digester the <code>Digester</code> to which the rules for the bean will be added
209      */

210     public void addRuleInstances(Digester digester) {
211         if (log.isTraceEnabled()) {
212             log.trace("Adding rules to:" + digester);
213         }
214
215         context.setDigester(digester);
216
217         // if the classloader is not set, set to the digester classloader
218
if (context.getClassLoader() == null) {
219             context.setClassLoader(digester.getClassLoader());
220         }
221
222         // TODO: need to think about strategy for paths
223
// may need to provide a default path and then allow the user to override
224
digester.addRule("!" + basePath + "/*", new ActionMappingRule());
225     }
226
227     /**
228      * Single rule that is used to map all elements.
229      *
230      * @author <a HREF='http://jakarta.apache.org/'>Jakarta Commons Team</a>
231      */

232     private final class ActionMappingRule extends Rule {
233
234         /**
235           * Processes the start of a new <code>Element</code>.
236           * The actual processing is delegated to <code>MappingAction</code>'s.
237           * @see Rule#begin(String, String, Attributes)
238           */

239         public void begin(String JavaDoc namespace, String JavaDoc name, Attributes JavaDoc attributes)
240             throws Exception JavaDoc {
241
242             if (log.isTraceEnabled()) {
243                 int attributesLength = attributes.getLength();
244                 if (attributesLength > 0) {
245                     log.trace("Attributes:");
246                 }
247                 for (int i = 0, size = attributesLength; i < size; i++) {
248                     log.trace("Local:" + attributes.getLocalName(i));
249                     log.trace("URI:" + attributes.getURI(i));
250                     log.trace("QName:" + attributes.getQName(i));
251                 }
252             }
253
254             context.pushElement(name);
255             
256             MappingAction nextAction =
257                 nextAction(namespace, name, attributes, context);
258
259             context.pushMappingAction(nextAction);
260         }
261
262         /**
263          * Gets the next action to be executed
264          * @param namespace the element's namespace, not null
265          * @param name the element name, not null
266          * @param attributes the element's attributes, not null
267          * @param context the <code>ReadContext</code> against which the xml is being mapped.
268          * @return the initialized <code>MappingAction</code>, not null
269          * @throws Exception
270          */

271         private MappingAction nextAction(
272             String JavaDoc namespace,
273             String JavaDoc name,
274             Attributes JavaDoc attributes,
275             ReadContext context)
276             throws Exception JavaDoc {
277                 
278             MappingAction result = null;
279             MappingAction lastAction = context.currentMappingAction();
280             if (lastAction == null)
281             {
282                 result = BeanBindAction.INSTANCE;
283             } else {
284                 
285                 result = lastAction.next(namespace, name, attributes, context);
286             }
287             return result.begin(namespace, name, attributes, context);
288         }
289
290
291
292         /**
293         * Processes the body text for the current element.
294         * This is delegated to the current <code>MappingAction</code>.
295         * @see Rule#body(String, String, String)
296         */

297         public void body(String JavaDoc namespace, String JavaDoc name, String JavaDoc text)
298             throws Exception JavaDoc {
299
300             log.trace("[BRS] Body with text " + text);
301             if (digester.getCount() > 0) {
302                 MappingAction action = context.currentMappingAction();
303                 action.body(text, context);
304             } else {
305                 log.trace("[BRS] ZERO COUNT");
306             }
307         }
308
309         /**
310         * Process the end of this element.
311         * This is delegated to the current <code>MappingAction</code>.
312         */

313         public void end(String JavaDoc namespace, String JavaDoc name) throws Exception JavaDoc {
314
315             MappingAction action = context.popMappingAction();
316             action.end(context);
317         }
318
319         /**
320          * Tidy up.
321          */

322         public void finish() {
323             //
324
// Clear indexed beans so that we're ready to process next document
325
//
326
context.clearBeans();
327         }
328
329     }
330
331     /**
332      * Specialization of <code>ReadContext</code> when reading from <code>Digester</code>.
333      * @author <a HREF='http://jakarta.apache.org/'>Jakarta Commons Team</a>
334      * @version $Revision: 1.20.2.1 $
335      */

336     private static class DigesterReadContext extends ReadContext {
337
338         private Digester digester;
339
340         /**
341          * @param context
342          * @param readConfiguration
343          */

344         public DigesterReadContext(
345             Context context,
346             ReadConfiguration readConfiguration) {
347             super(context, readConfiguration);
348             // TODO Auto-generated constructor stub
349
}
350
351         /**
352          * @param bindingConfiguration
353          * @param readConfiguration
354          */

355         public DigesterReadContext(
356             BindingConfiguration bindingConfiguration,
357             ReadConfiguration readConfiguration) {
358             super(bindingConfiguration, readConfiguration);
359         }
360
361         /**
362          * @param log
363          * @param bindingConfiguration
364          * @param readConfiguration
365          */

366         public DigesterReadContext(
367             Log log,
368             BindingConfiguration bindingConfiguration,
369             ReadConfiguration readConfiguration) {
370             super(log, bindingConfiguration, readConfiguration);
371         }
372
373         /**
374          * @param log
375          * @param bindingConfiguration
376          * @param readConfiguration
377          */

378         public DigesterReadContext(ReadContext readContext) {
379             super(readContext);
380         }
381
382         public Digester getDigester() {
383             // TODO: replace with something better
384
return digester;
385         }
386
387         public void setDigester(Digester digester) {
388             // TODO: replace once moved to single Rule
389
this.digester = digester;
390         }
391
392         /* (non-Javadoc)
393          * @see org.apache.commons.betwixt.io.read.ReadContext#pushBean(java.lang.Object)
394          */

395         public void pushBean(Object JavaDoc bean) {
396             super.pushBean(bean);
397             digester.push(bean);
398         }
399
400         /* (non-Javadoc)
401          * @see org.apache.commons.betwixt.io.read.ReadContext#putBean(java.lang.Object)
402          */

403         public Object JavaDoc popBean() {
404             Object JavaDoc bean = super.popBean();
405             Object JavaDoc top = digester.pop();
406             return bean;
407         }
408     }
409
410 }
411
Popular Tags