|
From: Colin S. <col...@ex...> - 2005-10-17 01:51:45
|
I managed to miss this when it was initially posted. We may want to
consider this for 1.3.
Eugene Kuleshov wrote:
> Folks,
>
> I've implemented a sax-based parser for Spring's XML bean definition
> and wonder if you'd be interested to integrate this into Spring
> framework. this class can be used in place of the current DOM-based
> parser as well as an lightweight adapter for runtime app context
> generators such as xslt-based tools or tools like Jacn (even so I
> believe Jacn should directly generate Spring factories without
> intermediate XML representation).
>
> I run all existing tests from xml package and they all seem working
> just fine. That however required to have copies of
> XmlBeanDefinitionReaderand and XmlBeanFactory patched to work with my
> parser.
>
> In my tests this parser is little bit faster then current DOM-based
> parser and in my opinion it is structured little better then DOM-based
> parser. Basically is is sort-of stripped-down Digester (stack-based
> state machine) with declarative definitions for parsing rules.
> Interestingly the same rules could be used with StAX-based parser with
> very minimal changes or even without changes using adapter for SAX
> Attributes instance used in rule params.
>
> Also note that current XmlBeanDefinitionReader class is tight to
> DOM-based API and does not allow to hookup abstract XML parsers (e.g.
> SAX or StAX). This make impossible to substiture custom non-DOM XML
> parser to XmlBeanFactory.
>
> regards,
> Eugene
>
>
>------------------------------------------------------------------------
>
>
>package com.cibcwm.go.otis.dasl.util;
>
>import java.io.IOException;
>import java.io.InputStream;
>import java.util.ArrayList;
>import java.util.Arrays;
>import java.util.HashMap;
>import java.util.Iterator;
>import java.util.List;
>import java.util.Map;
>import java.util.Properties;
>
>import javax.xml.parsers.ParserConfigurationException;
>import javax.xml.parsers.SAXParser;
>import javax.xml.parsers.SAXParserFactory;
>
>import org.apache.commons.logging.Log;
>import org.apache.commons.logging.LogFactory;
>import org.springframework.beans.MutablePropertyValues;
>import org.springframework.beans.factory.BeanDefinitionStoreException;
>import org.springframework.beans.factory.config.BeanDefinition;
>import org.springframework.beans.factory.config.BeanDefinitionHolder;
>import org.springframework.beans.factory.config.ConstructorArgumentValues;
>import org.springframework.beans.factory.config.RuntimeBeanReference;
>import org.springframework.beans.factory.config.TypedStringValue;
>import org.springframework.beans.factory.support.AbstractBeanDefinition;
>import org.springframework.beans.factory.support.BeanDefinitionReader;
>import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
>import org.springframework.beans.factory.support.LookupOverride;
>import org.springframework.beans.factory.support.ManagedList;
>import org.springframework.beans.factory.support.ManagedMap;
>import org.springframework.beans.factory.support.ManagedSet;
>import org.springframework.beans.factory.support.ReplaceOverride;
>import org.springframework.core.io.ClassPathResource;
>import org.springframework.core.io.Resource;
>import org.springframework.core.io.support.ResourcePatternUtils;
>import org.springframework.util.ClassUtils;
>import org.springframework.util.StringUtils;
>
>import org.xml.sax.Attributes;
>import org.xml.sax.InputSource;
>import org.xml.sax.SAXException;
>import org.xml.sax.SAXParseException;
>import org.xml.sax.helpers.DefaultHandler;
>
>
>/**
> * Default implementation of the XmlBeanDefinitionParser interface.
> * Parses bean definitions according to the "spring-beans" DTD,
> * that is, Spring's default XML bean definition format.
> *
> * <p>The structure, elements and attribute names of the required XML document
> * are hard-coded in this class. (Of course a transform could be run if necessary
> * to produce this format). "beans" doesn't need to be the root element of the XML
> * document: This class will parse all bean definition elements in the XML file.
> *
> * @author Rod Johnson
> * @author Juergen Hoeller
> * @author Rob Harrop
> * @since 18.12.2003
> */
>public class SAXBeanDefinitionParser extends DefaultHandler {
>
> /**
> * Stack of the intermediate processing contexts.
> */
> List stack = new ArrayList();
> /**
> * Complete name of the current element.
> */
> private String match = "";
> private StringBuffer text = new StringBuffer();
>
>
> private final RuleSet RULES = new RuleSet();
> {
> RULES.add("*/description", null);
>
> RULES.add("beans/import", new BeansImportRule());
> RULES.add("beans/alias", new BeansAliasRule());
> RULES.add("beans", new BeansRule()); // description?, (import | alias | bean)*
>
> RULES.add("*/bean/replaced-method/arg-type", new BeanReplacedMethodArgTypeRule());
> RULES.add("*/bean/replaced-method", new BeanReplacedMethodRule()); // (arg-type)*
> RULES.add("*/bean/property", new BeanPropertyRule()); // description?, (bean | ref | idref | value | null | list | set | map | props)?
> RULES.add("*/bean/lookup-method", new BeanLookupMethodRule());
> RULES.add("*/bean/constructor-arg", new BeanConstructorArgRule()); // description?, (bean | ref | idref | value | null | list | set | map | props)?
> RULES.add("*/bean", new BeanRule()); // description?, (constructor-arg | property | lookup-method | replaced-method)*
>
> RULES.add("*/ref", new RefRule());
> RULES.add("*/idref", new IdRefRule());
> RULES.add("*/value", new ValueRule());
> RULES.add("*/null", new NullRule());
>
> RULES.add("*/list", new ListRule()); // (bean | ref | idref | value | null | list | set | map | props)*
>
> RULES.add("*/set", new SetType()); // (bean | ref | idref | value | null | list | set | map | props)*
>
> RULES.add("*/map/entry/key", new MapEntryKeyRule()); // (bean | ref | idref | value | null | list | set | map | props)
> RULES.add("*/map/entry", new MapEntryRule()); // key?, (bean | ref | idref | value | null | list | set | map | props)?
> RULES.add("*/map", new MapRule()); // (entry)*
>
> RULES.add("*/props/prop", new PropsPropRule());
> RULES.add("*/props", new PropsRule()); // (prop)*
> }
>
> static private final String BEAN_NAME_DELIMITERS = ",; ";
>
> /**
> * Value of a T/F attribute that represents true.
> * Anything else represents false. Case seNsItive.
> */
> static private final String TRUE_VALUE = "true";
> static private final String DEFAULT_VALUE = "default";
>
> static private final String AUTOWIRE_BY_NAME_VALUE = "byName";
> static private final String AUTOWIRE_BY_TYPE_VALUE = "byType";
> static private final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
> static private final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";
>
> static private final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";
> static private final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";
> static private final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";
>
> static private final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
> static private final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
> static private final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
>
> static private final String RESOURCE_ATTRIBUTE = "resource";
>
> static private final String NAME_ATTRIBUTE = "name";
> static private final String ALIAS_ATTRIBUTE = "alias";
>
> static private final String BEAN_ELEMENT = "bean";
> static private final String ID_ATTRIBUTE = "id";
> static private final String PARENT_ATTRIBUTE = "parent";
>
> static private final String CLASS_ATTRIBUTE = "class";
> static private final String ABSTRACT_ATTRIBUTE = "abstract";
> static private final String SINGLETON_ATTRIBUTE = "singleton";
> static private final String LAZY_INIT_ATTRIBUTE = "lazy-init";
> static private final String AUTOWIRE_ATTRIBUTE = "autowire";
> static private final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";
> static private final String DEPENDS_ON_ATTRIBUTE = "depends-on";
> static private final String INIT_METHOD_ATTRIBUTE = "init-method";
> static private final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
> static private final String FACTORY_METHOD_ATTRIBUTE = "factory-method";
> static private final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";
>
> static private final String INDEX_ATTRIBUTE = "index";
> static private final String TYPE_ATTRIBUTE = "type";
> static private final String REF_ATTRIBUTE = "ref";
> static private final String VALUE_ATTRIBUTE = "value";
>
> static private final String REPLACER_ATTRIBUTE = "replacer";
> static private final String ARG_TYPE_MATCH_ATTRIBUTE = "match";
>
> static private final String BEAN_REF_ATTRIBUTE = "bean";
> static private final String LOCAL_REF_ATTRIBUTE = "local";
> static private final String PARENT_REF_ATTRIBUTE = "parent";
>
> static private final String KEY_ATTRIBUTE = "key";
> static private final String KEY_REF_ATTRIBUTE = "key-ref";
> static private final String VALUE_REF_ATTRIBUTE = "value-ref";
>
>
> protected final Log logger = LogFactory.getLog(getClass());
>
> BeanDefinitionReader beanDefinitionReader;
>
> Resource resource;
>
> String defaultLazyInit;
>
> String defaultAutowire;
>
> String defaultDependencyCheck;
>
> int beanDefinitionCount = 0;
> private boolean validating = true;
>
>
> public SAXBeanDefinitionParser( boolean validating) {
> this.validating = validating;
> }
>
> public int registerBeanDefinitions(BeanDefinitionReader reader, Resource resource, InputStream inputStream)
> throws BeanDefinitionStoreException {
> this.beanDefinitionReader = reader;
> this.resource = resource;
>
> SAXParserFactory factory = SAXParserFactory.newInstance();
> factory.setValidating(validating);
> SAXParser parser;
> try {
> parser = factory.newSAXParser();
> logger.debug("Loading bean definitions");
> parser.parse(inputStream, this);
>
> } catch( ParserConfigurationException ex) {
> logger.error( ex.getMessage(), ex);
> throw new BeanDefinitionStoreException( ex.getMessage(), ex);
>
> } catch( SAXException ex) {
> logger.error( ex.getMessage(), ex);
> throw new BeanDefinitionStoreException( ex.getMessage(), ex);
>
> } catch( IOException ex) {
> logger.error( ex.getMessage(), ex);
> throw new BeanDefinitionStoreException( ex.getMessage(), ex);
>
> }
>
> if (logger.isDebugEnabled()) {
> logger.debug("Found " + beanDefinitionCount + " <bean> elements in " + resource);
> }
> return beanDefinitionCount;
> }
>
> /**
> * Return the BeanDefinitionReader that this parser has been called from.
> */
> protected final BeanDefinitionReader getBeanDefinitionReader() {
> return beanDefinitionReader;
> }
>
> /**
> * Return the descriptor for the XML resource that this parser works on.
> */
> protected final Resource getResource() {
> return resource;
> }
>
> /**
> * Return the default lazy-init flag for the document that's currently parsed.
> */
> protected final String getDefaultLazyInit() {
> return defaultLazyInit;
> }
>
> /**
> * Return the default autowire setting for the document that's currently parsed.
> */
> protected final String getDefaultAutowire() {
> return defaultAutowire;
> }
>
> /**
> * Return the default dependency-check setting for the document that's currently parsed.
> */
> protected final String getDefaultDependencyCheck() {
> return defaultDependencyCheck;
> }
>
>
> /**
> * Process notification of the start of an XML element being reached.
> *
> * @param ns - The Namespace URI, or the empty string if the element has no
> * Namespace URI or if Namespace processing is not being performed.
> * @param localName - The local name (without prefix), or the empty string
> * if Namespace processing is not being performed.
> * @param qName - The qualified name (with prefix), or the empty string if
> * qualified names are not available.
> * @param list - The attributes attached to the element. If there are no
> * attributes, it shall be an empty Attributes object.
> * @exception SAXException if a parsing error is to be reported
> */
> public final void startElement( String ns, String localName, String qName, Attributes list) {
> // the actual element name is either in localName or qName, depending
> // on whether the parser is namespace aware
> String name = localName;
> if (name == null || name.length() < 1) {
> name = qName;
> }
>
> // Compute the current matching rule
> StringBuffer sb = new StringBuffer(match);
> if (match.length() > 0) {
> sb.append('/');
> }
> sb.append(name);
> match = sb.toString();
>
> // Fire "begin" event for relevant rule
> Rule r = (Rule) RULES.match(match);
> if (r != null) {
> r.begin(ns, name, list);
> }
>
> text = new StringBuffer(); // TODO optimize this
> }
>
> /**
> * Process notification of the end of an XML element being reached.
> *
> * @param ns - The Namespace URI, or the empty string if the element has no
> * Namespace URI or if Namespace processing is not being performed.
> * @param localName - The local name (without prefix), or the empty string
> * if Namespace processing is not being performed.
> * @param qName - The qualified XML 1.0 name (with prefix), or the empty
> * string if qualified names are not available.
> *
> * @exception SAXException if a parsing error is to be reported
> */
> public final void endElement(String ns, String localName, String qName) {
> // the actual element name is either in localName or qName, depending
> // on whether the parser is namespace aware
> String name = localName;
> if (name == null || name.length() < 1) {
> name = qName;
> }
>
> // Fire "end" event for relevant rule
> Rule r = (Rule) RULES.match(match);
> if (r != null) {
> r.text(ns, name, text.toString());
> r.end(ns, name);
> }
>
> // Recover the previous match expression
> int slash = match.lastIndexOf('/');
> if (slash >= 0) {
> match = match.substring(0, slash);
> } else {
> match = "";
> }
> }
>
> public void characters( char[] ch, int start, int length) {
> text.append( ch, start, length);
> }
>
>
> public InputSource resolveEntity( String publicId, String systemId) throws SAXException {
> if("-//SPRING//DTD BEAN//EN".equals(publicId) &&
> "http://www.springframework.org/dtd/spring-beans.dtd".equals(systemId)) {
> Resource resource = new ClassPathResource("/org/springframework/beans/factory/xml/spring-beans.dtd", getClass());
> try {
> InputSource source = new InputSource( resource.getInputStream());
> source.setPublicId( publicId);
> source.setSystemId( systemId);
> if (logger.isDebugEnabled()) {
> logger.debug("Found beans DTD [" + systemId + "] in classpath");
> }
> return source;
> } catch( IOException e) {
> throw new SAXException(e);
> }
> }
> return null;
> }
>
> public void error( SAXParseException e) throws SAXException {
> System.err.println( "ERROR "+e.toString());
> throw e;
> }
>
> public void warning( SAXParseException e) throws SAXException {
> System.err.println( "WARNING "+e.toString());
> throw e;
> }
>
> public void fatalError( SAXParseException e) throws SAXException {
> System.err.println( "FATAL "+e.toString());
> throw e;
> }
>
> private static final class RuleSet {
> private Map rules = new HashMap();
> private List lpatterns = new ArrayList();
> private List rpatterns = new ArrayList();
>
> public void add(String path, Rule rule) {
> String pattern = path;
> if (path.startsWith("*/")) {
> pattern = path.substring(1);
> lpatterns.add(pattern);
> } else if (path.endsWith("/*")) {
> pattern = path.substring(0, path.length() - 1);
> rpatterns.add(pattern);
> }
> rules.put(pattern, rule);
> }
>
> public Object match(String path) {
> if (rules.containsKey(path)) {
> return rules.get(path);
> }
>
> for (Iterator it = lpatterns.iterator(); it.hasNext();) {
> String pattern = (String) it.next();
> if (path.endsWith(pattern)) {
> return rules.get(pattern);
> }
> }
>
> for (Iterator it = rpatterns.iterator(); it.hasNext();) {
> String pattern = (String) it.next();
> if (path.startsWith(pattern)) {
> return rules.get(pattern);
> }
> }
>
> return null;
> }
>
> }
>
> final Object peek() {
> return stack.size() == 0 ? null : stack.get(stack.size() - 1);
> }
>
> final Object peek(int n) {
> return stack.size() < (n + 1) ? null : stack.get(n);
> }
>
> final Object pop() {
> return stack.size() == 0 ? null : stack.remove(stack.size() - 1);
> }
>
> final void push(Object object) {
> stack.add(object);
> }
>
>
> protected abstract class Rule {
>
> public void begin( String ns, String name, Attributes attrs) {
> }
>
> public void end( String ns, String name) {
> }
>
> public void text( String ns, String name, String text) {
> }
>
> protected BeanDefinitionHolder getBeanDefinitionHolder() {
> for( int n = stack.size()-1; n>=0; n--) {
> Object o = stack.get(n);
> if( o instanceof BeanDefinitionHolder) {
> return ( BeanDefinitionHolder) o;
> }
> }
> throw new BeanDefinitionStoreException( "Unable to find BeanDefinitionHolder");
> }
>
> protected AbstractBeanDefinition getBeanDefinition() {
> return ( AbstractBeanDefinition) getBeanDefinitionHolder().getBeanDefinition();
> }
>
> protected Object getValue(String elementName, Attributes atts) {
> String ref = atts.getValue(REF_ATTRIBUTE);
> String value = atts.getValue(VALUE_ATTRIBUTE);
> if(ref!=null && value!=null) {
> throw new BeanDefinitionStoreException( getResource(), getBeanDefinitionHolder().getBeanName(), elementName +
> " is only allowed to contain either a 'ref' attribute OR a 'value' attribute OR a sub-element");
> }
>
> if (ref!=null) {
> return new RuntimeBeanReference(ref);
> } else if (value!=null) {
> return value;
> }
>
> return null;
> }
>
> public void setValue( Object value) {
> Object target = peek();
>
> // introspect type and set an appropriate property
> // TODO add assertion for already set properties
> if( target instanceof ConstructorArgumentValuesHolder) { // constructor-arg/...
> ((ConstructorArgumentValuesHolder) target).setValue(value);
>
> } else if( target instanceof PropertyValueHolder) { // property/...
> ((PropertyValueHolder) target).setValue(value);
>
> } else if( target instanceof ManagedList) { // list/...
> ((ManagedList) target).add(value);
>
> } else if( target instanceof ManagedSet) { // set/...
> ((ManagedSet) target).add(value);
>
> } else if( target instanceof MapEntryHolder) { // map/entry/...
> ((MapEntryHolder) target).setValue(value);
>
> } else if( target instanceof MapEntryKeyHolder) { // map/entry/key/...
> ((MapEntryKeyHolder) target).setKey(value);
>
> }
> }
> }
>
>
> /**
> * description?, (import | alias | bean)*
> */
> private final class BeansRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> defaultLazyInit = atts.getValue(DEFAULT_LAZY_INIT_ATTRIBUTE);
> defaultAutowire = atts.getValue(DEFAULT_AUTOWIRE_ATTRIBUTE);
> defaultDependencyCheck = atts.getValue(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE);
>
> if (logger.isDebugEnabled()) {
> logger.debug("Default lazy init '" + defaultLazyInit + "'");
> logger.debug("Default autowire '" + defaultAutowire + "'");
> logger.debug("Default dependency check '" + defaultDependencyCheck + "'");
> }
> }
> }
>
>
> public class BeansImportRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String location = atts.getValue(RESOURCE_ATTRIBUTE);
>
> if (ResourcePatternUtils.isUrl(location)) {
> int importCount = getBeanDefinitionReader().loadBeanDefinitions(location);
> if (logger.isDebugEnabled()) {
> logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
> }
> } else {
> // No URL -> considering resource location as relative to the current file.
> try {
> Resource relativeResource = getResource().createRelative(location);
> int importCount = getBeanDefinitionReader().loadBeanDefinitions(relativeResource);
> if (logger.isDebugEnabled()) {
> logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
> }
> } catch (IOException ex) {
> throw new BeanDefinitionStoreException(
> "Invalid relative resource location [" + location + "] to import bean definitions from", ex);
> }
> }
> }
> }
>
>
> public class BeansAliasRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String beanName = atts.getValue(NAME_ATTRIBUTE);
> String alias = atts.getValue(ALIAS_ATTRIBUTE);
> beanDefinitionReader.getBeanFactory().registerAlias(beanName, alias);
> }
> }
>
>
> /**
> * description?, (constructor-arg | property | lookup-method | replaced-method)*
> */
> public class BeanRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> beanDefinitionCount++;
> // BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele, false);
>
> String id = atts.getValue(ID_ATTRIBUTE);
> String nameAttr = atts.getValue(NAME_ATTRIBUTE);
>
> List aliases = new ArrayList();
> if (StringUtils.hasLength(nameAttr)) {
> String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
> aliases.addAll(Arrays.asList(nameArr));
> }
>
> String beanName = id;
> if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
> beanName = (String) aliases.remove(0);
> if (logger.isDebugEnabled()) {
> logger.debug("No XML 'id' specified - using '" + beanName +
> "' as bean name and " + aliases + " as aliases");
> }
> }
>
> BeanDefinition beanDefinition = getBeanDefinition(atts, beanName);
>
> if (!StringUtils.hasText(beanName) && beanDefinition instanceof AbstractBeanDefinition) {
> boolean isInnerBean = stack.size()>0;
> beanName = BeanDefinitionReaderUtils.generateBeanName(
> (AbstractBeanDefinition) beanDefinition, beanDefinitionReader.getBeanFactory(), isInnerBean);
> if (logger.isDebugEnabled()) {
> logger.debug("Neither XML 'id' nor 'name' specified - " +
> "using generated bean name [" + beanName + "]");
> }
> }
>
> String[] aliasesArray = (String[]) aliases.toArray(new String[aliases.size()]);
>
> push( new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray));
> }
>
> public void end( String ns, String name) {
> BeanDefinitionHolder bh = ( BeanDefinitionHolder) pop(); // don't inline
> if(stack.size()==0) {
> BeanDefinitionReaderUtils.registerBeanDefinition(bh, beanDefinitionReader.getBeanFactory());
> } else {
> setValue(bh);
> }
> }
>
> protected BeanDefinition getBeanDefinition(Attributes atts, String beanName)
> throws BeanDefinitionStoreException {
>
> String className = atts.getValue(CLASS_ATTRIBUTE);
> String parent = atts.getValue(PARENT_ATTRIBUTE);
>
> try {
> ConstructorArgumentValues cargs = new ConstructorArgumentValues();
> MutablePropertyValues pvs = new MutablePropertyValues();
>
> AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(
> className, parent, cargs, pvs, getBeanDefinitionReader().getBeanClassLoader());
>
> String dependsOn = atts.getValue(DEPENDS_ON_ATTRIBUTE);
> if (dependsOn!=null) {
> bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS));
> }
>
> String factoryMethod = atts.getValue(FACTORY_METHOD_ATTRIBUTE);
> if (factoryMethod!=null) {
> bd.setFactoryMethodName(factoryMethod);
> }
> String factoryBeanName = atts.getValue(FACTORY_BEAN_ATTRIBUTE);
> if (factoryBeanName!=null) {
> bd.setFactoryBeanName(factoryBeanName);
> }
>
> String dependencyCheck = atts.getValue(DEPENDENCY_CHECK_ATTRIBUTE);
> if (DEFAULT_VALUE.equals(dependencyCheck)) {
> dependencyCheck = getDefaultDependencyCheck();
> }
> bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
>
> String autowire = atts.getValue(AUTOWIRE_ATTRIBUTE);
> if (DEFAULT_VALUE.equals(autowire)) {
> autowire = getDefaultAutowire();
> }
> bd.setAutowireMode(getAutowireMode(autowire));
>
> String initMethodName = atts.getValue(INIT_METHOD_ATTRIBUTE);
> if (initMethodName!=null && !initMethodName.equals("")) {
> bd.setInitMethodName(initMethodName);
> }
> String destroyMethodName = atts.getValue(DESTROY_METHOD_ATTRIBUTE);
> if (destroyMethodName!=null && !destroyMethodName.equals("")) {
> bd.setDestroyMethodName(destroyMethodName);
> }
>
> bd.setResourceDescription(getResource().getDescription());
>
> String isAbstract = atts.getValue(ABSTRACT_ATTRIBUTE);
> if (isAbstract!=null) {
> bd.setAbstract(TRUE_VALUE.equals(isAbstract));
> }
>
> String isSingleton = atts.getValue(SINGLETON_ATTRIBUTE);
> if (isSingleton!=null) {
> bd.setSingleton(TRUE_VALUE.equals(isSingleton));
> }
>
> String lazyInit = atts.getValue(LAZY_INIT_ATTRIBUTE);
> if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
> // Just apply default to singletons, as lazy-init has no meaning for prototypes.
> lazyInit = defaultLazyInit;
> }
> bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
>
> return bd;
> }
> catch (ClassNotFoundException ex) {
> throw new BeanDefinitionStoreException(
> resource, beanName, "Bean class [" + className + "] not found", ex);
> }
> catch (NoClassDefFoundError err) {
> throw new BeanDefinitionStoreException(
> resource, beanName, "Class that bean class [" + className + "] depends on not found", err);
> }
> }
>
> protected int getDependencyCheck(String att) {
> int dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE;
> if (DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE.equals(att)) {
> dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_ALL;
> }
> else if (DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE.equals(att)) {
> dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE;
> }
> else if (DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE.equals(att)) {
> dependencyCheckCode = AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS;
> }
> // Else leave default value.
> return dependencyCheckCode;
> }
>
> protected int getAutowireMode(String att) {
> int autowire = AbstractBeanDefinition.AUTOWIRE_NO;
> if (AUTOWIRE_BY_NAME_VALUE.equals(att)) {
> autowire = AbstractBeanDefinition.AUTOWIRE_BY_NAME;
> }
> else if (AUTOWIRE_BY_TYPE_VALUE.equals(att)) {
> autowire = AbstractBeanDefinition.AUTOWIRE_BY_TYPE;
> }
> else if (AUTOWIRE_CONSTRUCTOR_VALUE.equals(att)) {
> autowire = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR;
> }
> else if (AUTOWIRE_AUTODETECT_VALUE.equals(att)) {
> autowire = AbstractBeanDefinition.AUTOWIRE_AUTODETECT;
> }
> // Else leave default value.
> return autowire;
> }
>
> }
>
>
> /**
> * description?, (bean | ref | idref | value | null | list | set | map | props)?
> */
> public class BeanConstructorArgRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String index = atts.getValue(INDEX_ATTRIBUTE);
> String type = atts.getValue(TYPE_ATTRIBUTE);
> Object value = getValue(name, atts);
> push(new ConstructorArgumentValuesHolder( index, type, value));
> }
>
> public void end( String ns, String name) {
> ConstructorArgumentValuesHolder ch = ( ConstructorArgumentValuesHolder) pop();
>
> BeanDefinitionHolder bh = getBeanDefinitionHolder();
> String beanName = bh.getBeanName();
> ConstructorArgumentValues cargs = bh.getBeanDefinition().getConstructorArgumentValues();
>
> String type = ch.getType();
> String index = ch.getIndex();
> Object val = ch.getValue();
> if (StringUtils.hasLength(index)) {
> try {
> int i = Integer.parseInt(index);
> if (i < 0) {
> throw new BeanDefinitionStoreException(getResource(), beanName, "'index' cannot be lower than 0");
> }
> if (StringUtils.hasLength(type)) {
> cargs.addIndexedArgumentValue(i, val, type);
> } else {
> cargs.addIndexedArgumentValue(i, val);
> }
> } catch (NumberFormatException ex) {
> throw new BeanDefinitionStoreException(getResource(), beanName,
> "Attribute 'index' of tag 'constructor-arg' must be an integer");
> }
> } else {
> if (StringUtils.hasLength(type)) {
> cargs.addGenericArgumentValue(val, type);
> } else {
> cargs.addGenericArgumentValue(val);
> }
> }
> }
>
> }
>
>
> /**
> * description?, (bean | ref | idref | value | null | list | set | map | props)?
> */
> public class BeanPropertyRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> BeanDefinitionHolder bh = getBeanDefinitionHolder();
>
> String propertyName = atts.getValue(NAME_ATTRIBUTE);
> if (!StringUtils.hasLength(propertyName)) {
> throw new BeanDefinitionStoreException(
> getResource(), bh.getBeanName(), "Tag 'property' must have a 'name' attribute");
> }
>
> MutablePropertyValues pvs = bh.getBeanDefinition().getPropertyValues();
> if (pvs.contains(propertyName)) {
> throw new BeanDefinitionStoreException(
> getResource(), bh.getBeanName(), "Multiple 'property' definitions for property '" + propertyName + "'");
> }
>
> Object value = getValue(name+" name "+propertyName, atts);
> push( new PropertyValueHolder(propertyName, value));
> }
>
> public void end( String ns, String name) {
> PropertyValueHolder pvh = ( PropertyValueHolder) pop(); // don't inline
>
> MutablePropertyValues pvs = getBeanDefinition().getPropertyValues();
> pvs.addPropertyValue(pvh.getName(), pvh.getValue());
> }
> }
>
>
> public class BeanLookupMethodRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String methodName = atts.getValue(NAME_ATTRIBUTE);
> String beanRef = atts.getValue(BEAN_ELEMENT);
> getBeanDefinition().getMethodOverrides().addOverride(new LookupOverride(methodName, beanRef));
> }
> }
>
>
> /**
> * (arg-type)*
> */
> public class BeanReplacedMethodRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String methodName = atts.getValue(NAME_ATTRIBUTE);
> String callback = atts.getValue(REPLACER_ATTRIBUTE);
> push( new ReplaceOverride(methodName, callback));
> }
>
> public void end( String ns, String name) {
> ReplaceOverride o = ( ReplaceOverride) pop(); // don't inline
> getBeanDefinition().getMethodOverrides().addOverride(o);
> }
> }
>
>
> public class BeanReplacedMethodArgTypeRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> ReplaceOverride replaceOverride = ( ReplaceOverride) peek();
> String typeId = atts.getValue(ARG_TYPE_MATCH_ATTRIBUTE);
> replaceOverride.addTypeIdentifier(typeId==null ? "" : typeId);
> }
>
>// public void text( String arg0, String arg1, String arg2) {
>// // TODO !!!
>// ....
>// }
>//
>// public void end( String arg0, String arg1) {
>// ...
>// }
> }
>
>
> /**
> * (entry)*
> */
> public class MapRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> push( new ManagedMap());
> }
> public void end( String ns, String name) {
> setValue(pop());
> }
> }
>
>
> /**
> * key?, (bean | ref | idref | value | null | list | set | map | props)?
> */
> public class MapEntryRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String keyAttribute = atts.getValue(KEY_ATTRIBUTE);
> String keyRefAttribute = atts.getValue(KEY_REF_ATTRIBUTE);
> if (keyAttribute!=null && keyRefAttribute!=null) {
> throw new BeanDefinitionStoreException(
> getResource(), getBeanDefinitionHolder().getBeanName(), "<entry> is only allowed to contain either " +
> "a 'key' attribute OR a 'key-ref' attribute OR a <key> sub-element");
> }
>
> Object key = null;
> if (keyAttribute!=null) {
> key = keyAttribute;
> } else if (keyRefAttribute!=null) {
> key = new RuntimeBeanReference(keyRefAttribute);
> }
>
> String valueAttribute = atts.getValue(VALUE_ATTRIBUTE);
> String valueRefAttribute = atts.getValue(VALUE_REF_ATTRIBUTE);
> if (valueAttribute!=null && valueRefAttribute!=null) {
> throw new BeanDefinitionStoreException(
> getResource(), getBeanDefinitionHolder().getBeanName(), "<entry> is only allowed to contain either " +
> "a 'value' attribute OR a 'value-ref' attribute OR a value sub-element");
> }
> Object value = null;
> if (valueAttribute!=null) {
> value = valueAttribute;
> } else if (valueRefAttribute!=null) {
> value = new RuntimeBeanReference(valueRefAttribute);
> }
>
> push( new MapEntryHolder( key, value));
>
> }
> public void end( String ns, String name) {
> MapEntryHolder entry = (MapEntryHolder) pop();
> ManagedMap map = ( ManagedMap) peek();
> map.put(entry.getKey(), entry.getValue());
> }
> }
>
>
> /**
> * (bean | ref | idref | value | null | list | set | map | props)
> */
> public class MapEntryKeyRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> push( new MapEntryKeyHolder(null));
> }
> public void end( String ns, String name) {
> Object key = ((MapEntryKeyHolder)pop()).getKey();
> (( MapEntryHolder) peek()).setKey(key);
> }
> }
>
>
> /**
> * (bean | ref | idref | value | null | list | set | map | props)*
> */
> public class SetType extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> push( new ManagedSet());
> }
> public void end( String ns, String name) {
> setValue(pop());
> }
> }
>
>
> /**
> * (bean | ref | idref | value | null | list | set | map | props)*
> */
> public class ListRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> push( new ManagedList());
> }
>
> public void end( String ns, String name) {
> setValue(pop());
> }
> }
>
>
> public class NullRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> setValue(null);
> }
> }
>
>
> public class ValueRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String typeClassName = atts.getValue( TYPE_ATTRIBUTE);
> push(typeClassName);
> }
> public void text( String ns, String name, String text) {
> push(text);
> }
> public void end( String ns, String name) {
> String value = ( String) pop();
> String typeClassName = ( String) pop();
> if (typeClassName!=null) {
> try {
> Class typeClass = ClassUtils.forName(typeClassName, getBeanDefinitionReader().getBeanClassLoader());
> setValue(new TypedStringValue(value, typeClass));
> } catch (ClassNotFoundException ex) {
> throw new BeanDefinitionStoreException(
> getResource(), getBeanDefinitionHolder().getBeanName(), "Value type class [" + typeClassName + "] not found", ex);
> }
> } else {
> setValue(value);
> }
> }
> }
>
>
> public class IdRefRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> // A generic reference to any name of any bean.
> String beanRef = atts.getValue(BEAN_REF_ATTRIBUTE);
> if (!StringUtils.hasLength(beanRef)) {
> // A reference to the id of another bean in the same XML file.
> beanRef = atts.getValue(LOCAL_REF_ATTRIBUTE);
> if (!StringUtils.hasLength(beanRef)) {
> throw new BeanDefinitionStoreException(
> getResource(), getBeanDefinitionHolder().getBeanName(), "Either 'bean' or 'local' is required for an idref");
> }
> }
>
> setValue(beanRef);
> }
> }
>
>
> public class RefRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> RuntimeBeanReference ref;
>
> String beanRef = atts.getValue(BEAN_REF_ATTRIBUTE);
> if (!StringUtils.hasLength(beanRef)) {
> // A reference to the id of another bean in the same XML file.
> beanRef = atts.getValue(LOCAL_REF_ATTRIBUTE);
> if (!StringUtils.hasLength(beanRef)) {
> // A reference to the id of another bean in a parent context.
> beanRef = atts.getValue(PARENT_REF_ATTRIBUTE);
> if (!StringUtils.hasLength(beanRef)) {
> throw new BeanDefinitionStoreException(
> getResource(), getBeanDefinitionHolder().getBeanName(), "'bean', 'local' or 'parent' is required for a reference");
> }
> ref = new RuntimeBeanReference(beanRef, true);
> } else {
> ref = new RuntimeBeanReference(beanRef);
> }
> } else {
> ref = new RuntimeBeanReference(beanRef);
> }
>
> setValue(ref);
> }
> }
>
>
> /**
> * (prop)*
> */
> public class PropsRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> push( new Properties());
> }
> public void end( String ns, String name) {
> setValue(pop());
> }
> }
>
>
> public class PropsPropRule extends Rule {
> public void begin( String ns, String name, Attributes atts) {
> String key = atts.getValue(KEY_ATTRIBUTE);
> push(key);
> }
> public void text( String ns, String name, String text) {
> // Trim the text value to avoid unwanted whitespace
> // caused by typical XML formatting.
> push(text.trim());
> }
> public void end( String ns, String name) {
> String value = ( String) pop();
> String key = ( String) pop();
> Properties props = ( Properties) peek();
> props.setProperty(key, value);
> }
> }
>
>
> public static class ConstructorArgumentValuesHolder {
> private final String index;
> private final String type;
> private Object value;
>
> public ConstructorArgumentValuesHolder( String index, String type, Object value) {
> this.index = index;
> this.type = type;
> this.value = value;
> }
>
> public String getIndex() {
> return index;
> }
>
> public String getType() {
> return type;
> }
>
> public Object getValue() {
> return value;
> }
>
> public void setValue( Object value) {
> this.value = value;
> }
>
> }
>
>
> public static class PropertyValueHolder {
> private final String name;
> private Object value;
>
> public PropertyValueHolder( String name, Object value) {
> this.name = name;
> this.value = value;
> }
>
> public String getName() {
> return name;
> }
>
> public Object getValue() {
> return value;
> }
>
> public void setValue( Object value) {
> this.value = value;
> }
>
> }
>
>
> public static class MapEntryHolder {
> private Object key;
> private Object value;
>
> public MapEntryHolder( Object key, Object value) {
> this.key = key;
> this.value = value;
> }
>
> public Object getKey() {
> return key;
> }
>
> public Object getValue() {
> return value;
> }
>
> public void setKey( Object key) {
> this.key = key;
> }
>
> public void setValue( Object value) {
> this.value = value;
> }
>
> }
>
>
> public static class MapEntryKeyHolder {
> private Object key;
>
> public MapEntryKeyHolder( Object key) {
> this.key = key;
> }
>
> public Object getKey() {
> return key;
> }
>
> public void setKey( Object key) {
> this.key = key;
> }
>
> }
>
>}
>
>
>
|