OPEN - issue BATCH-911: Consolidate Samples

http://jira.springframework.org/browse/BATCH-911

Added support for listeners that implement the interface, along with support for class attribute in listener tag.
This commit is contained in:
lucasward
2008-11-19 07:02:32 +00:00
parent 6e39c1a572
commit 6a66b0efed
5 changed files with 218 additions and 5 deletions

View File

@@ -16,21 +16,26 @@
package org.springframework.batch.core.configuration.xml;
import static org.springframework.util.StringUtils.hasText;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.listener.JobExecutionListenerAdapter;
import org.springframework.batch.core.listener.JobExecutionListenerFactoryBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
* {@link BeanDefinitionParser} for {@link JobExecutionListener}s
@@ -48,9 +53,39 @@ public class JobExecutionListenerParser {
@SuppressWarnings("unchecked")
List<Element> listenerElements = (List<Element>) DomUtils.getChildElementsByTagName(element, "listener");
for(Element listenerElement : listenerElements){
BeanDefinitionBuilder listenerBuilder = BeanDefinitionBuilder.genericBeanDefinition(JobExecutionListenerAdapter.class);
String delegateName = listenerElement.getAttribute("ref");
listenerBuilder.addConstructorArgReference(delegateName);
BeanDefinitionBuilder listenerBuilder = BeanDefinitionBuilder.genericBeanDefinition(JobExecutionListenerFactoryBean.class);
String id = listenerElement.getAttribute("id");
String listenerRef = listenerElement.getAttribute("ref");
String className = listenerElement.getAttribute("class");
if ((StringUtils.hasText(id) || StringUtils.hasText(className))
&& StringUtils.hasText(listenerRef)) {
NamedNodeMap attributeNodes = listenerElement.getAttributes();
StringBuilder attributes = new StringBuilder();
for (int i = 0; i < attributeNodes.getLength(); i++) {
if (i > 0) {
attributes.append(" ");
}
attributes.append(attributeNodes.item(i));
}
throw new BeanCreationException("Both 'ref' and 'class' specified; use 'class' with an optional 'id' or just 'ref' for <" +
listenerElement.getTagName() + "> element with attributes: " + attributes);
}
if(hasText(listenerRef)){
listenerBuilder.addPropertyReference("delegate", listenerRef);
}
else if(hasText(className)){
RootBeanDefinition beanDef = new RootBeanDefinition(className, null, null);
if (!StringUtils.hasText(id)) {
id = parserContext.getReaderContext().generateBeanName(beanDef);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDef);
listenerBuilder.addPropertyReference("delegate", id);
}
else {
throw new BeanCreationException("Neither 'ref' or 'class' specified for <" + listenerElement.getTagName() + "> element");
}
String beforeMethod = listenerElement.getAttribute("before-method");
if(StringUtils.hasText(beforeMethod)){
@@ -62,7 +97,6 @@ public class JobExecutionListenerParser {
listenerBuilder.addPropertyValue("afterMethod", afterMethod);
}
AbstractBeanDefinition beanDef = listenerBuilder.getBeanDefinition();
String id = listenerElement.getAttribute("id");
if (!StringUtils.hasText(id)) {
id = parserContext.getReaderContext().generateBeanName(beanDef);
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.listener;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* {@link FactoryBean} implementation that accepts a delgate, checking whether
* or not it implements the {@link JobExecutionListener} interface, and if so, passes directly
* through. However, if it does not implement the interface, {@link JobExecutionListenerAdapter}
* is used to
*
* @author Lucas Ward
*
*/
public class JobExecutionListenerFactoryBean implements FactoryBean, InitializingBean{
private Object delegate;
private String beforeMethod;
private String afterMethod;
public void setDelegate(Object delegate) {
this.delegate = delegate;
}
public void setBeforeMethod(String beforeMethod) {
this.beforeMethod = beforeMethod;
}
public void setAfterMethod(String afterMethod) {
this.afterMethod = afterMethod;
}
public Object getObject() throws Exception {
if(delegate instanceof JobExecutionListener){
return delegate;
}
else{
JobExecutionListenerAdapter listenerAdapter = new JobExecutionListenerAdapter(delegate);
listenerAdapter.setBeforeMethod(beforeMethod);
listenerAdapter.setAfterMethod(afterMethod);
listenerAdapter.afterPropertiesSet();
return listenerAdapter;
}
}
@SuppressWarnings("unchecked")
public Class getObjectType() {
return JobExecutionListener.class;
}
public boolean isSingleton() {
return false;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(delegate, "Delegate listener must not be null");
}
}

View File

@@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.annotation.AfterJob;
import org.springframework.batch.core.annotation.BeforeJob;
@@ -32,12 +33,15 @@ public class JobExecutionListenerAdapterTests {
private TestClass testClass;
private AnnotatedTestClass annotatedTestClass;
private InterfaceTestClass interfaceTestClass;
private JobExecution jobExecution = new JobExecution(11L);
@Before
public void setUp(){
testClass = new TestClass();
annotatedTestClass = new AnnotatedTestClass();
interfaceTestClass = new InterfaceTestClass();
}
@Test
@@ -90,6 +94,16 @@ public class JobExecutionListenerAdapterTests {
assertTrue(annotatedTestClass.afterJobCalled);
}
@Test
public void testWithInterface() throws Exception{
JobExecutionListenerAdapter adapter = new JobExecutionListenerAdapter(interfaceTestClass);
adapter.afterPropertiesSet();
adapter.beforeJob(jobExecution);
adapter.afterJob(jobExecution);
assertTrue(annotatedTestClass.beforeJobCalled);
assertTrue(annotatedTestClass.afterJobCalled);
}
private class TestClass{
boolean beforeJobCalled = false;
@@ -116,4 +130,9 @@ public class JobExecutionListenerAdapterTests {
super.afterJobCalled = true;
}
}
private class InterfaceTestClass extends TestClass implements JobExecutionListener {
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.listener;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.annotation.AfterJob;
import org.springframework.batch.core.annotation.BeforeJob;
/**
* @author Lucas Ward
*
*/
public class JobExecutionListnerFactoryBeanTests {
JobExecutionListenerFactoryBean factoryBean;
@Before
public void setUp(){
factoryBean = new JobExecutionListenerFactoryBean();
}
@Test
public void testWithInterface() throws Exception{
JobListenerWithInterface delegate = new JobListenerWithInterface();
factoryBean.setDelegate(delegate);
assertEquals(delegate,factoryBean.getObject());
}
@Test
public void testWithAnnotations() throws Exception{
AnnotatedTestClass delegate = new AnnotatedTestClass();
factoryBean.setDelegate(delegate);
JobExecutionListener listener = (JobExecutionListener) factoryBean.getObject();
JobExecution jobExecution = new JobExecution(11L);
listener.beforeJob(jobExecution);
listener.afterJob(jobExecution);
assertTrue(delegate.beforeJobCalled);
assertTrue(delegate.afterJobCalled);
}
private class JobListenerWithInterface implements JobExecutionListener{
public void afterJob(JobExecution jobExecution) {
}
public void beforeJob(JobExecution jobExecution) {
}
}
private class AnnotatedTestClass {
boolean beforeJobCalled = false;
boolean afterJobCalled = false;
@BeforeJob
public void before(){
beforeJobCalled = true;
}
@AfterJob
public void after(){
afterJobCalled = true;
}
}
}

View File

@@ -12,6 +12,7 @@
</step>
<listeners>
<listener after-method="afterJob" ref="testListener"/>
<listener after-method="afterJob" class="org.springframework.batch.core.configuration.xml.TestJobListener"/>
</listeners>
</job>