KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.apache.commons.betwixt.io;
17
18 import java.beans.IntrospectionException JavaDoc;
19 import java.util.HashSet JavaDoc;
20 import java.util.Set JavaDoc;
21
22 import javax.xml.parsers.SAXParser JavaDoc;
23
24 import org.apache.commons.betwixt.BindingConfiguration;
25 import org.apache.commons.betwixt.ElementDescriptor;
26 import org.apache.commons.betwixt.XMLBeanInfo;
27 import org.apache.commons.betwixt.XMLIntrospector;
28 import org.apache.commons.betwixt.io.read.ReadConfiguration;
29 import org.apache.commons.betwixt.io.read.ReadContext;
30 import org.apache.commons.digester.Digester;
31 import org.apache.commons.digester.ExtendedBaseRules;
32 import org.apache.commons.digester.RuleSet;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.xml.sax.XMLReader JavaDoc;
36
37 /** <p><code>BeanReader</code> reads a tree of beans from an XML document.</p>
38   *
39   * <p>Call {@link #registerBeanClass(Class)} or {@link #registerBeanClass(String, Class)}
40   * to add rules to map a bean class.</p>
41   *
42   * @author <a HREF="mailto:jstrachan@apache.org">James Strachan</a>
43   */

44 public class BeanReader extends Digester {
45
46     /** Introspector used */
47     private XMLIntrospector introspector = new XMLIntrospector();
48     /** Log used for logging (Doh!) */
49     private Log log = LogFactory.getLog( BeanReader.class );
50     /** The registered classes */
51     private Set JavaDoc registeredClasses = new HashSet JavaDoc();
52     /** Dynamic binding configuration settings */
53     private BindingConfiguration bindingConfiguration = new BindingConfiguration();
54     /** Reading specific configuration settings */
55     private ReadConfiguration readConfiguration = new ReadConfiguration();
56     
57     /**
58      * Construct a new BeanReader with default properties.
59      */

60     public BeanReader() {
61         // TODO: now we require extended rules may need to document this
62
setRules(new ExtendedBaseRules());
63     }
64
65     /**
66      * Construct a new BeanReader, allowing a SAXParser to be passed in. This
67      * allows BeanReader to be used in environments which are unfriendly to
68      * JAXP1.1 (such as WebLogic 6.0). Thanks for the request to change go to
69      * James House (james@interobjective.com). This may help in places where
70      * you are able to load JAXP 1.1 classes yourself.
71      *
72      * @param parser use this <code>SAXParser</code>
73      */

74     public BeanReader(SAXParser JavaDoc parser) {
75         super(parser);
76         setRules(new ExtendedBaseRules());
77     }
78
79     /**
80      * Construct a new BeanReader, allowing an XMLReader to be passed in. This
81      * allows BeanReader to be used in environments which are unfriendly to
82      * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you
83      * have to configure namespace and validation support yourself, as these
84      * properties only affect the SAXParser and emtpy constructor.
85      *
86      * @param reader use this <code>XMLReader</code> as source for SAX events
87      */

88     public BeanReader(XMLReader JavaDoc reader) {
89         super(reader);
90         setRules(new ExtendedBaseRules());
91     }
92
93     
94     /**
95      * <p>Register a bean class and add mapping rules for this bean class.</p>
96      *
97      * <p>A bean class is introspected when it is registered.
98      * It will <strong>not</strong> be introspected again even if the introspection
99      * settings are changed.
100      * If re-introspection is required, then {@link #deregisterBeanClass} must be called
101      * and the bean re-registered.</p>
102      *
103      * <p>A bean class can only be registered once.
104      * If the same class is registered a second time, this registration will be ignored.
105      * In order to change a registration, call {@link #deregisterBeanClass}
106      * before calling this method.</p>
107      *
108      * <p>All the rules required to digest this bean are added when this method is called.
109      * Other rules that you want to execute before these should be added before this
110      * method is called.
111      * Those that should be executed afterwards, should be added afterwards.</p>
112      *
113      * @param beanClass the <code>Class</code> to be registered
114      * @throws IntrospectionException if the bean introspection fails
115      */

116     public void registerBeanClass(Class JavaDoc beanClass) throws IntrospectionException JavaDoc {
117         if ( ! registeredClasses.contains( beanClass ) ) {
118             if ( log.isTraceEnabled() ) {
119                 log.trace( "Registering class " + beanClass );
120             }
121             registeredClasses.add( beanClass );
122             
123             // introspect and find the ElementDescriptor to use as the root
124
XMLBeanInfo xmlInfo = introspector.introspect( beanClass );
125             ElementDescriptor elementDescriptor = xmlInfo.getElementDescriptor();
126
127             String JavaDoc path = elementDescriptor.getQualifiedName();
128             if (log.isTraceEnabled()) {
129                 log.trace("Added path: " + path + ", mapped to: " + beanClass.getName());
130             }
131             addBeanCreateRule( path, elementDescriptor, beanClass );
132             
133         } else {
134             if ( log.isWarnEnabled() ) {
135                 log.warn("Cannot add class " + beanClass.getName() + " since it already exists");
136             }
137         }
138     }
139     
140     /**
141      * <p>Registers a bean class
142      * and add mapping rules for this bean class at the given path expression.</p>
143      *
144      *
145      * <p>A bean class is introspected when it is registered.
146      * It will <strong>not</strong> be introspected again even if the introspection
147      * settings are changed.
148      * If re-introspection is required, then {@link #deregisterBeanClass} must be called
149      * and the bean re-registered.</p>
150      *
151      * <p>A bean class can only be registered once.
152      * If the same class is registered a second time, this registration will be ignored.
153      * In order to change a registration, call {@link #deregisterBeanClass}
154      * before calling this method.</p>
155      *
156      * <p>All the rules required to digest this bean are added when this method is called.
157      * Other rules that you want to execute before these should be added before this
158      * method is called.
159      * Those that should be executed afterwards, should be added afterwards.</p>
160      *
161      * @param path the xml path expression where the class is to registered.
162      * This should be in digester path notation
163      * @param beanClass the <code>Class</code> to be registered
164      * @throws IntrospectionException if the bean introspection fails
165      */

166     public void registerBeanClass(String JavaDoc path, Class JavaDoc beanClass) throws IntrospectionException JavaDoc {
167         if ( ! registeredClasses.contains( beanClass ) ) {
168             registeredClasses.add( beanClass );
169             
170             // introspect and find the ElementDescriptor to use as the root
171
XMLBeanInfo xmlInfo = introspector.introspect( beanClass );
172             ElementDescriptor elementDescriptor = xmlInfo.getElementDescriptor();
173
174             addBeanCreateRule( path, elementDescriptor, beanClass );
175         } else {
176             if ( log.isWarnEnabled() ) {
177                 log.warn("Cannot add class " + beanClass.getName() + " since it already exists");
178             }
179         }
180     }
181     
182     /**
183      * <p>Flush all registered bean classes.
184      * This allows all bean classes to be re-registered
185      * by a subsequent calls to <code>registerBeanClass</code>.</p>
186      *
187      * <p><strong>Note</strong> that deregistering a bean does <strong>not</strong>
188      * remove the Digester rules associated with that bean.</p>
189      * @since 0.5
190      */

191     public void flushRegisteredBeanClasses() {
192         registeredClasses.clear();
193     }
194     
195     /**
196      * <p>Remove the given class from the register.
197      * Calling this method will allow the bean class to be re-registered
198      * by a subsequent call to <code>registerBeanClass</code>.
199      * This allows (for example) a bean to be reintrospected after a change
200      * to the introspection settings.</p>
201      *
202      * <p><strong>Note</strong> that deregistering a bean does <strong>not</strong>
203      * remove the Digester rules associated with that bean.</p>
204      *
205      * @param beanClass the <code>Class</code> to remove from the set of registered bean classes
206      * @since 0.5
207      */

208     public void deregisterBeanClass( Class JavaDoc beanClass ) {
209         registeredClasses.remove( beanClass );
210     }
211     
212     // Properties
213
//-------------------------------------------------------------------------
214

215     /**
216      * <p> Get the introspector used. </p>
217      *
218      * <p> The {@link XMLBeanInfo} used to map each bean is
219      * created by the <code>XMLIntrospector</code>.
220      * One way in which the mapping can be customized is by
221      * altering the <code>XMLIntrospector</code>. </p>
222      *
223      * @return the <code>XMLIntrospector</code> used for the introspection
224      */

225     public XMLIntrospector getXMLIntrospector() {
226         return introspector;
227     }
228     
229
230     /**
231      * <p> Set the introspector to be used. </p>
232      *
233      * <p> The {@link XMLBeanInfo} used to map each bean is
234      * created by the <code>XMLIntrospector</code>.
235      * One way in which the mapping can be customized is by
236      * altering the <code>XMLIntrospector</code>. </p>
237      *
238      * @param introspector use this introspector
239      */

240     public void setXMLIntrospector(XMLIntrospector introspector) {
241         this.introspector = introspector;
242     }
243
244     /**
245      * <p> Get the current level for logging. </p>
246      *
247      * @return the <code>Log</code> implementation this class logs to
248      */

249     public Log getLog() {
250         return log;
251     }
252
253     /**
254      * <p> Set the current logging level. </p>
255      *
256      * @param log the <code>Log</code>implementation to use for logging
257      */

258     public void setLog(Log log) {
259         this.log = log;
260         setLogger(log);
261     }
262     
263     /**
264      * Should the reader use <code>ID</code> attributes to match beans.
265      *
266      * @return true if <code>ID</code> and <code>IDREF</code>
267      * attributes should be used to match instances
268      * @deprecated 0.5 use {@link BindingConfiguration#getMapIDs}
269      */

270     public boolean getMatchIDs() {
271         return getBindingConfiguration().getMapIDs();
272     }
273     
274     /**
275      * Set whether the read should use <code>ID</code> attributes to match beans.
276      *
277      * @param matchIDs pass true if <code>ID</code>'s should be matched
278      * @deprecated 0.5 use {@link BindingConfiguration#setMapIDs}
279      */

280     public void setMatchIDs(boolean matchIDs) {
281         getBindingConfiguration().setMapIDs( matchIDs );
282     }
283     
284     /**
285      * Gets the dynamic configuration setting to be used for bean reading.
286      * @return the BindingConfiguration settings, not null
287      * @since 0.5
288      */

289     public BindingConfiguration getBindingConfiguration() {
290         return bindingConfiguration;
291     }
292     
293     /**
294      * Sets the dynamic configuration setting to be used for bean reading.
295      * @param bindingConfiguration the BindingConfiguration settings, not null
296      * @since 0.5
297      */

298     public void setBindingConfiguration( BindingConfiguration bindingConfiguration ) {
299         this.bindingConfiguration = bindingConfiguration;
300     }
301     
302     /**
303      * Gets read specific configuration details.
304      * @return the ReadConfiguration, not null
305      * @since 0.5
306      */

307     public ReadConfiguration getReadConfiguration() {
308         return readConfiguration;
309     }
310     
311     /**
312      * Sets the read specific configuration details.
313      * @param readConfiguration not null
314      * @since 0.5
315      */

316     public void setReadConfiguration( ReadConfiguration readConfiguration ) {
317         this.readConfiguration = readConfiguration;
318     }
319         
320     // Implementation methods
321
//-------------------------------------------------------------------------
322

323     /**
324      * Adds a new bean create rule for the specified path
325      *
326      * @param path the digester path at which this rule should be added
327      * @param elementDescriptor the <code>ElementDescriptor</code> describes the expected element
328      * @param beanClass the <code>Class</code> of the bean created by this rule
329      */

330     protected void addBeanCreateRule(
331                                     String JavaDoc path,
332                                     ElementDescriptor elementDescriptor,
333                                     Class JavaDoc beanClass ) {
334         if (log.isTraceEnabled()) {
335             log.trace("Adding BeanRuleSet for " + beanClass);
336         }
337         RuleSet ruleSet = new BeanRuleSet(
338                                             introspector,
339                                             path ,
340                                             elementDescriptor,
341                                             beanClass,
342                                             makeContext());
343         addRuleSet( ruleSet );
344     }
345         
346     /**
347       * Factory method for new contexts.
348       * Ensure that they are correctly configured.
349       * @return the ReadContext created, not null
350       */

351     private ReadContext makeContext() {
352         return new ReadContext( log, bindingConfiguration, readConfiguration );
353     }
354 }
355
Popular Tags