001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.sys.spring.datadictionary;
017    
018    import org.apache.log4j.Logger;
019    import org.springframework.beans.factory.support.AbstractBeanDefinition;
020    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
021    import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
022    import org.springframework.beans.factory.xml.ParserContext;
023    import org.springframework.util.StringUtils;
024    import org.w3c.dom.Element;
025    import org.w3c.dom.Node;
026    import org.w3c.dom.NodeList;
027    
028    public abstract class KualiBeanDefinitionParserBase extends AbstractBeanDefinitionParser {
029    
030        private static Logger LOG = Logger.getLogger(KualiBeanDefinitionParserBase.class);
031        
032        protected void parseEmbeddedPropertyElements(Element element, BeanDefinitionBuilder bean) {
033            NodeList children = element.getChildNodes();
034            for ( int i = 0; i < children.getLength(); i++ ) {
035                Node child = children.item(i);
036                if ( child.getLocalName() != null && child.getLocalName().equals("property") ) {
037                    Element propertyElement = (Element)child;                
038                    String propName = propertyElement.getAttribute("name");
039                    String propValue = propertyElement.getAttribute("value");
040                    if ( propValue != null ) {
041                        bean.addPropertyValue(propName, propValue);
042                    } else if ( propertyElement.getAttribute("ref") != null ) {
043                        bean.addPropertyReference(propName, propertyElement.getAttribute("ref") );
044                    }
045                }
046            }        
047        }
048        
049        protected void handleAbstractAttribute( Element element, BeanDefinitionBuilder bean) {
050            String abstractStr = element.getAttribute("abstract");
051            
052            if ( StringUtils.hasText(abstractStr) ) {
053                bean.setAbstract( Boolean.valueOf(abstractStr) );
054            }
055        }
056        
057        /* The below copied from AbstractSingleBeanDefinitionParser and modified to allow for parent beans to be handled. */
058        /**
059         * Creates a {@link BeanDefinitionBuilder} instance for the
060         * {@link #getBeanClass bean Class} and passes it to the
061         * {@link #doParse} strategy method.
062         * @param element the element that is to be parsed into a single BeanDefinition
063         * @param parserContext the object encapsulating the current state of the parsing process
064         * @return the BeanDefinition resulting from the parsing of the supplied {@link Element}
065         * @throws IllegalStateException if the bean {@link Class} returned from
066         * {@link #getBeanClass(org.w3c.dom.Element)} is <code>null</code>
067         * @see #doParse
068         */
069        @SuppressWarnings("unchecked")
070        protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
071            BeanDefinitionBuilder builder = null;
072            
073            String parent = element.getAttribute("parent");
074            String beanClass = element.getAttribute("class");
075            if ( StringUtils.hasText(beanClass) ) {
076                try {
077                    builder = BeanDefinitionBuilder.rootBeanDefinition(Class.forName(beanClass));
078                } catch (Exception ex) {
079                    LOG.fatal( "Unable to resolve class given in class element of a " + element.getLocalName() + " element with id " + element.getAttribute("id"), ex );
080                    throw new RuntimeException(ex);
081                }
082            } else  if ( StringUtils.hasText(parent)) {
083                builder = BeanDefinitionBuilder.childBeanDefinition(parent);
084            } else if ( getBeanClass(element) != null ) {
085                builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClass(element));
086            } else {
087                builder = BeanDefinitionBuilder.childBeanDefinition(getBaseBeanTypeParent(element)); 
088            }
089            builder.setSource(parserContext.extractSource(element));
090            if (parserContext.isNested()) {
091                // Inner bean definition must receive same singleton status as containing bean.
092                builder.setSingleton(parserContext.getContainingBeanDefinition().isSingleton());
093            }
094            if (parserContext.isDefaultLazyInit()) {
095                // Default-lazy-init applies to custom bean definitions as well.
096                builder.setLazyInit(true);
097            }
098            doParse(element, parserContext, builder);
099            return builder.getBeanDefinition();
100        }
101    
102        /**
103         * Parse the supplied {@link Element} and populate the supplied
104         * {@link BeanDefinitionBuilder} as required.
105         * <p>The default implementation delegates to the <code>doParse</code>
106         * version without ParserContext argument.
107         * @param element the XML element being parsed
108         * @param parserContext the object encapsulating the current state of the parsing process
109         * @param builder used to define the <code>BeanDefinition</code>
110         * @see #doParse(Element, BeanDefinitionBuilder)
111         */
112        protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
113    
114        protected abstract String getBaseBeanTypeParent( Element element );
115        
116        protected Class getBeanClass( Element element ) {
117            return null;
118        }
119    }