View Javadoc

1   package org.springframework.batch.core.configuration.xml;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.springframework.batch.core.listener.AbstractListenerFactoryBean;
7   import org.springframework.batch.core.listener.ListenerMetaData;
8   import org.springframework.beans.BeanMetadataElement;
9   import org.springframework.beans.factory.config.BeanDefinition;
10  import org.springframework.beans.factory.config.BeanDefinitionHolder;
11  import org.springframework.beans.factory.config.RuntimeBeanReference;
12  import org.springframework.beans.factory.support.AbstractBeanDefinition;
13  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
14  import org.springframework.beans.factory.support.ManagedMap;
15  import org.springframework.beans.factory.xml.ParserContext;
16  import org.springframework.util.StringUtils;
17  import org.springframework.util.xml.DomUtils;
18  import org.w3c.dom.Element;
19  
20  /**
21   * @author Dan Garrette
22   * @since 2.0
23   * @see StepListenerParser
24   * @see JobExecutionListenerParser
25   */
26  public abstract class AbstractListenerParser {
27  
28  	private static final String ID_ATTR = "id";
29  
30  	private static final String REF_ATTR = "ref";
31  
32  	private static final String BEAN_ELE = "bean";
33  
34  	private static final String REF_ELE = "ref";
35  
36  	public AbstractBeanDefinition parse(Element element, ParserContext parserContext) {
37  		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(getBeanClass());
38  		doParse(element, parserContext, builder);
39  		return builder.getBeanDefinition();
40  	}
41  
42  	@SuppressWarnings("unchecked")
43  	public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
44  		builder.addPropertyValue("delegate", parseListenerElement(element, parserContext, builder.getRawBeanDefinition()));
45  
46  		ManagedMap metaDataMap = new ManagedMap();
47  		for (String metaDataPropertyName : getMethodNameAttributes()) {
48  			String listenerMethod = element.getAttribute(metaDataPropertyName);
49  			if (StringUtils.hasText(listenerMethod)) {
50  				metaDataMap.put(metaDataPropertyName, listenerMethod);
51  			}
52  		}
53  		builder.addPropertyValue("metaDataMap", metaDataMap);
54  	}
55  
56  	@SuppressWarnings("unchecked")
57  	public static BeanMetadataElement parseListenerElement(Element element, ParserContext parserContext, BeanDefinition enclosing) {
58  		String listenerRef = element.getAttribute(REF_ATTR);
59  		List<Element> beanElements = DomUtils.getChildElementsByTagName(element, BEAN_ELE);
60  		List<Element> refElements = DomUtils.getChildElementsByTagName(element, REF_ELE);
61  
62  		verifyListenerAttributesAndSubelements(listenerRef, beanElements, refElements, element, parserContext);
63  
64  		if (StringUtils.hasText(listenerRef)) {
65  			return new RuntimeBeanReference(listenerRef);
66  		}
67  		else if (beanElements.size() == 1) {
68  			Element beanElement = beanElements.get(0);
69  			BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
70  					beanElement, enclosing);
71  			parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
72  			return beanDefinitionHolder;
73  		}
74  		else {
75  			return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElements.get(0), null);
76  		}
77  	}
78  
79  	private static void verifyListenerAttributesAndSubelements(String listenerRef, List<Element> beanElements,
80  			List<Element> refElements, Element element, ParserContext parserContext) {
81  		int total = (StringUtils.hasText(listenerRef) ? 1 : 0) + beanElements.size() + refElements.size();
82  		if (total != 1) {
83  			StringBuilder found = new StringBuilder();
84  			if (total == 0) {
85  				found.append("None");
86  			}
87  			else {
88  				if (StringUtils.hasText(listenerRef)) {
89  					found.append("'" + REF_ATTR + "' attribute, ");
90  				}
91  				if (beanElements.size() == 1) {
92  					found.append("<" + BEAN_ELE + "/> element, ");
93  				}
94  				else if (beanElements.size() > 1) {
95  					found.append(beanElements.size() + " <" + BEAN_ELE + "/> elements, ");
96  				}
97  				if (refElements.size() == 1) {
98  					found.append("<" + REF_ELE + "/> element, ");
99  				}
100 				else if (refElements.size() > 1) {
101 					found.append(refElements.size() + " <" + REF_ELE + "/> elements, ");
102 				}
103 				found.delete(found.length() - 2, found.length());
104 			}
105 
106 			String id = element.getAttribute(ID_ATTR);
107 			parserContext.getReaderContext().error(
108 					"The <" + element.getTagName() + (StringUtils.hasText(id) ? " id=\"" + id + "\"" : "")
109 							+ "/> element must have exactly one of: '" + REF_ATTR + "' attribute, <" + BEAN_ELE
110 							+ "/> attribute, or <" + REF_ELE + "/> element.  Found: " + found + ".", element);
111 		}
112 	}
113 
114 	private List<String> getMethodNameAttributes() {
115 		List<String> methodNameAttributes = new ArrayList<String>();
116 		for (ListenerMetaData metaData : getMetaDataValues()) {
117 			methodNameAttributes.add(metaData.getPropertyName());
118 		}
119 		return methodNameAttributes;
120 	}
121 
122 	protected abstract Class<? extends AbstractListenerFactoryBean> getBeanClass();
123 
124 	protected abstract ListenerMetaData[] getMetaDataValues();
125 
126 }