KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > riotfamily > common > beans > xml > AbstractGenericBeanDefinitionParser


1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1
3  * The contents of this file are subject to the Mozilla Public License Version
4  * 1.1 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  * http://www.mozilla.org/MPL/
7  *
8  * Software distributed under the License is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10  * for the specific language governing rights and limitations under the
11  * License.
12  *
13  * The Original Code is Riot.
14  *
15  * The Initial Developer of the Original Code is
16  * Neteye GmbH.
17  * Portions created by the Initial Developer are Copyright (C) 2007
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  * Felix Gnass [fgnass at neteye dot de]
22  * Carsten Woelk [cwoelk at neteye dot de]
23  *
24  * ***** END LICENSE BLOCK ***** */

25 package org.riotfamily.common.beans.xml;
26
27 import org.springframework.beans.factory.BeanDefinitionStoreException;
28 import org.springframework.beans.factory.config.BeanDefinition;
29 import org.springframework.beans.factory.config.BeanDefinitionHolder;
30 import org.springframework.beans.factory.parsing.BeanComponentDefinition;
31 import org.springframework.beans.factory.support.AbstractBeanDefinition;
32 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
33 import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
34 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
35 import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
36 import org.springframework.beans.factory.xml.BeanDefinitionParser;
37 import org.springframework.beans.factory.xml.ParserContext;
38 import org.springframework.util.Assert;
39 import org.springframework.util.StringUtils;
40 import org.w3c.dom.Element JavaDoc;
41
42 /**
43  * Class similar to Spring's {@link AbstractBeanDefinitionParser}.
44  * Supports registering aliased beans and decoration of nested beans.
45  *
46  * @author Carsten Woelk [cwoelk at neteye dot de]
47  * @author Felix Gnass [fgnass at neteye dot de]
48  * @since 6.5
49  */

50 public abstract class AbstractGenericBeanDefinitionParser implements BeanDefinitionParser {
51
52     /** Constant for the id attribute */
53     public static final String JavaDoc ID_ATTRIBUTE = "id";
54
55     private Class JavaDoc beanClass;
56
57     private boolean decorate = true;
58
59     public AbstractGenericBeanDefinitionParser(Class JavaDoc beanClass) {
60         Assert.notNull(beanClass, "The beanClass must not be null");
61         this.beanClass = beanClass;
62     }
63
64     /**
65      * Sets whether the bean should be decorated. Default is <code>true</code>.
66      */

67     public void setDecorate(boolean decorate) {
68         this.decorate = decorate;
69     }
70
71     public final BeanDefinition parse(Element JavaDoc element, ParserContext parserContext) {
72         AbstractBeanDefinition definition = parseInternal(element, parserContext);
73         if (!parserContext.isNested()) {
74             try {
75                 String JavaDoc id = resolveId(element, definition, parserContext);
76                 if (!StringUtils.hasText(id)) {
77                     parserContext.getReaderContext().error(
78                             "Id is required for element '" + element.getLocalName() + "' when used as a top-level tag", element);
79                 }
80                 String JavaDoc[] aliases = resolveAliases(element, definition, parserContext);
81                 BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
82                 if (decorate) {
83                     parserContext.getDelegate().decorateBeanDefinitionIfRequired(element, holder);
84                 }
85                 registerBeanDefinition(holder, parserContext.getRegistry());
86                 if (shouldFireEvents()) {
87                     BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
88                     postProcessComponentDefinition(componentDefinition);
89                     parserContext.registerComponent(componentDefinition);
90                 }
91             }
92             catch (BeanDefinitionStoreException ex) {
93                 parserContext.getReaderContext().error(ex.getMessage(), element);
94                 return null;
95             }
96         }
97         else if (decorate) {
98             BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, "");
99             parserContext.getDelegate().decorateBeanDefinitionIfRequired(element, holder);
100         }
101         return definition;
102     }
103
104     /**
105      * Creates a {@link BeanDefinitionBuilder} instance for the
106      * {@link #getBeanClass bean Class} and passes it to the
107      * {@link #doParse} strategy method.
108      * @param element the element that is to be parsed into a single BeanDefinition
109      * @param parserContext the object encapsulating the current state of the parsing process
110      * @return the BeanDefinition resulting from the parsing of the supplied {@link Element}
111      * @throws IllegalStateException if the bean {@link Class} returned from
112      * {@link #getBeanClass(org.w3c.dom.Element)} is <code>null</code>
113      * @see #doParse
114      */

115     protected final AbstractBeanDefinition parseInternal(Element JavaDoc element, ParserContext parserContext) {
116         BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
117         builder.setSource(parserContext.extractSource(element));
118         if (parserContext.isNested()) {
119             // Inner bean definition must receive same singleton status as containing bean.
120
builder.setSingleton(parserContext.getContainingBeanDefinition().isSingleton());
121         }
122         if (parserContext.isDefaultLazyInit()) {
123             // Default-lazy-init applies to custom bean definitions as well.
124
builder.setLazyInit(true);
125         }
126         doParse(element, parserContext, builder);
127         return builder.getBeanDefinition();
128     }
129
130     /**
131      * Resolve the ID for the supplied {@link BeanDefinition}.
132      * <p>When using {@link #shouldGenerateId generation}, a name is generated automatically.
133      * Otherwise, the ID is extracted from the "id" attribute, potentially with a
134      * {@link #shouldGenerateIdAsFallback() fallback} to a generated id.
135      * @param element the element that the bean definition has been built from
136      * @param definition the bean definition to be registered
137      * @param parserContext the object encapsulating the current state of the parsing process;
138      * provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
139      * @return the resolved id
140      * @throws BeanDefinitionStoreException if no unique name could be generated
141      * for the given bean definition
142      */

143     protected String JavaDoc resolveId(Element JavaDoc element, AbstractBeanDefinition definition, ParserContext parserContext)
144             throws BeanDefinitionStoreException {
145
146         if (shouldGenerateId()) {
147             return parserContext.getReaderContext().generateBeanName(definition);
148         }
149         else {
150             String JavaDoc id = element.getAttribute(ID_ATTRIBUTE);
151             if (!StringUtils.hasText(id) && shouldGenerateIdAsFallback()) {
152                 id = parserContext.getReaderContext().generateBeanName(definition);
153             }
154             return id;
155         }
156     }
157
158     /**
159      * Resolve the aliases for the supplied {@link BeanDefinition}. The default
160      * implementation delegates the call to
161      * {@link #resolveAlias(Element, AbstractBeanDefinition, ParserContext)}
162      * and tokenizes the returned String.
163      */

164     protected String JavaDoc[] resolveAliases(Element JavaDoc element,
165             AbstractBeanDefinition definition, ParserContext parserContext) {
166
167         String JavaDoc alias = resolveAlias(element, definition, parserContext);
168         return StringUtils.tokenizeToStringArray(alias, ",; ");
169     }
170
171     /**
172      * Resolve the alias for the supplied {@link BeanDefinition}. The returned
173      * String may contain multiple bean-names separated by commas, semicolons
174      * or spaces. The default implementation returns <code>null</code>
175      */

176     protected String JavaDoc resolveAlias(Element JavaDoc element,
177             AbstractBeanDefinition definition, ParserContext parserContext) {
178
179         return null;
180     }
181
182     /**
183      * Register the supplied {@link BeanDefinitionHolder bean} with the supplied
184      * {@link BeanDefinitionRegistry registry}.
185      * <p>Subclasses can override this method to control whether or not the supplied
186      * {@link BeanDefinitionHolder bean} is actually even registered, or to
187      * register even more beans.
188      * <p>The default implementation registers the supplied {@link BeanDefinitionHolder bean}
189      * with the supplied {@link BeanDefinitionRegistry registry} only if the <code>isNested</code>
190      * parameter is <code>false</code>, because one typically does not want inner beans
191      * to be registered as top level beans.
192      * @param definition the bean definition to be registered
193      * @param registry the registry that the bean is to be registered with
194      * @see BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry)
195      */

196     protected void registerBeanDefinition(BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
197         BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry);
198     }
199
200     /**
201      * Should an ID be generated instead of read from the passed in {@link Element}?
202      * <p>Disabled by default; subclasses can override this to enable ID generation.
203      * Note that this flag is about <i>always</i> generating an ID; the parser
204      * won't even check for an "id" attribute in this case.
205      * @return whether the parser should always generate an id
206      */

207     protected boolean shouldGenerateId() {
208         return false;
209     }
210
211     /**
212      * Should an ID be generated instead if the passed in {@link Element} does not
213      * specify an "id" attribute explicitly?
214      * <p>Disabled by default; subclasses can override this to enable ID generation
215      * as fallback: The parser will first check for an "id" attribute in this case,
216      * only falling back to a generated ID if no value was specified.
217      * @return whether the parser should generate an id if no id was specified
218      */

219     protected boolean shouldGenerateIdAsFallback() {
220         return true;
221     }
222
223     /**
224      * Controls whether this parser is supposed to fire a
225      * {@link org.springframework.beans.factory.parsing.BeanComponentDefinition}
226      * event after parsing the bean definition.
227      * <p>This implementation returns <code>true</code> by default; that is,
228      * an event will be fired when a bean definition has been completely parsed.
229      * Override this to return <code>false</code> in order to suppress the event.
230      * @return <code>true</code> in order to fire a component registration event
231      * after parsing the bean definition; <code>false</code> to suppress the event
232      * @see #postProcessComponentDefinition
233      * @see org.springframework.beans.factory.parsing.ReaderContext#fireComponentRegistered
234      */

235     protected boolean shouldFireEvents() {
236         return true;
237     }
238
239     /**
240      * Hook method called after the primary parsing of a
241      * {@link BeanComponentDefinition} but before the
242      * {@link BeanComponentDefinition} has been registered with a
243      * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}.
244      * <p>Derived classes can override this method to supply any custom logic that
245      * is to be executed after all the parsing is finished.
246      * <p>The default implementation is a no-op.
247      * @param componentDefinition the {@link BeanComponentDefinition} that is to be processed
248      */

249     protected void postProcessComponentDefinition(BeanComponentDefinition componentDefinition) {
250     }
251
252     /**
253      * Parse the supplied {@link Element} and populate the supplied
254      * {@link BeanDefinitionBuilder} as required.
255      * <p>The default implementation delegates to the <code>doParse</code>
256      * version without ParserContext argument.
257      * @param element the XML element being parsed
258      * @param parserContext the object encapsulating the current state of the parsing process
259      * @param builder used to define the <code>BeanDefinition</code>
260      * @see #doParse(Element, BeanDefinitionBuilder)
261      */

262     protected void doParse(Element JavaDoc element, ParserContext parserContext, BeanDefinitionBuilder builder) {
263         doParse(element, builder);
264     }
265
266     /**
267      * Parse the supplied {@link Element} and populate the supplied
268      * {@link BeanDefinitionBuilder} as required.
269      * <p>The default implementation does nothing.
270      * @param element the XML element being parsed
271      * @param builder used to define the <code>BeanDefinition</code>
272      */

273     protected void doParse(Element JavaDoc element, BeanDefinitionBuilder builder) {
274     }
275
276 }
277
Popular Tags