diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameter.java index 03d0bb1f7..c800cc475 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameter.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameter.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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; import java.io.Serializable; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java index 0041b25ae..d36195a9a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParameters.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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; import java.io.Serializable; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java index 0792b9f32..9b3ed50b3 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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; import java.util.Date; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/StartLimitExceededException.java b/spring-batch-core/src/main/java/org/springframework/batch/core/StartLimitExceededException.java index 7e0a79bf3..7776b2b71 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/StartLimitExceededException.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/StartLimitExceededException.java @@ -1,11 +1,27 @@ -package org.springframework.batch.core; - -/** - * Indicates the step's start limit has been exceeded. - */ -public class StartLimitExceededException extends RuntimeException { - - public StartLimitExceededException(String message) { - super(message); - } -} +/* + * Copyright 2006-2007 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; + +/** + * Indicates the step's start limit has been exceeded. + */ +public class StartLimitExceededException extends RuntimeException { + + public StartLimitExceededException(String message) { + super(message); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterJob.java index 85b98d206..dcf6bafeb 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterJob.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterProcess.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterProcess.java index bfdeccdf5..b2f5fa8fe 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterProcess.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterProcess.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterStep.java index a0e4ae9f3..f72eb9884 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterStep.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterWrite.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterWrite.java index 2277f1e70..731520d5d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterWrite.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/AfterWrite.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeJob.java index ba531acce..1fecc3f7b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeJob.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeStep.java index 7bcd88920..a67673427 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeStep.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeWrite.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeWrite.java index 3caa3099c..02a13c351 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeWrite.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/BeforeWrite.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnProcessError.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnProcessError.java index fbf00fd9d..e01c4bc64 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnProcessError.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnProcessError.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInProcess.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInProcess.java index 434c907f6..29e0e2194 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInProcess.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInProcess.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInRead.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInRead.java index 991d4f87f..5745155dc 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInRead.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInRead.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInWrite.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInWrite.java index 74f8ac506..2f4a6fc2d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInWrite.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnSkipInWrite.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnWriteError.java b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnWriteError.java index 5fa33872a..fb1ffd39b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnWriteError.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/annotation/OnWriteError.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.annotation; import java.lang.annotation.ElementType; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ApplicationContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ApplicationContextFactory.java index 624cde579..d0fe30475 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ApplicationContextFactory.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ApplicationContextFactory.java @@ -1,9 +1,25 @@ -package org.springframework.batch.core.configuration.support; - -import org.springframework.context.ConfigurableApplicationContext; - -public interface ApplicationContextFactory { - - ConfigurableApplicationContext createApplicationContext(); - -} +/* + * Copyright 2006-2007 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.configuration.support; + +import org.springframework.context.ConfigurableApplicationContext; + +public interface ApplicationContextFactory { + + ConfigurableApplicationContext createApplicationContext(); + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java index aac1493a6..6d7cf97b5 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java @@ -1,68 +1,84 @@ -package org.springframework.batch.core.configuration.support; - -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.AbstractXmlApplicationContext; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -public class ClassPathXmlApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware { - - private ConfigurableApplicationContext parent; - - private Resource path; - - /** - * Setter for the path to the xml to load to create an - * {@link ApplicationContext}. Use imports to centralise the configuration in - * one file. - * - * @param path the resource path to the xml to load for the child context. - */ - public void setPath(Resource path) { - this.path = path; - } - - /** - * Setter for the parent application context. - * - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext); - parent = (ConfigurableApplicationContext) applicationContext; - } - - /** - * Creates an {@link ApplicationContext} from the provided path. - * - * @see ApplicationContextFactory#createApplicationContext() - */ - public ConfigurableApplicationContext createApplicationContext() { - if (path == null) { - return parent; - } - return new ResourceXmlApplicationContext(parent); - } - - /** - * @author Dave Syer - * - */ - private final class ResourceXmlApplicationContext extends AbstractXmlApplicationContext { - /** - * @param parent - */ - private ResourceXmlApplicationContext(ApplicationContext parent) { - super(parent); - refresh(); - } - - protected Resource[] getConfigResources() { - return new Resource[] {path}; - } - } - -} +/* + * Copyright 2006-2007 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.configuration.support; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +public class ClassPathXmlApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware { + + private ConfigurableApplicationContext parent; + + private Resource path; + + /** + * Setter for the path to the xml to load to create an + * {@link ApplicationContext}. Use imports to centralise the configuration in + * one file. + * + * @param path the resource path to the xml to load for the child context. + */ + public void setPath(Resource path) { + this.path = path; + } + + /** + * Setter for the parent application context. + * + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext); + parent = (ConfigurableApplicationContext) applicationContext; + } + + /** + * Creates an {@link ApplicationContext} from the provided path. + * + * @see ApplicationContextFactory#createApplicationContext() + */ + public ConfigurableApplicationContext createApplicationContext() { + if (path == null) { + return parent; + } + return new ResourceXmlApplicationContext(parent); + } + + /** + * @author Dave Syer + * + */ + private final class ResourceXmlApplicationContext extends AbstractXmlApplicationContext { + /** + * @param parent + */ + private ResourceXmlApplicationContext(ApplicationContext parent) { + super(parent); + refresh(); + } + + protected Resource[] getConfigResources() { + return new Resource[] {path}; + } + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java index 0f3dcbc08..99e29d44f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.configuration.support; import java.util.Collection; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobFactoryRegistrationListener.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobFactoryRegistrationListener.java index 01c730b22..1521a15af 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobFactoryRegistrationListener.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobFactoryRegistrationListener.java @@ -1,57 +1,73 @@ -package org.springframework.batch.core.configuration.support; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.configuration.JobFactory; -import org.springframework.batch.core.configuration.JobRegistry; - -/** - * Generic service that can bind and unbind a {@link JobFactory} in a - * {@link JobRegistry}. - * - * @author Dave Syer - * - */ -public class JobFactoryRegistrationListener { - - private Log logger = LogFactory.getLog(getClass()); - - private JobRegistry jobRegistry; - - /** - * Public setter for a {@link JobRegistry} to use for all the bind and - * unbind events. - * - * @param jobRegistry {@link JobRegistry} - */ - public void setJobRegistry(JobRegistry jobRegistry) { - this.jobRegistry = jobRegistry; - } - - /** - * Take the {@link JobFactory} provided and register it with the - * {@link JobRegistry}. - * @param jobFactory a {@link JobFactory} - * @param params not needed by this listener. - * @throws Exception if there is a problem - */ - public void bind(JobFactory jobFactory, Map params) throws Exception { - logger.info("Binding JobFactory: " + jobFactory.getJobName()); - jobRegistry.register(jobFactory); - } - - /** - * Take the {@link JobFactory} provided and unregister it with the - * {@link JobRegistry}. - * @param jobFactory a {@link JobFactory} - * @param params not needed by this listener. - * @throws Exception if there is a problem - */ - public void unbind(JobFactory jobFactory, Map params) throws Exception { - logger.info("Unbinding JobFactory: " + jobFactory.getJobName()); - jobRegistry.unregister(jobFactory.getJobName()); - } - -} +/* + * Copyright 2006-2007 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.configuration.support; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.configuration.JobFactory; +import org.springframework.batch.core.configuration.JobRegistry; + +/** + * Generic service that can bind and unbind a {@link JobFactory} in a + * {@link JobRegistry}. + * + * @author Dave Syer + * + */ +public class JobFactoryRegistrationListener { + + private Log logger = LogFactory.getLog(getClass()); + + private JobRegistry jobRegistry; + + /** + * Public setter for a {@link JobRegistry} to use for all the bind and + * unbind events. + * + * @param jobRegistry {@link JobRegistry} + */ + public void setJobRegistry(JobRegistry jobRegistry) { + this.jobRegistry = jobRegistry; + } + + /** + * Take the {@link JobFactory} provided and register it with the + * {@link JobRegistry}. + * @param jobFactory a {@link JobFactory} + * @param params not needed by this listener. + * @throws Exception if there is a problem + */ + public void bind(JobFactory jobFactory, Map params) throws Exception { + logger.info("Binding JobFactory: " + jobFactory.getJobName()); + jobRegistry.register(jobFactory); + } + + /** + * Take the {@link JobFactory} provided and unregister it with the + * {@link JobRegistry}. + * @param jobFactory a {@link JobFactory} + * @param params not needed by this listener. + * @throws Exception if there is a problem + */ + public void unbind(JobFactory jobFactory, Map params) throws Exception { + logger.info("Unbinding JobFactory: " + jobFactory.getJobName()); + jobRegistry.unregister(jobFactory.getJobName()); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java index 9a927d845..ea6d2c52a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java @@ -1,74 +1,90 @@ -package org.springframework.batch.core.configuration.support; - -import org.osgi.framework.BundleContext; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.osgi.context.BundleContextAware; -import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext; - -public class OsgiBundleXmlApplicationContextFactory implements BundleContextAware, - ApplicationContextFactory, ApplicationContextAware { - - private BundleContext bundleContext; - - private ApplicationContext parent; - - private String path; - - private String displayName; - - /** - * @param path - * the resource path to the xml to load for the child context. - */ - public void setPath(String path) { - this.path = path; - } - - /** - * @param displayName the display name for the application context created. - */ - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - /** - * Setter for the parent application context. - * - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - parent = applicationContext; - } - - /** - * Stash the {@link BundleContext} for creating a job application context - * later. - * - * @see org.springframework.osgi.context.BundleContextAware#setBundleContext(org.osgi.framework.BundleContext) - */ - public void setBundleContext(BundleContext context) { - this.bundleContext = context; - } - - /** - * Create an application context from the provided path, using the current - * OSGi {@link BundleContext} and the enclosing Spring - * {@link ApplicationContext} as a parent context. - * - * @see ApplicationContextFactory#createApplicationContext() - */ - public ConfigurableApplicationContext createApplicationContext() { - OsgiBundleXmlApplicationContext context = new OsgiBundleXmlApplicationContext( - new String[] { path }, parent); - String displayName = bundleContext.getBundle().getSymbolicName() + ":" + this.displayName; - context.setDisplayName(displayName); - context.setBundleContext(bundleContext); - context.refresh(); - return context; - } - -} +/* + * Copyright 2006-2007 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.configuration.support; + +import org.osgi.framework.BundleContext; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.osgi.context.BundleContextAware; +import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext; + +public class OsgiBundleXmlApplicationContextFactory implements BundleContextAware, + ApplicationContextFactory, ApplicationContextAware { + + private BundleContext bundleContext; + + private ApplicationContext parent; + + private String path; + + private String displayName; + + /** + * @param path + * the resource path to the xml to load for the child context. + */ + public void setPath(String path) { + this.path = path; + } + + /** + * @param displayName the display name for the application context created. + */ + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + /** + * Setter for the parent application context. + * + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + parent = applicationContext; + } + + /** + * Stash the {@link BundleContext} for creating a job application context + * later. + * + * @see org.springframework.osgi.context.BundleContextAware#setBundleContext(org.osgi.framework.BundleContext) + */ + public void setBundleContext(BundleContext context) { + this.bundleContext = context; + } + + /** + * Create an application context from the provided path, using the current + * OSGi {@link BundleContext} and the enclosing Spring + * {@link ApplicationContext} as a parent context. + * + * @see ApplicationContextFactory#createApplicationContext() + */ + public ConfigurableApplicationContext createApplicationContext() { + OsgiBundleXmlApplicationContext context = new OsgiBundleXmlApplicationContext( + new String[] { path }, parent); + String displayName = bundleContext.getBundle().getSymbolicName() + ":" + this.displayName; + context.setDisplayName(displayName); + context.setBundleContext(bundleContext); + context.refresh(); + return context; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/AbstractJobExplorerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/AbstractJobExplorerFactoryBean.java index 7278e58bf..1db77387f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/AbstractJobExplorerFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/AbstractJobExplorerFactoryBean.java @@ -1,47 +1,63 @@ -package org.springframework.batch.core.explore.support; - -import org.springframework.batch.core.explore.JobExplorer; -import org.springframework.batch.core.repository.dao.JobExecutionDao; -import org.springframework.batch.core.repository.dao.JobInstanceDao; -import org.springframework.batch.core.repository.dao.StepExecutionDao; -import org.springframework.beans.factory.FactoryBean; - -/** - * A {@link FactoryBean} that automates the creation of a - * {@link SimpleJobExplorer}. Declares abstract methods for providing DAO - * object implementations. - * - * @see JobExplorerFactoryBean - * @see MapJobExplorerFactoryBean - * - * @author Dave Syer - */ -public abstract class AbstractJobExplorerFactoryBean implements FactoryBean { - - /** - * @return fully configured {@link JobInstanceDao} implementation. - */ - protected abstract JobInstanceDao createJobInstanceDao() throws Exception; - - /** - * @return fully configured {@link JobExecutionDao} implementation. - */ - protected abstract JobExecutionDao createJobExecutionDao() throws Exception; - - protected abstract StepExecutionDao createStepExecutionDao() throws Exception; - - /** - * The type of object to be returned from {@link #getObject()}. - * - * @return JobExplorer.class - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ - public Class getObjectType() { - return JobExplorer.class; - } - - public boolean isSingleton() { - return true; - } - -} +/* + * Copyright 2006-2007 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.explore.support; + +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.repository.dao.JobExecutionDao; +import org.springframework.batch.core.repository.dao.JobInstanceDao; +import org.springframework.batch.core.repository.dao.StepExecutionDao; +import org.springframework.beans.factory.FactoryBean; + +/** + * A {@link FactoryBean} that automates the creation of a + * {@link SimpleJobExplorer}. Declares abstract methods for providing DAO + * object implementations. + * + * @see JobExplorerFactoryBean + * @see MapJobExplorerFactoryBean + * + * @author Dave Syer + */ +public abstract class AbstractJobExplorerFactoryBean implements FactoryBean { + + /** + * @return fully configured {@link JobInstanceDao} implementation. + */ + protected abstract JobInstanceDao createJobInstanceDao() throws Exception; + + /** + * @return fully configured {@link JobExecutionDao} implementation. + */ + protected abstract JobExecutionDao createJobExecutionDao() throws Exception; + + protected abstract StepExecutionDao createStepExecutionDao() throws Exception; + + /** + * The type of object to be returned from {@link #getObject()}. + * + * @return JobExplorer.class + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + public Class getObjectType() { + return JobExplorer.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/MapJobExplorerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/MapJobExplorerFactoryBean.java index 079da015b..8f2be18ea 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/MapJobExplorerFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/explore/support/MapJobExplorerFactoryBean.java @@ -1,38 +1,54 @@ -package org.springframework.batch.core.explore.support; - -import org.springframework.batch.core.repository.dao.JobExecutionDao; -import org.springframework.batch.core.repository.dao.JobInstanceDao; -import org.springframework.batch.core.repository.dao.MapJobExecutionDao; -import org.springframework.batch.core.repository.dao.MapJobInstanceDao; -import org.springframework.batch.core.repository.dao.MapStepExecutionDao; -import org.springframework.batch.core.repository.dao.StepExecutionDao; -import org.springframework.beans.factory.FactoryBean; - -/** - * A {@link FactoryBean} that automates the creation of a - * {@link SimpleJobExplorer} using in-memory DAO implementations. - * - * @author Dave Syer - */ -public class MapJobExplorerFactoryBean extends AbstractJobExplorerFactoryBean { - - @Override - protected JobExecutionDao createJobExecutionDao() throws Exception { - return new MapJobExecutionDao(); - } - - @Override - protected JobInstanceDao createJobInstanceDao() throws Exception { - return new MapJobInstanceDao(); - } - - @Override - protected StepExecutionDao createStepExecutionDao() throws Exception { - return new MapStepExecutionDao(); - } - - public Object getObject() throws Exception { - return new SimpleJobExplorer(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao()); - } - -} +/* + * Copyright 2006-2007 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.explore.support; + +import org.springframework.batch.core.repository.dao.JobExecutionDao; +import org.springframework.batch.core.repository.dao.JobInstanceDao; +import org.springframework.batch.core.repository.dao.MapJobExecutionDao; +import org.springframework.batch.core.repository.dao.MapJobInstanceDao; +import org.springframework.batch.core.repository.dao.MapStepExecutionDao; +import org.springframework.batch.core.repository.dao.StepExecutionDao; +import org.springframework.beans.factory.FactoryBean; + +/** + * A {@link FactoryBean} that automates the creation of a + * {@link SimpleJobExplorer} using in-memory DAO implementations. + * + * @author Dave Syer + */ +public class MapJobExplorerFactoryBean extends AbstractJobExplorerFactoryBean { + + @Override + protected JobExecutionDao createJobExecutionDao() throws Exception { + return new MapJobExecutionDao(); + } + + @Override + protected JobInstanceDao createJobInstanceDao() throws Exception { + return new MapJobInstanceDao(); + } + + @Override + protected StepExecutionDao createStepExecutionDao() throws Exception { + return new MapStepExecutionDao(); + } + + public Object getObject() throws Exception { + return new SimpleJobExplorer(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao()); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/DecisionState.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/DecisionState.java index 6ca2ce743..85f7876d2 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/DecisionState.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/DecisionState.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.job.flow.support.state; import org.springframework.batch.core.job.flow.FlowExecutor; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/EndState.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/EndState.java index 99e25a3b6..46acf6986 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/EndState.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/EndState.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.job.flow.support.state; import org.springframework.batch.core.BatchStatus; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/StepState.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/StepState.java index 9e6678552..d453d397f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/StepState.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/state/StepState.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.job.flow.support.state; import org.springframework.batch.core.Step; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/ExitCodeMapper.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/ExitCodeMapper.java index a936d81b3..f1b22c45a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/ExitCodeMapper.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/ExitCodeMapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.launch.support; /** diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/PartitionHandler.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/PartitionHandler.java index 2169cca6d..8ab11536e 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/PartitionHandler.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/PartitionHandler.java @@ -1,38 +1,54 @@ -package org.springframework.batch.core.partition; - -import java.util.Collection; - -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.item.ExecutionContext; - -/** - * Interface defining the responsibilities of controlling the execution of a - * partitioned {@link StepExecution}. Implementations will need to create a - * partition with the {@link StepExecutionSplitter}, and then use an execution - * fabric (grid, etc.), to execute the partitioned step. The results of the - * executions can be returned raw from remote workers to be aggregated by the - * caller. - * - * @author Dave Syer - * - */ -public interface PartitionHandler { - - /** - * Main entry point for {@link PartitionHandler} interface. The splitter - * creates all the executions that need to be farmed out, along with their - * input parameters (in the form of their {@link ExecutionContext}). The - * master step execution is used to identify the partition and group - * together the results logically. - * - * @param stepSplitter a strategy for generating a collection of - * {@link StepExecution} instances - * @param stepExecution the master step execution for the whole partition - * @return a collection of completed {@link StepExecution} instances - * @throws Exception if anything goes wrong. This allows implementations to - * be liberal and rely on the caller to translate an exception into a step - * failure as necessary. - */ - Collection handle(StepExecutionSplitter stepSplitter, StepExecution stepExecution) throws Exception; - -} +/* + * Copyright 2006-2007 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.partition; + +import java.util.Collection; + +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.item.ExecutionContext; + +/** + * Interface defining the responsibilities of controlling the execution of a + * partitioned {@link StepExecution}. Implementations will need to create a + * partition with the {@link StepExecutionSplitter}, and then use an execution + * fabric (grid, etc.), to execute the partitioned step. The results of the + * executions can be returned raw from remote workers to be aggregated by the + * caller. + * + * @author Dave Syer + * + */ +public interface PartitionHandler { + + /** + * Main entry point for {@link PartitionHandler} interface. The splitter + * creates all the executions that need to be farmed out, along with their + * input parameters (in the form of their {@link ExecutionContext}). The + * master step execution is used to identify the partition and group + * together the results logically. + * + * @param stepSplitter a strategy for generating a collection of + * {@link StepExecution} instances + * @param stepExecution the master step execution for the whole partition + * @return a collection of completed {@link StepExecution} instances + * @throws Exception if anything goes wrong. This allows implementations to + * be liberal and rely on the caller to translate an exception into a step + * failure as necessary. + */ + Collection handle(StepExecutionSplitter stepSplitter, StepExecution stepExecution) throws Exception; + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/StepExecutionSplitter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/StepExecutionSplitter.java index c9f5b9694..4bf931a5a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/StepExecutionSplitter.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/StepExecutionSplitter.java @@ -1,47 +1,63 @@ -package org.springframework.batch.core.partition; - -import java.util.Set; - -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobExecutionException; -import org.springframework.batch.core.StepExecution; - -/** - * Strategy interface for generating input contexts for a partitioned step - * execution independent from the fabric they are going to run on. - * - * @author Dave Syer - * - */ -public interface StepExecutionSplitter { - - /** - * The name of the step configuration that will be executed remotely. Remote - * workers are going to execute a the same step for each execution context - * in the partition. - * @return the name of the step that will execute the business logic - */ - String getStepName(); - - /** - * Partition the provided {@link StepExecution} into a set of parallel - * executable instances with the same parent {@link JobExecution}. The grid - * size will be treated as a hint for the size of the collection to be - * returned. It may or may not correspond to the physical size of an - * execution grid.
- *
- * - * On a restart clients of the {@link StepExecutionSplitter} should expect - * it to reconstitute the state of the last failed execution and only return - * those executions that need to be restarted. Thus the grid size hint will - * be ignored on a restart. - * - * @param stepExecution the {@link StepExecution} to be partitioned. - * @param gridSize a hint for the splitter if the size of the grid is known - * @return a set of {@link StepExecution} instances for remote processing - * - * @throws JobExecutionException if the split cannot be made - */ - Set split(StepExecution stepExecution, int gridSize) throws JobExecutionException; - +/* + * Copyright 2006-2007 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.partition; + +import java.util.Set; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionException; +import org.springframework.batch.core.StepExecution; + +/** + * Strategy interface for generating input contexts for a partitioned step + * execution independent from the fabric they are going to run on. + * + * @author Dave Syer + * + */ +public interface StepExecutionSplitter { + + /** + * The name of the step configuration that will be executed remotely. Remote + * workers are going to execute a the same step for each execution context + * in the partition. + * @return the name of the step that will execute the business logic + */ + String getStepName(); + + /** + * Partition the provided {@link StepExecution} into a set of parallel + * executable instances with the same parent {@link JobExecution}. The grid + * size will be treated as a hint for the size of the collection to be + * returned. It may or may not correspond to the physical size of an + * execution grid.
+ *
+ * + * On a restart clients of the {@link StepExecutionSplitter} should expect + * it to reconstitute the state of the last failed execution and only return + * those executions that need to be restarted. Thus the grid size hint will + * be ignored on a restart. + * + * @param stepExecution the {@link StepExecution} to be partitioned. + * @param gridSize a hint for the splitter if the size of the grid is known + * @return a set of {@link StepExecution} instances for remote processing + * + * @throws JobExecutionException if the split cannot be made + */ + Set split(StepExecution stepExecution, int gridSize) throws JobExecutionException; + } \ No newline at end of file diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/PartitionStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/PartitionStep.java index eb0268599..e85cbf6a7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/PartitionStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/PartitionStep.java @@ -1,86 +1,102 @@ -package org.springframework.batch.core.partition.support; - -import java.util.Collection; - -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.JobExecutionException; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.partition.PartitionHandler; -import org.springframework.batch.core.partition.StepExecutionSplitter; -import org.springframework.batch.core.step.AbstractStep; -import org.springframework.batch.item.ExecutionContext; -import org.springframework.util.Assert; - -/** - * Implementation of {@link Step} which partitions the execution and spreads the - * load using a {@link PartitionHandler}. - * - * @author Dave Syer - * - */ -public class PartitionStep extends AbstractStep { - - private StepExecutionSplitter stepExecutionSplitter; - - private PartitionHandler partitionHandler; - - private StepExecutionAggregator aggregator = new StepExecutionAggregator(); - - /** - * Public setter for mandatory property {@link PartitionHandler}. - * @param partitionHandler the {@link PartitionHandler} to set - */ - public void setPartitionHandler(PartitionHandler partitionHandler) { - this.partitionHandler = partitionHandler; - } - - /** - * Public setter for mandatory property {@link StepExecutionSplitter}. - * @param stepExecutionSplitter the {@link StepExecutionSplitter} to set - */ - public void setStepExecutionSplitter(StepExecutionSplitter stepExecutionSplitter) { - this.stepExecutionSplitter = stepExecutionSplitter; - } - - /** - * Assert that mandatory properties are set (stepExecutionSplitter, - * partitionHandler) and delegate top superclass. - * - * @see AbstractStep#afterPropertiesSet() - */ - public void afterPropertiesSet() throws Exception { - Assert.notNull(stepExecutionSplitter, "StepExecutionSplitter must be provided"); - Assert.notNull(partitionHandler, "PartitionHandler must be provided"); - super.afterPropertiesSet(); - } - - /** - * Delegate execution to the {@link PartitionHandler} provided. The - * {@link StepExecution} passed in here becomes the parent or master - * execution for the partition, summarising the status on exit of the - * logical grouping of work carried out by the {@link PartitionHandler}. The - * individual step executions and their input parameters (through - * {@link ExecutionContext}) for the partition elements are provided by the - * {@link StepExecutionSplitter}. - * - * @param stepExecution the master step execution for the partition - * - * @see Step#execute(StepExecution) - */ - @Override - protected void doExecute(StepExecution stepExecution) throws Exception { - - // Wait for task completion and then aggregate the results - Collection executions = partitionHandler.handle(stepExecutionSplitter, stepExecution); - stepExecution.upgradeStatus(BatchStatus.COMPLETED); - aggregator.aggregate(stepExecution, executions); - - // If anything failed or had a problem we need to crap out - if (stepExecution.getStatus().isUnsuccessful()) { - throw new JobExecutionException("Partition handler returned an unsuccessful step"); - } - - } - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.Collection; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.JobExecutionException; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.partition.PartitionHandler; +import org.springframework.batch.core.partition.StepExecutionSplitter; +import org.springframework.batch.core.step.AbstractStep; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.util.Assert; + +/** + * Implementation of {@link Step} which partitions the execution and spreads the + * load using a {@link PartitionHandler}. + * + * @author Dave Syer + * + */ +public class PartitionStep extends AbstractStep { + + private StepExecutionSplitter stepExecutionSplitter; + + private PartitionHandler partitionHandler; + + private StepExecutionAggregator aggregator = new StepExecutionAggregator(); + + /** + * Public setter for mandatory property {@link PartitionHandler}. + * @param partitionHandler the {@link PartitionHandler} to set + */ + public void setPartitionHandler(PartitionHandler partitionHandler) { + this.partitionHandler = partitionHandler; + } + + /** + * Public setter for mandatory property {@link StepExecutionSplitter}. + * @param stepExecutionSplitter the {@link StepExecutionSplitter} to set + */ + public void setStepExecutionSplitter(StepExecutionSplitter stepExecutionSplitter) { + this.stepExecutionSplitter = stepExecutionSplitter; + } + + /** + * Assert that mandatory properties are set (stepExecutionSplitter, + * partitionHandler) and delegate top superclass. + * + * @see AbstractStep#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + Assert.notNull(stepExecutionSplitter, "StepExecutionSplitter must be provided"); + Assert.notNull(partitionHandler, "PartitionHandler must be provided"); + super.afterPropertiesSet(); + } + + /** + * Delegate execution to the {@link PartitionHandler} provided. The + * {@link StepExecution} passed in here becomes the parent or master + * execution for the partition, summarising the status on exit of the + * logical grouping of work carried out by the {@link PartitionHandler}. The + * individual step executions and their input parameters (through + * {@link ExecutionContext}) for the partition elements are provided by the + * {@link StepExecutionSplitter}. + * + * @param stepExecution the master step execution for the partition + * + * @see Step#execute(StepExecution) + */ + @Override + protected void doExecute(StepExecution stepExecution) throws Exception { + + // Wait for task completion and then aggregate the results + Collection executions = partitionHandler.handle(stepExecutionSplitter, stepExecution); + stepExecution.upgradeStatus(BatchStatus.COMPLETED); + aggregator.aggregate(stepExecution, executions); + + // If anything failed or had a problem we need to crap out + if (stepExecution.getStatus().isUnsuccessful()) { + throw new JobExecutionException("Partition handler returned an unsuccessful step"); + } + + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/Partitioner.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/Partitioner.java index 7245e9cbd..334cfb792 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/Partitioner.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/Partitioner.java @@ -1,29 +1,45 @@ -package org.springframework.batch.core.partition.support; - -import java.util.Map; - -import org.springframework.batch.item.ExecutionContext; - -/** - * Central strategy interface for creating input parameters for a partitioned - * step in the form of {@link ExecutionContext} instances. The usual aim is to - * create a set of distinct input values, e.g. a set of non-overlapping primary - * key ranges, or a set of unique filenames. - * - * @author Dave Syer - * - */ -public interface Partitioner { - - /** - * Create a set of distinct {@link ExecutionContext} instances together with - * a unique identifier for each one. The identifiers should be short, - * mnemonic values, and only have to be unique within the return value (e.g. - * use an incrementer). - * - * @param gridSize the size of the map to return - * @return a map from identifier to input parameters - */ - Map partition(int gridSize); - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.Map; + +import org.springframework.batch.item.ExecutionContext; + +/** + * Central strategy interface for creating input parameters for a partitioned + * step in the form of {@link ExecutionContext} instances. The usual aim is to + * create a set of distinct input values, e.g. a set of non-overlapping primary + * key ranges, or a set of unique filenames. + * + * @author Dave Syer + * + */ +public interface Partitioner { + + /** + * Create a set of distinct {@link ExecutionContext} instances together with + * a unique identifier for each one. The identifiers should be short, + * mnemonic values, and only have to be unique within the return value (e.g. + * use an incrementer). + * + * @param gridSize the size of the map to return + * @return a map from identifier to input parameters + */ + Map partition(int gridSize); + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimplePartitioner.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimplePartitioner.java index f9d052fa7..e62bfc78c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimplePartitioner.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimplePartitioner.java @@ -1,29 +1,45 @@ -package org.springframework.batch.core.partition.support; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.batch.item.ExecutionContext; - -/** - * Simplest possible implementation of {@link Partitioner}. Just creates a set - * of empty {@link ExecutionContext} instances, and labels them as - * {partition0, partition1, ..., partitionN}, where N is the grid - * size. - * - * @author Dave Syer - * - */ -public class SimplePartitioner implements Partitioner { - - private static final String PARTITION_KEY = "partition"; - - public Map partition(int gridSize) { - Map map = new HashMap(gridSize); - for (int i = 0; i < gridSize; i++) { - map.put(PARTITION_KEY + i, new ExecutionContext()); - } - return map; - } - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.batch.item.ExecutionContext; + +/** + * Simplest possible implementation of {@link Partitioner}. Just creates a set + * of empty {@link ExecutionContext} instances, and labels them as + * {partition0, partition1, ..., partitionN}, where N is the grid + * size. + * + * @author Dave Syer + * + */ +public class SimplePartitioner implements Partitioner { + + private static final String PARTITION_KEY = "partition"; + + public Map partition(int gridSize) { + Map map = new HashMap(gridSize); + for (int i = 0; i < gridSize; i++) { + map.put(PARTITION_KEY + i, new ExecutionContext()); + } + return map; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimpleStepExecutionSplitter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimpleStepExecutionSplitter.java index 25492a205..da36f0f82 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimpleStepExecutionSplitter.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/SimpleStepExecutionSplitter.java @@ -1,159 +1,175 @@ -package org.springframework.batch.core.partition.support; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobExecutionException; -import org.springframework.batch.core.JobInstance; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.partition.StepExecutionSplitter; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.item.ExecutionContext; - -/** - * Generic implementation of {@link StepExecutionSplitter} that delegates to a - * {@link Partitioner} to generate {@link ExecutionContext} instances. Takes - * care of restartability and identifying the step executions from previous runs - * of the same job. The generated {@link StepExecution} instances have names - * that identify them uniquely in the partition. The name is constructed from a - * base (name of the target step) plus a suffix taken from the - * {@link Partitioner} identifiers, separated by a colon, e.g. - * {step1:partition0, step1:partition1, ...}. - * - * @author Dave Syer - * - */ -public class SimpleStepExecutionSplitter implements StepExecutionSplitter { - - private static final String STEP_NAME_SEPARATOR = ":"; - - private final String stepName; - - private final Partitioner partitioner; - - private final Step step; - - private final JobRepository jobRepository; - - public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step) { - this(jobRepository, step, new SimplePartitioner()); - } - - /** - * Construct a {@link SimpleStepExecutionSplitter} from its mandatory - * properties. - * - * @param jobRepository the {@link JobRepository} - * @param step the target step (a local version of it) - * @param partitioner a {@link Partitioner} to use for generating input - * parameters - */ - public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step, Partitioner partitioner) { - this.jobRepository = jobRepository; - this.step = step; - this.partitioner = partitioner; - this.stepName = step.getName(); - } - - /** - * @see StepExecutionSplitter#getStepName() - */ - public String getStepName() { - return this.stepName; - } - - /** - * @see StepExecutionSplitter#split(StepExecution, int) - */ - public Set split(StepExecution stepExecution, int gridSize) throws JobExecutionException { - - JobExecution jobExecution = stepExecution.getJobExecution(); - - // If this is a restart we must retain the same grid size, ignoring the - // one passed in... - int splitSize = getSplitSize(stepExecution, gridSize); - - Map contexts = partitioner.partition(splitSize); - Set set = new HashSet(contexts.size()); - - for (Entry context : contexts.entrySet()) { - - // Make the step execution name unique and repeatable - String stepName = this.stepName + STEP_NAME_SEPARATOR + context.getKey(); - - StepExecution currentStepExecution = jobExecution.createStepExecution(stepName); - - boolean startable = getStartable(currentStepExecution, context.getValue()); - - if (startable) { - jobRepository.add(currentStepExecution); - set.add(currentStepExecution); - } - - } - - return set; - - } - - private int getSplitSize(StepExecution stepExecution, int gridSize) { - ExecutionContext context = stepExecution.getExecutionContext(); - String key = SimpleStepExecutionSplitter.class.getSimpleName() + ".GRID_SIZE"; - int result = (int) context.getLong(key, gridSize); - context.putLong(key, result); - if (context.isDirty()) { - jobRepository.updateExecutionContext(stepExecution); - } - return result; - } - - private boolean getStartable(StepExecution stepExecution, ExecutionContext context) throws JobExecutionException { - - JobInstance jobInstance = stepExecution.getJobExecution().getJobInstance(); - String stepName = stepExecution.getStepName(); - StepExecution lastStepExecution = jobRepository.getLastStepExecution(jobInstance, stepName); - - boolean isRestart = (lastStepExecution != null && lastStepExecution.getStatus() != BatchStatus.COMPLETED) ? true - : false; - - if (isRestart) { - stepExecution.setExecutionContext(lastStepExecution.getExecutionContext()); - } - else { - stepExecution.setExecutionContext(context); - } - - return shouldStart(step, lastStepExecution) || isRestart; - - } - - private boolean shouldStart(Step step, StepExecution lastStepExecution) throws JobExecutionException { - - if (lastStepExecution == null) { - return true; - } - - BatchStatus stepStatus = lastStepExecution.getStatus(); - - if (stepStatus == BatchStatus.UNKNOWN) { - throw new JobExecutionException("Cannot restart step from UNKNOWN status. " - + "The last execution ended with a failure that could not be rolled back, " - + "so it may be dangerous to proceed. " + "Manual intervention is probably necessary."); - } - - if (stepStatus == BatchStatus.COMPLETED && step.isAllowStartIfComplete() == false) { - // step is complete, false should be returned, indicating that the - // step should not be started - return false; - } - - return true; - - } - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionException; +import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.partition.StepExecutionSplitter; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.item.ExecutionContext; + +/** + * Generic implementation of {@link StepExecutionSplitter} that delegates to a + * {@link Partitioner} to generate {@link ExecutionContext} instances. Takes + * care of restartability and identifying the step executions from previous runs + * of the same job. The generated {@link StepExecution} instances have names + * that identify them uniquely in the partition. The name is constructed from a + * base (name of the target step) plus a suffix taken from the + * {@link Partitioner} identifiers, separated by a colon, e.g. + * {step1:partition0, step1:partition1, ...}. + * + * @author Dave Syer + * + */ +public class SimpleStepExecutionSplitter implements StepExecutionSplitter { + + private static final String STEP_NAME_SEPARATOR = ":"; + + private final String stepName; + + private final Partitioner partitioner; + + private final Step step; + + private final JobRepository jobRepository; + + public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step) { + this(jobRepository, step, new SimplePartitioner()); + } + + /** + * Construct a {@link SimpleStepExecutionSplitter} from its mandatory + * properties. + * + * @param jobRepository the {@link JobRepository} + * @param step the target step (a local version of it) + * @param partitioner a {@link Partitioner} to use for generating input + * parameters + */ + public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step, Partitioner partitioner) { + this.jobRepository = jobRepository; + this.step = step; + this.partitioner = partitioner; + this.stepName = step.getName(); + } + + /** + * @see StepExecutionSplitter#getStepName() + */ + public String getStepName() { + return this.stepName; + } + + /** + * @see StepExecutionSplitter#split(StepExecution, int) + */ + public Set split(StepExecution stepExecution, int gridSize) throws JobExecutionException { + + JobExecution jobExecution = stepExecution.getJobExecution(); + + // If this is a restart we must retain the same grid size, ignoring the + // one passed in... + int splitSize = getSplitSize(stepExecution, gridSize); + + Map contexts = partitioner.partition(splitSize); + Set set = new HashSet(contexts.size()); + + for (Entry context : contexts.entrySet()) { + + // Make the step execution name unique and repeatable + String stepName = this.stepName + STEP_NAME_SEPARATOR + context.getKey(); + + StepExecution currentStepExecution = jobExecution.createStepExecution(stepName); + + boolean startable = getStartable(currentStepExecution, context.getValue()); + + if (startable) { + jobRepository.add(currentStepExecution); + set.add(currentStepExecution); + } + + } + + return set; + + } + + private int getSplitSize(StepExecution stepExecution, int gridSize) { + ExecutionContext context = stepExecution.getExecutionContext(); + String key = SimpleStepExecutionSplitter.class.getSimpleName() + ".GRID_SIZE"; + int result = (int) context.getLong(key, gridSize); + context.putLong(key, result); + if (context.isDirty()) { + jobRepository.updateExecutionContext(stepExecution); + } + return result; + } + + private boolean getStartable(StepExecution stepExecution, ExecutionContext context) throws JobExecutionException { + + JobInstance jobInstance = stepExecution.getJobExecution().getJobInstance(); + String stepName = stepExecution.getStepName(); + StepExecution lastStepExecution = jobRepository.getLastStepExecution(jobInstance, stepName); + + boolean isRestart = (lastStepExecution != null && lastStepExecution.getStatus() != BatchStatus.COMPLETED) ? true + : false; + + if (isRestart) { + stepExecution.setExecutionContext(lastStepExecution.getExecutionContext()); + } + else { + stepExecution.setExecutionContext(context); + } + + return shouldStart(step, lastStepExecution) || isRestart; + + } + + private boolean shouldStart(Step step, StepExecution lastStepExecution) throws JobExecutionException { + + if (lastStepExecution == null) { + return true; + } + + BatchStatus stepStatus = lastStepExecution.getStatus(); + + if (stepStatus == BatchStatus.UNKNOWN) { + throw new JobExecutionException("Cannot restart step from UNKNOWN status. " + + "The last execution ended with a failure that could not be rolled back, " + + "so it may be dangerous to proceed. " + "Manual intervention is probably necessary."); + } + + if (stepStatus == BatchStatus.COMPLETED && step.isAllowStartIfComplete() == false) { + // step is complete, false should be returned, indicating that the + // step should not be started + return false; + } + + return true; + + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/StepExecutionAggregator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/StepExecutionAggregator.java index 21c1c509b..4e71d9d29 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/StepExecutionAggregator.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/StepExecutionAggregator.java @@ -1,49 +1,65 @@ -package org.springframework.batch.core.partition.support; - -import java.util.Collection; - -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.StepExecution; -import org.springframework.util.Assert; - -/** - * Convenience class for aggregating a set of {@link StepExecution} instances - * into a single result. - * - * @author Dave Syer - * - */ -public class StepExecutionAggregator { - - /** - * Take the inputs and aggregate certain fields, putting the aggregates into - * the result. The aggregated fields are - *
    - *
  • status - choosing the highest value using {@link BatchStatus#max(BatchStatus, BatchStatus)}
  • - *
  • exitStatus - using {@link ExitStatus#and(ExitStatus)}
  • - *
  • commitCount, rollbackCount, etc. - by arithmetic sum
  • - *
- * - * @param result the result to overwrite - * @param executions the inputs - */ - public void aggregate(StepExecution result, Collection executions) { - Assert.notNull(result, "To aggregate into a result it must be non-null."); - if (executions == null || executions.isEmpty()) { - throw new IllegalArgumentException("Cannot aggregate empty or null executions: " + executions); - } - for (StepExecution stepExecution : executions) { - BatchStatus status = stepExecution.getStatus(); - result.setStatus(BatchStatus.max(result.getStatus(), status)); - result.setExitStatus(result.getExitStatus().and(stepExecution.getExitStatus())); - result.setCommitCount(result.getCommitCount() + stepExecution.getCommitCount()); - result.setRollbackCount(result.getRollbackCount() + stepExecution.getRollbackCount()); - result.setReadCount(result.getReadCount() + stepExecution.getReadCount()); - result.setReadSkipCount(result.getReadSkipCount() + stepExecution.getReadSkipCount()); - result.setWriteCount(result.getWriteCount() + stepExecution.getWriteCount()); - result.setWriteSkipCount(result.getWriteSkipCount() + stepExecution.getWriteSkipCount()); - } - } - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.Collection; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepExecution; +import org.springframework.util.Assert; + +/** + * Convenience class for aggregating a set of {@link StepExecution} instances + * into a single result. + * + * @author Dave Syer + * + */ +public class StepExecutionAggregator { + + /** + * Take the inputs and aggregate certain fields, putting the aggregates into + * the result. The aggregated fields are + *
    + *
  • status - choosing the highest value using {@link BatchStatus#max(BatchStatus, BatchStatus)}
  • + *
  • exitStatus - using {@link ExitStatus#and(ExitStatus)}
  • + *
  • commitCount, rollbackCount, etc. - by arithmetic sum
  • + *
+ * + * @param result the result to overwrite + * @param executions the inputs + */ + public void aggregate(StepExecution result, Collection executions) { + Assert.notNull(result, "To aggregate into a result it must be non-null."); + if (executions == null || executions.isEmpty()) { + throw new IllegalArgumentException("Cannot aggregate empty or null executions: " + executions); + } + for (StepExecution stepExecution : executions) { + BatchStatus status = stepExecution.getStatus(); + result.setStatus(BatchStatus.max(result.getStatus(), status)); + result.setExitStatus(result.getExitStatus().and(stepExecution.getExitStatus())); + result.setCommitCount(result.getCommitCount() + stepExecution.getCommitCount()); + result.setRollbackCount(result.getRollbackCount() + stepExecution.getRollbackCount()); + result.setReadCount(result.getReadCount() + stepExecution.getReadCount()); + result.setReadSkipCount(result.getReadSkipCount() + stepExecution.getReadSkipCount()); + result.setWriteCount(result.getWriteCount() + stepExecution.getWriteCount()); + result.setWriteSkipCount(result.getWriteSkipCount() + stepExecution.getWriteSkipCount()); + } + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/TaskExecutorPartitionHandler.java b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/TaskExecutorPartitionHandler.java index aee1ee972..b9ec00628 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/TaskExecutorPartitionHandler.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/partition/support/TaskExecutorPartitionHandler.java @@ -1,92 +1,108 @@ -package org.springframework.batch.core.partition.support; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; - -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.partition.PartitionHandler; -import org.springframework.batch.core.partition.StepExecutionSplitter; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.task.SyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.core.task.TaskRejectedException; -import org.springframework.util.Assert; - -public class TaskExecutorPartitionHandler implements PartitionHandler, InitializingBean { - - private int gridSize = 1; - - private TaskExecutor taskExecutor = new SyncTaskExecutor(); - - private Step step; - - public void afterPropertiesSet() throws Exception { - Assert.notNull(step, "A Step must be provided."); - } - - public void setGridSize(int gridSize) { - this.gridSize = gridSize; - } - - public void setTaskExecutor(TaskExecutor taskExecutor) { - this.taskExecutor = taskExecutor; - } - - public void setStep(Step step) { - this.step = step; - } - - /** - * @see PartitionHandler#handle(StepExecutionSplitter, StepExecution) - */ - public Collection handle(StepExecutionSplitter stepExecutionSplitter, - StepExecution masterStepExecution) throws Exception { - - Set> tasks = new HashSet>(gridSize); - - Collection result = new ArrayList(); - - for (final StepExecution stepExecution : stepExecutionSplitter.split(masterStepExecution, gridSize)) { - - final FutureTask task = new FutureTask(new Callable() { - public StepExecution call() throws Exception { - step.execute(stepExecution); - return stepExecution; - } - }); - - try { - taskExecutor.execute(task); - tasks.add(task); - } - catch (TaskRejectedException e) { - // couldn't execute one of the tasks - ExitStatus exitStatus = ExitStatus.FAILED - .addExitDescription("TaskExecutor rejected the task for this step."); - /* - * Set the status in case the caller is tracking it through the - * JobExecution. - */ - stepExecution.setStatus(BatchStatus.FAILED); - stepExecution.setExitStatus(exitStatus); - result.add(stepExecution); - } - - } - - for (Future task : tasks) { - result.add(task.get()); - } - return result; - - } - -} +/* + * Copyright 2006-2007 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.partition.support; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.partition.PartitionHandler; +import org.springframework.batch.core.partition.StepExecutionSplitter; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.task.SyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; +import org.springframework.core.task.TaskRejectedException; +import org.springframework.util.Assert; + +public class TaskExecutorPartitionHandler implements PartitionHandler, InitializingBean { + + private int gridSize = 1; + + private TaskExecutor taskExecutor = new SyncTaskExecutor(); + + private Step step; + + public void afterPropertiesSet() throws Exception { + Assert.notNull(step, "A Step must be provided."); + } + + public void setGridSize(int gridSize) { + this.gridSize = gridSize; + } + + public void setTaskExecutor(TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + } + + public void setStep(Step step) { + this.step = step; + } + + /** + * @see PartitionHandler#handle(StepExecutionSplitter, StepExecution) + */ + public Collection handle(StepExecutionSplitter stepExecutionSplitter, + StepExecution masterStepExecution) throws Exception { + + Set> tasks = new HashSet>(gridSize); + + Collection result = new ArrayList(); + + for (final StepExecution stepExecution : stepExecutionSplitter.split(masterStepExecution, gridSize)) { + + final FutureTask task = new FutureTask(new Callable() { + public StepExecution call() throws Exception { + step.execute(stepExecution); + return stepExecution; + } + }); + + try { + taskExecutor.execute(task); + tasks.add(task); + } + catch (TaskRejectedException e) { + // couldn't execute one of the tasks + ExitStatus exitStatus = ExitStatus.FAILED + .addExitDescription("TaskExecutor rejected the task for this step."); + /* + * Set the status in case the caller is tracking it through the + * JobExecution. + */ + stepExecution.setStatus(BatchStatus.FAILED); + stepExecution.setExitStatus(exitStatus); + result.add(stepExecution); + } + + } + + for (Future task : tasks) { + result.add(task.get()); + } + return result; + + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/AbstractJdbcBatchMetadataDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/AbstractJdbcBatchMetadataDao.java index 948bd2581..63f00af0f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/AbstractJdbcBatchMetadataDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/AbstractJdbcBatchMetadataDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import org.springframework.beans.factory.InitializingBean; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java index 2f3ef6926..2ec5e3764 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java @@ -1,37 +1,53 @@ -package org.springframework.batch.core.repository.dao; - -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.item.ExecutionContext; - -/** - * DAO interface for persisting and retrieving {@link ExecutionContext}s. - * - * @author Robert Kasanicky - */ -public interface ExecutionContextDao { - - /** - * @param jobExecution - * @return execution context associated with the given jobExecution - */ - ExecutionContext getExecutionContext(JobExecution jobExecution); - - /** - * @param stepExecution - * @return execution context associated with the given stepExecution - */ - ExecutionContext getExecutionContext(StepExecution stepExecution); - - /** - * Persist the execution context associated with the given jobExecution - * @param jobExecution - */ - void persistExecutionContext(final JobExecution jobExecution); - - /** - * Persist the execution context associated with the given stepExecution - * @param stepExecution - */ - void persistExecutionContext(final StepExecution stepExecution); -} +/* + * Copyright 2006-2007 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.repository.dao; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.item.ExecutionContext; + +/** + * DAO interface for persisting and retrieving {@link ExecutionContext}s. + * + * @author Robert Kasanicky + */ +public interface ExecutionContextDao { + + /** + * @param jobExecution + * @return execution context associated with the given jobExecution + */ + ExecutionContext getExecutionContext(JobExecution jobExecution); + + /** + * @param stepExecution + * @return execution context associated with the given stepExecution + */ + ExecutionContext getExecutionContext(StepExecution stepExecution); + + /** + * Persist the execution context associated with the given jobExecution + * @param jobExecution + */ + void persistExecutionContext(final JobExecution jobExecution); + + /** + * Persist the execution context associated with the given stepExecution + * @param stepExecution + */ + void persistExecutionContext(final StepExecution stepExecution); +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java index 355011331..1901fa197 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobExecutionDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.sql.ResultSet; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java index 1cdadecc3..576a97087 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcJobInstanceDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.sql.ResultSet; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java index c96b2ff57..f4d12fd73 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.sql.ResultSet; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java index 5bde5114b..3a1514663 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobExecutionDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.util.List; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java index aef6046e5..e1e3f7033 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JobInstanceDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.util.List; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java index c6862023a..1febce5a1 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java @@ -1,44 +1,60 @@ -package org.springframework.batch.core.repository.dao; - -import java.util.Map; - -import org.apache.commons.lang.SerializationUtils; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.support.transaction.TransactionAwareProxyFactory; - -public class MapExecutionContextDao implements ExecutionContextDao { - - private static Map contextsByStepExecutionId = TransactionAwareProxyFactory.createTransactionalMap(); - - private static Map contextsByJobExecutionId = TransactionAwareProxyFactory.createTransactionalMap(); - - public static void clear() { - contextsByJobExecutionId.clear(); - contextsByStepExecutionId.clear(); - } - - private static ExecutionContext copy(ExecutionContext original) { - return (ExecutionContext) SerializationUtils.deserialize(SerializationUtils.serialize(original)); - } - - - public ExecutionContext getExecutionContext(StepExecution stepExecution) { - return copy(contextsByStepExecutionId.get(stepExecution.getId())); - } - - public void persistExecutionContext(StepExecution stepExecution) { - contextsByStepExecutionId.put(stepExecution.getId(), copy(stepExecution.getExecutionContext())); - } - - public ExecutionContext getExecutionContext(JobExecution jobExecution) { - return copy(contextsByJobExecutionId.get(jobExecution.getId())); - } - - public void persistExecutionContext(JobExecution jobExecution) { - contextsByJobExecutionId.put(jobExecution.getId(), copy(jobExecution.getExecutionContext())); - - } - -} +/* + * Copyright 2006-2007 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.repository.dao; + +import java.util.Map; + +import org.apache.commons.lang.SerializationUtils; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.support.transaction.TransactionAwareProxyFactory; + +public class MapExecutionContextDao implements ExecutionContextDao { + + private static Map contextsByStepExecutionId = TransactionAwareProxyFactory.createTransactionalMap(); + + private static Map contextsByJobExecutionId = TransactionAwareProxyFactory.createTransactionalMap(); + + public static void clear() { + contextsByJobExecutionId.clear(); + contextsByStepExecutionId.clear(); + } + + private static ExecutionContext copy(ExecutionContext original) { + return (ExecutionContext) SerializationUtils.deserialize(SerializationUtils.serialize(original)); + } + + + public ExecutionContext getExecutionContext(StepExecution stepExecution) { + return copy(contextsByStepExecutionId.get(stepExecution.getId())); + } + + public void persistExecutionContext(StepExecution stepExecution) { + contextsByStepExecutionId.put(stepExecution.getId(), copy(stepExecution.getExecutionContext())); + } + + public ExecutionContext getExecutionContext(JobExecution jobExecution) { + return copy(contextsByJobExecutionId.get(jobExecution.getId())); + } + + public void persistExecutionContext(JobExecution jobExecution) { + contextsByJobExecutionId.put(jobExecution.getId(), copy(jobExecution.getExecutionContext())); + + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java index 95f4acd1a..a03110abb 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobExecutionDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.util.ArrayList; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobInstanceDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobInstanceDao.java index 21a354b7e..36c0fe301 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobInstanceDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapJobInstanceDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.util.ArrayList; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java index 597b99c94..c3b74852d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/StepExecutionDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repository.dao; import java.util.List; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/AbstractJobRepositoryFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/AbstractJobRepositoryFactoryBean.java index 481199cc1..5d6747e88 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/AbstractJobRepositoryFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/AbstractJobRepositoryFactoryBean.java @@ -1,134 +1,150 @@ -package org.springframework.batch.core.repository.support; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.aop.support.NameMatchMethodPointcut; -import org.springframework.batch.core.repository.JobRepository; -import org.springframework.batch.core.repository.dao.ExecutionContextDao; -import org.springframework.batch.core.repository.dao.JobExecutionDao; -import org.springframework.batch.core.repository.dao.JobInstanceDao; -import org.springframework.batch.core.repository.dao.StepExecutionDao; -import org.springframework.batch.support.PropertiesConverter; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.interceptor.TransactionInterceptor; -import org.springframework.util.Assert; - -/** - * A {@link FactoryBean} that automates the creation of a - * {@link SimpleJobRepository}. Declares abstract methods for providing DAO - * object implementations. - * - * @see JobRepositoryFactoryBean - * @see MapJobRepositoryFactoryBean - * - * @author Ben Hale - * @author Lucas Ward - * @author Robert Kasanicky - */ -public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, InitializingBean { - - private PlatformTransactionManager transactionManager; - - private ProxyFactory proxyFactory; - - private String isolationLevelForCreate = DEFAULT_ISOLATION_LEVEL; - - /** - * Default value for isolation level in create* method. - */ - private static final String DEFAULT_ISOLATION_LEVEL = "ISOLATION_SERIALIZABLE"; - - /** - * @return fully configured {@link JobInstanceDao} implementation. - */ - protected abstract JobInstanceDao createJobInstanceDao() throws Exception; - - /** - * @return fully configured {@link JobExecutionDao} implementation. - */ - protected abstract JobExecutionDao createJobExecutionDao() throws Exception; - - /** - * @return fully configured {@link StepExecutionDao} implementation. - */ - protected abstract StepExecutionDao createStepExecutionDao() throws Exception; - - /** - * @return fully configured {@link ExecutionContextDao} implementation. - */ - protected abstract ExecutionContextDao createExecutionContextDao() throws Exception; - - /** - * The type of object to be returned from {@link #getObject()}. - * - * @return JobRepository.class - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ - public Class getObjectType() { - return JobRepository.class; - } - - public boolean isSingleton() { - return true; - } - - /** - * public setter for the isolation level to be used for the transaction when - * job execution entities are initially created. The default is - * ISOLATION_SERIALIZABLE, which prevents accidental concurrent execution of - * the same job (ISOLATION_REPEATABLE_READ would work as well). - * - * @param isolationLevelForCreate the isolation level name to set - * - * @see SimpleJobRepository#createJobExecution(String, - * org.springframework.batch.core.JobParameters) - */ - public void setIsolationLevelForCreate(String isolationLevelForCreate) { - this.isolationLevelForCreate = isolationLevelForCreate; - } - - /** - * Public setter for the {@link PlatformTransactionManager}. - * @param transactionManager the transactionManager to set - */ - public void setTransactionManager(PlatformTransactionManager transactionManager) { - this.transactionManager = transactionManager; - } - - private void initializeProxy() throws Exception { - proxyFactory = new ProxyFactory(); - TransactionInterceptor advice = new TransactionInterceptor(transactionManager, PropertiesConverter - .stringToProperties("create*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate - + "\ngetLastJobExecution*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate - + "\n*=PROPAGATION_REQUIRED")); - DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(advice); - NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); - pointcut.addMethodName("*"); - advisor.setPointcut(pointcut); - proxyFactory.addAdvisor(advisor); - proxyFactory.setProxyTargetClass(false); - proxyFactory.addInterface(JobRepository.class); - proxyFactory.setTarget(getTarget()); - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(transactionManager, "TransactionManager must not be null."); - - initializeProxy(); - } - - private Object getTarget() throws Exception { - return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(), - createExecutionContextDao()); - } - - public Object getObject() throws Exception { - if (proxyFactory == null) { - afterPropertiesSet(); - } - return proxyFactory.getProxy(); - } - -} +/* + * Copyright 2006-2007 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.repository.support; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.NameMatchMethodPointcut; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.dao.ExecutionContextDao; +import org.springframework.batch.core.repository.dao.JobExecutionDao; +import org.springframework.batch.core.repository.dao.JobInstanceDao; +import org.springframework.batch.core.repository.dao.StepExecutionDao; +import org.springframework.batch.support.PropertiesConverter; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.interceptor.TransactionInterceptor; +import org.springframework.util.Assert; + +/** + * A {@link FactoryBean} that automates the creation of a + * {@link SimpleJobRepository}. Declares abstract methods for providing DAO + * object implementations. + * + * @see JobRepositoryFactoryBean + * @see MapJobRepositoryFactoryBean + * + * @author Ben Hale + * @author Lucas Ward + * @author Robert Kasanicky + */ +public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, InitializingBean { + + private PlatformTransactionManager transactionManager; + + private ProxyFactory proxyFactory; + + private String isolationLevelForCreate = DEFAULT_ISOLATION_LEVEL; + + /** + * Default value for isolation level in create* method. + */ + private static final String DEFAULT_ISOLATION_LEVEL = "ISOLATION_SERIALIZABLE"; + + /** + * @return fully configured {@link JobInstanceDao} implementation. + */ + protected abstract JobInstanceDao createJobInstanceDao() throws Exception; + + /** + * @return fully configured {@link JobExecutionDao} implementation. + */ + protected abstract JobExecutionDao createJobExecutionDao() throws Exception; + + /** + * @return fully configured {@link StepExecutionDao} implementation. + */ + protected abstract StepExecutionDao createStepExecutionDao() throws Exception; + + /** + * @return fully configured {@link ExecutionContextDao} implementation. + */ + protected abstract ExecutionContextDao createExecutionContextDao() throws Exception; + + /** + * The type of object to be returned from {@link #getObject()}. + * + * @return JobRepository.class + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + public Class getObjectType() { + return JobRepository.class; + } + + public boolean isSingleton() { + return true; + } + + /** + * public setter for the isolation level to be used for the transaction when + * job execution entities are initially created. The default is + * ISOLATION_SERIALIZABLE, which prevents accidental concurrent execution of + * the same job (ISOLATION_REPEATABLE_READ would work as well). + * + * @param isolationLevelForCreate the isolation level name to set + * + * @see SimpleJobRepository#createJobExecution(String, + * org.springframework.batch.core.JobParameters) + */ + public void setIsolationLevelForCreate(String isolationLevelForCreate) { + this.isolationLevelForCreate = isolationLevelForCreate; + } + + /** + * Public setter for the {@link PlatformTransactionManager}. + * @param transactionManager the transactionManager to set + */ + public void setTransactionManager(PlatformTransactionManager transactionManager) { + this.transactionManager = transactionManager; + } + + private void initializeProxy() throws Exception { + proxyFactory = new ProxyFactory(); + TransactionInterceptor advice = new TransactionInterceptor(transactionManager, PropertiesConverter + .stringToProperties("create*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate + + "\ngetLastJobExecution*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate + + "\n*=PROPAGATION_REQUIRED")); + DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(advice); + NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); + pointcut.addMethodName("*"); + advisor.setPointcut(pointcut); + proxyFactory.addAdvisor(advisor); + proxyFactory.setProxyTargetClass(false); + proxyFactory.addInterface(JobRepository.class); + proxyFactory.setTarget(getTarget()); + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(transactionManager, "TransactionManager must not be null."); + + initializeProxy(); + } + + private Object getTarget() throws Exception { + return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(), + createExecutionContextDao()); + } + + public Object getObject() throws Exception { + if (proxyFactory == null) { + afterPropertiesSet(); + } + return proxyFactory.getProxy(); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/MapJobRepositoryFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/MapJobRepositoryFactoryBean.java index 3ec2aab18..bb66aee31 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/MapJobRepositoryFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/MapJobRepositoryFactoryBean.java @@ -1,57 +1,73 @@ -package org.springframework.batch.core.repository.support; - -import org.springframework.batch.core.repository.dao.ExecutionContextDao; -import org.springframework.batch.core.repository.dao.JobExecutionDao; -import org.springframework.batch.core.repository.dao.JobInstanceDao; -import org.springframework.batch.core.repository.dao.MapExecutionContextDao; -import org.springframework.batch.core.repository.dao.MapJobExecutionDao; -import org.springframework.batch.core.repository.dao.MapJobInstanceDao; -import org.springframework.batch.core.repository.dao.MapStepExecutionDao; -import org.springframework.batch.core.repository.dao.StepExecutionDao; -import org.springframework.batch.support.transaction.ResourcelessTransactionManager; -import org.springframework.beans.factory.FactoryBean; - -/** - * A {@link FactoryBean} that automates the creation of a - * {@link SimpleJobRepository} using non-persistent in-memory DAO - * implementations. This repository is only really intended for use in testing - * and rapid prototyping. In such settings you might find that - * {@link ResourcelessTransactionManager} is useful (as long as your business - * logic does not use a relational database). - * - * @author Robert Kasanicky - */ -public class MapJobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean { - - /** - * Convenience method to clear all the map daos globally, removing all - * entities. - */ - public static void clear() { - MapJobInstanceDao.clear(); - MapJobExecutionDao.clear(); - MapStepExecutionDao.clear(); - MapExecutionContextDao.clear(); - } - - @Override - protected JobExecutionDao createJobExecutionDao() throws Exception { - return new MapJobExecutionDao(); - } - - @Override - protected JobInstanceDao createJobInstanceDao() throws Exception { - return new MapJobInstanceDao(); - } - - @Override - protected StepExecutionDao createStepExecutionDao() throws Exception { - return new MapStepExecutionDao(); - } - - @Override - protected ExecutionContextDao createExecutionContextDao() throws Exception { - return new MapExecutionContextDao(); - } - -} +/* + * Copyright 2006-2007 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.repository.support; + +import org.springframework.batch.core.repository.dao.ExecutionContextDao; +import org.springframework.batch.core.repository.dao.JobExecutionDao; +import org.springframework.batch.core.repository.dao.JobInstanceDao; +import org.springframework.batch.core.repository.dao.MapExecutionContextDao; +import org.springframework.batch.core.repository.dao.MapJobExecutionDao; +import org.springframework.batch.core.repository.dao.MapJobInstanceDao; +import org.springframework.batch.core.repository.dao.MapStepExecutionDao; +import org.springframework.batch.core.repository.dao.StepExecutionDao; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.beans.factory.FactoryBean; + +/** + * A {@link FactoryBean} that automates the creation of a + * {@link SimpleJobRepository} using non-persistent in-memory DAO + * implementations. This repository is only really intended for use in testing + * and rapid prototyping. In such settings you might find that + * {@link ResourcelessTransactionManager} is useful (as long as your business + * logic does not use a relational database). + * + * @author Robert Kasanicky + */ +public class MapJobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean { + + /** + * Convenience method to clear all the map daos globally, removing all + * entities. + */ + public static void clear() { + MapJobInstanceDao.clear(); + MapJobExecutionDao.clear(); + MapStepExecutionDao.clear(); + MapExecutionContextDao.clear(); + } + + @Override + protected JobExecutionDao createJobExecutionDao() throws Exception { + return new MapJobExecutionDao(); + } + + @Override + protected JobInstanceDao createJobInstanceDao() throws Exception { + return new MapJobInstanceDao(); + } + + @Override + protected StepExecutionDao createStepExecutionDao() throws Exception { + return new MapStepExecutionDao(); + } + + @Override + protected ExecutionContextDao createExecutionContextDao() throws Exception { + return new MapExecutionContextDao(); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/ChunkContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/ChunkContext.java index 7318c1045..9dcaa7c14 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/ChunkContext.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/ChunkContext.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.scope.context; import java.util.Arrays; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/StepScopeManager.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/StepScopeManager.java index d07057e32..701cafb4b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/StepScopeManager.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/StepScopeManager.java @@ -1,31 +1,47 @@ -package org.springframework.batch.core.scope.context; - -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.springframework.batch.core.JobInterruptedException; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.StepExecution; - -/** - * Convenient aspect to wrap a single threaded step execution, where the - * implementation of the {@link Step} is not step scope aware (i.e. not the ones - * provided by the framework). - * - * @author Dave Syer - * - */ -@Aspect -public class StepScopeManager { - - @Around("execution(void org.springframework.batch.core.Step+.execute(*)) && target(step) && args(stepExecution)") - public void execute(Step step, StepExecution stepExecution) throws JobInterruptedException { - StepSynchronizationManager.register(stepExecution); - try { - step.execute(stepExecution); - } - finally { - StepSynchronizationManager.release(); - } - } - -} +/* + * Copyright 2006-2007 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.scope.context; + +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.batch.core.JobInterruptedException; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; + +/** + * Convenient aspect to wrap a single threaded step execution, where the + * implementation of the {@link Step} is not step scope aware (i.e. not the ones + * provided by the framework). + * + * @author Dave Syer + * + */ +@Aspect +public class StepScopeManager { + + @Around("execution(void org.springframework.batch.core.Step+.execute(*)) && target(step) && args(stepExecution)") + public void execute(Step step, StepExecution stepExecution) throws JobInterruptedException { + StepSynchronizationManager.register(stepExecution); + try { + step.execute(stepExecution); + } + finally { + StepSynchronizationManager.release(); + } + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/ContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/ContextFactory.java index d7ec94cdb..4f89d47e0 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/ContextFactory.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/ContextFactory.java @@ -1,22 +1,38 @@ -package org.springframework.batch.core.scope.util; - -/** - * Interface to allow the context root for placeholder resolution to be switched - * at runtime. Useful for testing. - * - * @author Dave Syer - * - */ -public interface ContextFactory { - - /** - * @return a root object to which placeholders resolve relatively - */ - Object getContext(); - - /** - * @return a unique identifier for this context - */ - String getContextId(); - -} +/* + * Copyright 2006-2007 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.scope.util; + +/** + * Interface to allow the context root for placeholder resolution to be switched + * at runtime. Useful for testing. + * + * @author Dave Syer + * + */ +public interface ContextFactory { + + /** + * @return a root object to which placeholders resolve relatively + */ + Object getContext(); + + /** + * @return a unique identifier for this context + */ + String getContextId(); + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderProxyFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderProxyFactoryBean.java index ceecb1540..3cf598541 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderProxyFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/PlaceholderProxyFactoryBean.java @@ -1,166 +1,182 @@ -package org.springframework.batch.core.scope.util; - -import java.lang.reflect.Modifier; - -import org.springframework.aop.framework.AopInfrastructureBean; -import org.springframework.aop.framework.ProxyConfig; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.framework.autoproxy.AutoProxyUtils; -import org.springframework.aop.scope.DefaultScopedObject; -import org.springframework.aop.scope.ScopedObject; -import org.springframework.aop.scope.ScopedProxyFactoryBean; -import org.springframework.aop.support.DelegatingIntroductionInterceptor; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.FactoryBeanNotInitializedException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.util.ClassUtils; - -/** - * Factory bean for proxies that can replace placeholders in their target. Just - * a specialisation of {@link ScopedProxyFactoryBean}, with a different target - * source type. - * - * @author Dave Syer - * - */ -public class PlaceholderProxyFactoryBean extends ProxyConfig implements FactoryBean, BeanFactoryAware { - - /** The TargetSource that manages scoping */ - private final PlaceholderTargetSource scopedTargetSource = new PlaceholderTargetSource(); - - /** The name of the target bean */ - private String targetBeanName; - - /** The cached singleton proxy */ - private Object proxy; - - private final ContextFactory contextFactory; - - /** - * Create a new FactoryBean instance. - */ - public PlaceholderProxyFactoryBean(ContextFactory contextFactory) { - this.contextFactory = contextFactory; - // setProxyTargetClass(false); - } - - /** - * Set the name of the bean that is to be scoped. - */ - public void setTargetBeanName(String targetBeanName) { - this.targetBeanName = targetBeanName; - this.scopedTargetSource.setTargetBeanName(targetBeanName); - } - - public void setBeanFactory(BeanFactory beanFactory) { - if (!(beanFactory instanceof ConfigurableBeanFactory)) { - throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory); - } - ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; - - this.scopedTargetSource.setBeanFactory(beanFactory); - this.scopedTargetSource.setContextFactory(contextFactory); - - ProxyFactory pf = new ProxyFactory(); - pf.copyFrom(this); - pf.setTargetSource(this.scopedTargetSource); - - Class beanType = beanFactory.getType(this.targetBeanName); - if (beanType == null) { - throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName - + "': Target type could not be determined at the time of proxy creation."); - } - if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) { - pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader())); - } - - // Add an introduction that implements only the methods on ScopedObject. - ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName()); - pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject)); - - // Add the AopInfrastructureBean marker to indicate that the scoped - // proxy itself is not subject to auto-proxying! Only its target bean - // is. - pf.addInterface(AopInfrastructureBean.class); - - this.proxy = pf.getProxy(cbf.getBeanClassLoader()); - } - - public Object getObject() { - if (this.proxy == null) { - throw new FactoryBeanNotInitializedException(); - } - return this.proxy; - } - - public Class getObjectType() { - if (this.proxy != null) { - return this.proxy.getClass(); - } - if (this.scopedTargetSource != null) { - return this.scopedTargetSource.getTargetClass(); - } - return null; - } - - public boolean isSingleton() { - return true; - } - - /** - * Convenience method to create a {@link BeanDefinition} for a target - * wrapped in a placeholder tarrget source, able to defer binding of - * placeholders until the bean is used. - * - * @param definition a target bean definition - * @param registry a {@link BeanDefinitionRegistry} - * @param proxyTargetClass true if we need to use CGlib to create the - * proxies - * @return a {@link BeanDefinitionHolder} for a - * {@link PlaceholderProxyFactoryBean} - */ - public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition, - BeanDefinitionRegistry registry, boolean proxyTargetClass) { - - String originalBeanName = definition.getBeanName(); - BeanDefinition targetDefinition = definition.getBeanDefinition(); - - // Create a proxy definition for the original bean name, - // "hiding" the target bean in an internal target definition. - RootBeanDefinition proxyDefinition = new RootBeanDefinition(PlaceholderProxyFactoryBean.class); - proxyDefinition.getConstructorArgumentValues().addGenericArgumentValue(new StepContextFactory()); - proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition()); - proxyDefinition.setSource(definition.getSource()); - proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - String targetBeanName = "lazyBindingProxy." + originalBeanName; - proxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName); - - if (proxyTargetClass) { - targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); - // ProxyFactoryBean's "proxyTargetClass" default is TRUE, so we - // don't need to set it explicitly here. - } - else { - proxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE); - } - - proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); - // The target bean should be ignored in favor of the proxy. - targetDefinition.setAutowireCandidate(false); - - // Register the target bean as separate bean in the factory. - registry.registerBeanDefinition(targetBeanName, targetDefinition); - - // Return the scoped proxy definition as primary bean definition - // (potentially an inner bean). - return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases()); - } - -} +/* + * Copyright 2006-2007 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.scope.util; + +import java.lang.reflect.Modifier; + +import org.springframework.aop.framework.AopInfrastructureBean; +import org.springframework.aop.framework.ProxyConfig; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.framework.autoproxy.AutoProxyUtils; +import org.springframework.aop.scope.DefaultScopedObject; +import org.springframework.aop.scope.ScopedObject; +import org.springframework.aop.scope.ScopedProxyFactoryBean; +import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.FactoryBeanNotInitializedException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.util.ClassUtils; + +/** + * Factory bean for proxies that can replace placeholders in their target. Just + * a specialisation of {@link ScopedProxyFactoryBean}, with a different target + * source type. + * + * @author Dave Syer + * + */ +public class PlaceholderProxyFactoryBean extends ProxyConfig implements FactoryBean, BeanFactoryAware { + + /** The TargetSource that manages scoping */ + private final PlaceholderTargetSource scopedTargetSource = new PlaceholderTargetSource(); + + /** The name of the target bean */ + private String targetBeanName; + + /** The cached singleton proxy */ + private Object proxy; + + private final ContextFactory contextFactory; + + /** + * Create a new FactoryBean instance. + */ + public PlaceholderProxyFactoryBean(ContextFactory contextFactory) { + this.contextFactory = contextFactory; + // setProxyTargetClass(false); + } + + /** + * Set the name of the bean that is to be scoped. + */ + public void setTargetBeanName(String targetBeanName) { + this.targetBeanName = targetBeanName; + this.scopedTargetSource.setTargetBeanName(targetBeanName); + } + + public void setBeanFactory(BeanFactory beanFactory) { + if (!(beanFactory instanceof ConfigurableBeanFactory)) { + throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory); + } + ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; + + this.scopedTargetSource.setBeanFactory(beanFactory); + this.scopedTargetSource.setContextFactory(contextFactory); + + ProxyFactory pf = new ProxyFactory(); + pf.copyFrom(this); + pf.setTargetSource(this.scopedTargetSource); + + Class beanType = beanFactory.getType(this.targetBeanName); + if (beanType == null) { + throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName + + "': Target type could not be determined at the time of proxy creation."); + } + if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) { + pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader())); + } + + // Add an introduction that implements only the methods on ScopedObject. + ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName()); + pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject)); + + // Add the AopInfrastructureBean marker to indicate that the scoped + // proxy itself is not subject to auto-proxying! Only its target bean + // is. + pf.addInterface(AopInfrastructureBean.class); + + this.proxy = pf.getProxy(cbf.getBeanClassLoader()); + } + + public Object getObject() { + if (this.proxy == null) { + throw new FactoryBeanNotInitializedException(); + } + return this.proxy; + } + + public Class getObjectType() { + if (this.proxy != null) { + return this.proxy.getClass(); + } + if (this.scopedTargetSource != null) { + return this.scopedTargetSource.getTargetClass(); + } + return null; + } + + public boolean isSingleton() { + return true; + } + + /** + * Convenience method to create a {@link BeanDefinition} for a target + * wrapped in a placeholder tarrget source, able to defer binding of + * placeholders until the bean is used. + * + * @param definition a target bean definition + * @param registry a {@link BeanDefinitionRegistry} + * @param proxyTargetClass true if we need to use CGlib to create the + * proxies + * @return a {@link BeanDefinitionHolder} for a + * {@link PlaceholderProxyFactoryBean} + */ + public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition, + BeanDefinitionRegistry registry, boolean proxyTargetClass) { + + String originalBeanName = definition.getBeanName(); + BeanDefinition targetDefinition = definition.getBeanDefinition(); + + // Create a proxy definition for the original bean name, + // "hiding" the target bean in an internal target definition. + RootBeanDefinition proxyDefinition = new RootBeanDefinition(PlaceholderProxyFactoryBean.class); + proxyDefinition.getConstructorArgumentValues().addGenericArgumentValue(new StepContextFactory()); + proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition()); + proxyDefinition.setSource(definition.getSource()); + proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + + String targetBeanName = "lazyBindingProxy." + originalBeanName; + proxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName); + + if (proxyTargetClass) { + targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); + // ProxyFactoryBean's "proxyTargetClass" default is TRUE, so we + // don't need to set it explicitly here. + } + else { + proxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE); + } + + proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); + // The target bean should be ignored in favor of the proxy. + targetDefinition.setAutowireCandidate(false); + + // Register the target bean as separate bean in the factory. + registry.registerBeanDefinition(targetBeanName, targetDefinition); + + // Return the scoped proxy definition as primary bean definition + // (potentially an inner bean). + return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases()); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/StepContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/StepContextFactory.java index 890252d33..3808620cf 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/StepContextFactory.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/util/StepContextFactory.java @@ -1,23 +1,39 @@ -package org.springframework.batch.core.scope.util; - -import org.springframework.batch.core.scope.context.StepContext; -import org.springframework.batch.core.scope.context.StepSynchronizationManager; - -/** - * Implementation of {@link ContextFactory} that provides the current - * {@link StepContext} as a contxt object. - * - * @author Dave Syer - * - */ -public class StepContextFactory implements ContextFactory { - - public Object getContext() { - return StepSynchronizationManager.getContext(); - } - - public String getContextId() { - return (String) StepSynchronizationManager.getContext().getId(); - } - -} +/* + * Copyright 2006-2007 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.scope.util; + +import org.springframework.batch.core.scope.context.StepContext; +import org.springframework.batch.core.scope.context.StepSynchronizationManager; + +/** + * Implementation of {@link ContextFactory} that provides the current + * {@link StepContext} as a contxt object. + * + * @author Dave Syer + * + */ +public class StepContextFactory implements ContextFactory { + + public Object getContext() { + return StepSynchronizationManager.getContext(); + } + + public String getContextId() { + return (String) StepSynchronizationManager.getContext().getId(); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/BatchRetryTemplate.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/BatchRetryTemplate.java index d82774301..103374a8c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/BatchRetryTemplate.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/BatchRetryTemplate.java @@ -1,254 +1,270 @@ -package org.springframework.batch.core.step.item; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import org.springframework.batch.retry.ExhaustedRetryException; -import org.springframework.batch.retry.RecoveryCallback; -import org.springframework.batch.retry.RetryCallback; -import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryListener; -import org.springframework.batch.retry.RetryOperations; -import org.springframework.batch.retry.RetryPolicy; -import org.springframework.batch.retry.RetryState; -import org.springframework.batch.retry.backoff.BackOffPolicy; -import org.springframework.batch.retry.context.RetryContextSupport; -import org.springframework.batch.retry.policy.RetryContextCache; -import org.springframework.batch.retry.support.DefaultRetryState; -import org.springframework.batch.retry.support.RetrySynchronizationManager; -import org.springframework.batch.retry.support.RetryTemplate; -import org.springframework.batch.support.Classifier; - -/** - * A special purpose retry template that deals specifically with multi-valued - * stateful retry. This is useful in the case where the operation to be retried - * operates on multiple items, and when it fails there is no way to decide which - * (if any) of the items was responsible. The {@link RetryState} used in the - * execute methods is composite, and when a failure occurs, all of the keys in - * the composite are "tarred with the same brush". Subsequent attempts to - * execute with any of the keys that have failed previously results in a new - * attempt and the previous state is used to check the {@link RetryPolicy}. If - * one of the failed items eventually succeeds then the others in the current - * composite for that attempt will be cleared from the context cache (as - * normal), but there may still be entries in the cache for the original failed - * items. This might mean that an item that did not cause a failure is never - * retried because other items in the same batch fail fatally first. - * - * @author Dave Syer - * - */ -public class BatchRetryTemplate implements RetryOperations { - - private class BatchRetryState extends DefaultRetryState { - - private final Collection keys; - - public BatchRetryState(Collection keys) { - super(keys); - this.keys = new ArrayList(keys); - } - - } - - private static class BatchRetryContext extends RetryContextSupport { - - private final Collection contexts; - - public BatchRetryContext(RetryContext parent, Collection contexts) { - - super(parent); - - this.contexts = contexts; - int count = 0; - - for (RetryContext context : contexts) { - int retryCount = context.getRetryCount(); - if (retryCount > count) { - count = retryCount; - registerThrowable(context.getLastThrowable()); - } - } - - } - - } - - private static class InnerRetryTemplate extends RetryTemplate { - - @Override - protected boolean canRetry(RetryPolicy retryPolicy, RetryContext context) { - - BatchRetryContext batchContext = (BatchRetryContext) context; - - for (RetryContext nextContext : batchContext.contexts) { - if (!super.canRetry(retryPolicy, nextContext)) { - return false; - } - } - - return true; - - } - - @Override - protected RetryContext open(RetryPolicy retryPolicy, RetryState state) { - - BatchRetryState batchState = (BatchRetryState) state; - - Collection contexts = new ArrayList(); - for (RetryState retryState : batchState.keys) { - contexts.add(super.open(retryPolicy, retryState)); - } - - return new BatchRetryContext(RetrySynchronizationManager.getContext(), contexts); - - } - - @Override - protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Exception e) { - - BatchRetryState batchState = (BatchRetryState) state; - BatchRetryContext batchContext = (BatchRetryContext) context; - - Iterator contextIterator = batchContext.contexts.iterator(); - for (RetryState retryState : batchState.keys) { - RetryContext nextContext = contextIterator.next(); - super.registerThrowable(retryPolicy, retryState, nextContext, e); - } - - } - - @Override - protected void close(RetryPolicy retryPolicy, RetryContext context, RetryState state, boolean succeeded) { - - BatchRetryState batchState = (BatchRetryState) state; - BatchRetryContext batchContext = (BatchRetryContext) context; - - Iterator contextIterator = batchContext.contexts.iterator(); - for (RetryState retryState : batchState.keys) { - RetryContext nextContext = contextIterator.next(); - super.close(retryPolicy, nextContext, retryState, succeeded); - } - - } - - @Override - protected T handleRetryExhausted(RecoveryCallback recoveryCallback, RetryContext context, - RetryState state) throws Exception { - - BatchRetryState batchState = (BatchRetryState) state; - BatchRetryContext batchContext = (BatchRetryContext) context; - - // Accumulate exceptions to be thrown so all the keys get a crack - Exception rethrowable = null; - ExhaustedRetryException exhausted = null; - - Iterator contextIterator = batchContext.contexts.iterator(); - for (RetryState retryState : batchState.keys) { - - RetryContext nextContext = contextIterator.next(); - - try { - super.handleRetryExhausted(null, nextContext, retryState); - } - catch (ExhaustedRetryException e) { - exhausted = e; - } - catch (Exception e) { - rethrowable = e; - } - - } - - if (recoveryCallback != null) { - return recoveryCallback.recover(context); - } - - if (exhausted != null) { - throw exhausted; - } - - throw rethrowable; - - } - - } - - private final InnerRetryTemplate delegate = new InnerRetryTemplate(); - - private final RetryTemplate regular = new RetryTemplate(); - - public T execute(RetryCallback retryCallback, Collection states) throws ExhaustedRetryException, - Exception { - RetryState batchState = new BatchRetryState(states); - return delegate.execute(retryCallback, batchState); - } - - public T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, - Collection states) throws ExhaustedRetryException, Exception { - RetryState batchState = new BatchRetryState(states); - return delegate.execute(retryCallback, recoveryCallback, batchState); - } - - public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, - RetryState retryState) throws Exception, ExhaustedRetryException { - return regular.execute(retryCallback, recoveryCallback, retryState); - } - - public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback) throws Exception { - return regular.execute(retryCallback, recoveryCallback); - } - - public final T execute(RetryCallback retryCallback, RetryState retryState) throws Exception, - ExhaustedRetryException { - return regular.execute(retryCallback, retryState); - } - - public final T execute(RetryCallback retryCallback) throws Exception { - return regular.execute(retryCallback); - } - - public static List createState(List keys) { - List states = new ArrayList(); - for (Object key : keys) { - states.add(new DefaultRetryState(key)); - } - return states; - } - - public static List createState(List keys, Classifier classifier) { - List states = new ArrayList(); - for (Object key : keys) { - states.add(new DefaultRetryState(key, classifier)); - } - return states; - } - - public void registerListener(RetryListener listener) { - delegate.registerListener(listener); - regular.registerListener(listener); - } - - public void setBackOffPolicy(BackOffPolicy backOffPolicy) { - delegate.setBackOffPolicy(backOffPolicy); - regular.setBackOffPolicy(backOffPolicy); - } - - public void setListeners(RetryListener[] listeners) { - delegate.setListeners(listeners); - regular.setListeners(listeners); - } - - public void setRetryContextCache(RetryContextCache retryContextCache) { - delegate.setRetryContextCache(retryContextCache); - regular.setRetryContextCache(retryContextCache); - } - - public void setRetryPolicy(RetryPolicy retryPolicy) { - delegate.setRetryPolicy(retryPolicy); - regular.setRetryPolicy(retryPolicy); - } - -} +/* + * Copyright 2006-2007 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.step.item; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.springframework.batch.retry.ExhaustedRetryException; +import org.springframework.batch.retry.RecoveryCallback; +import org.springframework.batch.retry.RetryCallback; +import org.springframework.batch.retry.RetryContext; +import org.springframework.batch.retry.RetryListener; +import org.springframework.batch.retry.RetryOperations; +import org.springframework.batch.retry.RetryPolicy; +import org.springframework.batch.retry.RetryState; +import org.springframework.batch.retry.backoff.BackOffPolicy; +import org.springframework.batch.retry.context.RetryContextSupport; +import org.springframework.batch.retry.policy.RetryContextCache; +import org.springframework.batch.retry.support.DefaultRetryState; +import org.springframework.batch.retry.support.RetrySynchronizationManager; +import org.springframework.batch.retry.support.RetryTemplate; +import org.springframework.batch.support.Classifier; + +/** + * A special purpose retry template that deals specifically with multi-valued + * stateful retry. This is useful in the case where the operation to be retried + * operates on multiple items, and when it fails there is no way to decide which + * (if any) of the items was responsible. The {@link RetryState} used in the + * execute methods is composite, and when a failure occurs, all of the keys in + * the composite are "tarred with the same brush". Subsequent attempts to + * execute with any of the keys that have failed previously results in a new + * attempt and the previous state is used to check the {@link RetryPolicy}. If + * one of the failed items eventually succeeds then the others in the current + * composite for that attempt will be cleared from the context cache (as + * normal), but there may still be entries in the cache for the original failed + * items. This might mean that an item that did not cause a failure is never + * retried because other items in the same batch fail fatally first. + * + * @author Dave Syer + * + */ +public class BatchRetryTemplate implements RetryOperations { + + private class BatchRetryState extends DefaultRetryState { + + private final Collection keys; + + public BatchRetryState(Collection keys) { + super(keys); + this.keys = new ArrayList(keys); + } + + } + + private static class BatchRetryContext extends RetryContextSupport { + + private final Collection contexts; + + public BatchRetryContext(RetryContext parent, Collection contexts) { + + super(parent); + + this.contexts = contexts; + int count = 0; + + for (RetryContext context : contexts) { + int retryCount = context.getRetryCount(); + if (retryCount > count) { + count = retryCount; + registerThrowable(context.getLastThrowable()); + } + } + + } + + } + + private static class InnerRetryTemplate extends RetryTemplate { + + @Override + protected boolean canRetry(RetryPolicy retryPolicy, RetryContext context) { + + BatchRetryContext batchContext = (BatchRetryContext) context; + + for (RetryContext nextContext : batchContext.contexts) { + if (!super.canRetry(retryPolicy, nextContext)) { + return false; + } + } + + return true; + + } + + @Override + protected RetryContext open(RetryPolicy retryPolicy, RetryState state) { + + BatchRetryState batchState = (BatchRetryState) state; + + Collection contexts = new ArrayList(); + for (RetryState retryState : batchState.keys) { + contexts.add(super.open(retryPolicy, retryState)); + } + + return new BatchRetryContext(RetrySynchronizationManager.getContext(), contexts); + + } + + @Override + protected void registerThrowable(RetryPolicy retryPolicy, RetryState state, RetryContext context, Exception e) { + + BatchRetryState batchState = (BatchRetryState) state; + BatchRetryContext batchContext = (BatchRetryContext) context; + + Iterator contextIterator = batchContext.contexts.iterator(); + for (RetryState retryState : batchState.keys) { + RetryContext nextContext = contextIterator.next(); + super.registerThrowable(retryPolicy, retryState, nextContext, e); + } + + } + + @Override + protected void close(RetryPolicy retryPolicy, RetryContext context, RetryState state, boolean succeeded) { + + BatchRetryState batchState = (BatchRetryState) state; + BatchRetryContext batchContext = (BatchRetryContext) context; + + Iterator contextIterator = batchContext.contexts.iterator(); + for (RetryState retryState : batchState.keys) { + RetryContext nextContext = contextIterator.next(); + super.close(retryPolicy, nextContext, retryState, succeeded); + } + + } + + @Override + protected T handleRetryExhausted(RecoveryCallback recoveryCallback, RetryContext context, + RetryState state) throws Exception { + + BatchRetryState batchState = (BatchRetryState) state; + BatchRetryContext batchContext = (BatchRetryContext) context; + + // Accumulate exceptions to be thrown so all the keys get a crack + Exception rethrowable = null; + ExhaustedRetryException exhausted = null; + + Iterator contextIterator = batchContext.contexts.iterator(); + for (RetryState retryState : batchState.keys) { + + RetryContext nextContext = contextIterator.next(); + + try { + super.handleRetryExhausted(null, nextContext, retryState); + } + catch (ExhaustedRetryException e) { + exhausted = e; + } + catch (Exception e) { + rethrowable = e; + } + + } + + if (recoveryCallback != null) { + return recoveryCallback.recover(context); + } + + if (exhausted != null) { + throw exhausted; + } + + throw rethrowable; + + } + + } + + private final InnerRetryTemplate delegate = new InnerRetryTemplate(); + + private final RetryTemplate regular = new RetryTemplate(); + + public T execute(RetryCallback retryCallback, Collection states) throws ExhaustedRetryException, + Exception { + RetryState batchState = new BatchRetryState(states); + return delegate.execute(retryCallback, batchState); + } + + public T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, + Collection states) throws ExhaustedRetryException, Exception { + RetryState batchState = new BatchRetryState(states); + return delegate.execute(retryCallback, recoveryCallback, batchState); + } + + public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, + RetryState retryState) throws Exception, ExhaustedRetryException { + return regular.execute(retryCallback, recoveryCallback, retryState); + } + + public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback) throws Exception { + return regular.execute(retryCallback, recoveryCallback); + } + + public final T execute(RetryCallback retryCallback, RetryState retryState) throws Exception, + ExhaustedRetryException { + return regular.execute(retryCallback, retryState); + } + + public final T execute(RetryCallback retryCallback) throws Exception { + return regular.execute(retryCallback); + } + + public static List createState(List keys) { + List states = new ArrayList(); + for (Object key : keys) { + states.add(new DefaultRetryState(key)); + } + return states; + } + + public static List createState(List keys, Classifier classifier) { + List states = new ArrayList(); + for (Object key : keys) { + states.add(new DefaultRetryState(key, classifier)); + } + return states; + } + + public void registerListener(RetryListener listener) { + delegate.registerListener(listener); + regular.registerListener(listener); + } + + public void setBackOffPolicy(BackOffPolicy backOffPolicy) { + delegate.setBackOffPolicy(backOffPolicy); + regular.setBackOffPolicy(backOffPolicy); + } + + public void setListeners(RetryListener[] listeners) { + delegate.setListeners(listeners); + regular.setListeners(listeners); + } + + public void setRetryContextCache(RetryContextCache retryContextCache) { + delegate.setRetryContextCache(retryContextCache); + regular.setRetryContextCache(retryContextCache); + } + + public void setRetryPolicy(RetryPolicy retryPolicy) { + delegate.setRetryPolicy(retryPolicy); + regular.setRetryPolicy(retryPolicy); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/Chunk.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/Chunk.java index a521d688a..8b239ed20 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/Chunk.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/Chunk.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import java.util.ArrayList; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkOrientedTasklet.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkOrientedTasklet.java index ea9800b60..82781ff69 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkOrientedTasklet.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkOrientedTasklet.java @@ -1,68 +1,84 @@ -package org.springframework.batch.core.step.item; - -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.scope.context.ChunkContext; -import org.springframework.batch.core.step.tasklet.Tasklet; -import org.springframework.batch.repeat.RepeatStatus; - -/** - * A {@link Tasklet} implementing variations on read-process-write item - * handling. - * - * @author Dave Syer - * - * @param input item type - */ -public class ChunkOrientedTasklet implements Tasklet { - - private static final String INPUTS_KEY = "INPUTS"; - - private final ChunkProcessor chunkProcessor; - - private final ChunkProvider chunkProvider; - - private boolean buffering = true; - - public ChunkOrientedTasklet(ChunkProvider chunkProvider, ChunkProcessor chunkProcessor) { - this.chunkProvider = chunkProvider; - this.chunkProcessor = chunkProcessor; - } - - /** - * Flag to indicate that items should be buffered once read. Defaults to - * true, which is appropriate for forward-only, non-transactional item - * readers. Main (or only) use case for setting this flag to true is a - * transactional JMS item reader. - * - * @param buffering - */ - public void setBuffering(boolean buffering) { - this.buffering = buffering; - } - - public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { - - @SuppressWarnings("unchecked") - Chunk inputs = (Chunk) chunkContext.getAttribute(INPUTS_KEY); - if (inputs == null) { - inputs = chunkProvider.provide(contribution); - if (buffering) { - chunkContext.setAttribute(INPUTS_KEY, inputs); - } - } - - chunkProcessor.process(contribution, inputs); - - chunkContext.removeAttribute(INPUTS_KEY); - chunkContext.setComplete(); - chunkProvider.postProcess(contribution, inputs); - if (!inputs.isEnd()) { - contribution.setExitStatus(ExitStatus.FINISHED); - } - - return RepeatStatus.continueIf(!inputs.isEnd()); - - } - -} +/* + * Copyright 2006-2007 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.step.item; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; + +/** + * A {@link Tasklet} implementing variations on read-process-write item + * handling. + * + * @author Dave Syer + * + * @param input item type + */ +public class ChunkOrientedTasklet implements Tasklet { + + private static final String INPUTS_KEY = "INPUTS"; + + private final ChunkProcessor chunkProcessor; + + private final ChunkProvider chunkProvider; + + private boolean buffering = true; + + public ChunkOrientedTasklet(ChunkProvider chunkProvider, ChunkProcessor chunkProcessor) { + this.chunkProvider = chunkProvider; + this.chunkProcessor = chunkProcessor; + } + + /** + * Flag to indicate that items should be buffered once read. Defaults to + * true, which is appropriate for forward-only, non-transactional item + * readers. Main (or only) use case for setting this flag to true is a + * transactional JMS item reader. + * + * @param buffering + */ + public void setBuffering(boolean buffering) { + this.buffering = buffering; + } + + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + + @SuppressWarnings("unchecked") + Chunk inputs = (Chunk) chunkContext.getAttribute(INPUTS_KEY); + if (inputs == null) { + inputs = chunkProvider.provide(contribution); + if (buffering) { + chunkContext.setAttribute(INPUTS_KEY, inputs); + } + } + + chunkProcessor.process(contribution, inputs); + + chunkContext.removeAttribute(INPUTS_KEY); + chunkContext.setComplete(); + chunkProvider.postProcess(contribution, inputs); + if (!inputs.isEnd()) { + contribution.setExitStatus(ExitStatus.FINISHED); + } + + return RepeatStatus.continueIf(!inputs.isEnd()); + + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProcessor.java index 0dba281da..a601809f2 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import org.springframework.batch.core.StepContribution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProvider.java index 97c3cfaf2..54315fb35 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ChunkProvider.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import org.springframework.batch.core.StepContribution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java index 9382ae133..dadcc1d8a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import java.util.Collections; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProvider.java index 0b786bcc9..85b4e3ca9 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProvider.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import org.springframework.batch.core.StepContribution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBean.java index 4cb431333..786dc03c8 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBean.java @@ -1,299 +1,315 @@ -package org.springframework.batch.core.step.item; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; - -import org.springframework.batch.core.ItemProcessListener; -import org.springframework.batch.core.ItemReadListener; -import org.springframework.batch.core.ItemWriteListener; -import org.springframework.batch.core.SkipListener; -import org.springframework.batch.core.step.skip.LimitCheckingItemSkipPolicy; -import org.springframework.batch.core.step.skip.NonSkippableReadException; -import org.springframework.batch.core.step.skip.SkipLimitExceededException; -import org.springframework.batch.core.step.skip.SkipListenerFailedException; -import org.springframework.batch.core.step.skip.SkipPolicy; -import org.springframework.batch.core.step.tasklet.TaskletStep; -import org.springframework.batch.repeat.RepeatOperations; -import org.springframework.batch.repeat.support.RepeatTemplate; -import org.springframework.batch.retry.RetryException; -import org.springframework.batch.retry.RetryListener; -import org.springframework.batch.retry.RetryPolicy; -import org.springframework.batch.retry.backoff.BackOffPolicy; -import org.springframework.batch.retry.policy.ExceptionClassifierRetryPolicy; -import org.springframework.batch.retry.policy.MapRetryContextCache; -import org.springframework.batch.retry.policy.RetryContextCache; -import org.springframework.batch.retry.policy.SimpleRetryPolicy; -import org.springframework.batch.support.Classifier; - -/** - * Factory bean for step that provides options for configuring skip behaviour. - * User can set {@link #setSkipLimit(int)} to set how many exceptions of - * {@link #setSkippableExceptionClasses(Collection)} types are tolerated. - * {@link #setFatalExceptionClasses(Collection)} will cause immediate - * termination of job - they are treated as higher priority than - * {@link #setSkippableExceptionClasses(Collection)}, so the two lists don't - * need to be exclusive. - * - * Skippable exceptions on write will by default cause transaction rollback - to - * avoid rollback for specific exception class include it in the transaction - * attribute as "no rollback for". - * - * @see SimpleStepFactoryBean - * - * @author Dave Syer - * @author Robert Kasanicky - * - */ -public class FaultTolerantStepFactoryBean extends SimpleStepFactoryBean { - - private int skipLimit = 0; - - private Collection> skippableExceptionClasses = new HashSet>(); - - private Collection> fatalExceptionClasses = new HashSet>(); - - { - fatalExceptionClasses.add(Error.class); - skippableExceptionClasses.add(Exception.class); - } - - private int cacheCapacity = 0; - - private int retryLimit = 0; - - private Collection> retryableExceptionClasses = new HashSet>(); - - private BackOffPolicy backOffPolicy; - - private RetryListener[] retryListeners; - - private RetryPolicy retryPolicy; - - private RetryContextCache retryContextCache; - - private boolean isReaderTransactionalQueue = false; - - public void setIsReaderTransactionalQueue(boolean isReaderTransactionalQueue) { - this.isReaderTransactionalQueue = isReaderTransactionalQueue; - } - - /** - * Setter for the retry policy. If this is specified the other retry - * properties are ignored (retryLimit, backOffPolicy, - * retryableExceptionClasses). - * - * @param retryPolicy a stateless {@link RetryPolicy} - */ - public void setRetryPolicy(RetryPolicy retryPolicy) { - this.retryPolicy = retryPolicy; - } - - /** - * Public setter for the retry limit. Each item can be retried up to this - * limit. - * @param retryLimit the retry limit to set - */ - public void setRetryLimit(int retryLimit) { - this.retryLimit = retryLimit; - } - - /** - * Public setter for the capacity of the cache in the retry policy. If more - * items than this fail without being skipped or recovered an exception will - * be thrown. This is to guard against inadvertent infinite loops generated - * by item identity problems.
- * - * The default value should be high enough and more for most purposes. To - * breach the limit in a single-threaded step typically you have to have - * this many failures in a single transaction. Defaults to the value in the - * {@link MapRetryContextCache}.
- * - * This property is ignored if the - * {@link #setRetryContextCache(RetryContextCache)} is set directly. - * - * @param cacheCapacity the cache capacity to set (greater than 0 else - * ignored) - */ - public void setCacheCapacity(int cacheCapacity) { - this.cacheCapacity = cacheCapacity; - } - - /** - * Override the default retry context cache for retry of chunk processing. - * If this property is set then {@link #setCacheCapacity(int)} is ignored. - * - * @param retryContextCache the {@link RetryContextCache} to set - */ - public void setRetryContextCache(RetryContextCache retryContextCache) { - this.retryContextCache = retryContextCache; - } - - /** - * Public setter for the Class[]. - * @param retryableExceptionClasses the retryableExceptionClasses to set - */ - public void setRetryableExceptionClasses(Collection> retryableExceptionClasses) { - this.retryableExceptionClasses = retryableExceptionClasses; - } - - /** - * Public setter for the {@link BackOffPolicy}. - * @param backOffPolicy the {@link BackOffPolicy} to set - */ - public void setBackOffPolicy(BackOffPolicy backOffPolicy) { - this.backOffPolicy = backOffPolicy; - } - - /** - * Public setter for the {@link RetryListener}s. - * @param retryListeners the {@link RetryListener}s to set - */ - public void setRetryListeners(RetryListener[] retryListeners) { - this.retryListeners = retryListeners; - } - - /** - * Public setter for a limit that determines skip policy. If this value is - * positive then an exception in chunk processing will cause the item to be - * skipped and no exception propagated until the limit is reached. If it is - * zero then all exceptions will be propagated from the chunk and cause the - * step to abort. - * - * @param skipLimit the value to set. Default is 0 (never skip). - */ - public void setSkipLimit(int skipLimit) { - this.skipLimit = skipLimit; - } - - /** - * Public setter for exception classes that when raised won't crash the job - * but will result in transaction rollback and the item which handling - * caused the exception will be skipped. - * - * @param exceptionClasses defaults to Exception - */ - public void setSkippableExceptionClasses(Collection> exceptionClasses) { - this.skippableExceptionClasses = exceptionClasses; - } - - /** - * Public setter for exception classes that should cause immediate failure. - * - * @param fatalExceptionClasses {@link Error} by default - */ - public void setFatalExceptionClasses(Collection> fatalExceptionClasses) { - this.fatalExceptionClasses = fatalExceptionClasses; - } - - /** - * Uses the {@link #setSkipLimit(int)} value to configure item handler and - * and exception handler. - */ - protected void applyConfiguration(TaskletStep step) { - super.applyConfiguration(step); - - if (retryLimit > 0 || skipLimit > 0 || retryPolicy != null) { - - addFatalExceptionIfMissing(SkipLimitExceededException.class); - addFatalExceptionIfMissing(NonSkippableReadException.class); - addFatalExceptionIfMissing(SkipListenerFailedException.class); - addFatalExceptionIfMissing(RetryException.class); - - if (retryPolicy == null) { - - SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(retryLimit); - if (!retryableExceptionClasses.isEmpty()) { // otherwise we - // retry all exceptions - simpleRetryPolicy.setRetryableExceptionClasses(retryableExceptionClasses); - } - simpleRetryPolicy.setFatalExceptionClasses(fatalExceptionClasses); - - ExceptionClassifierRetryPolicy classifierRetryPolicy = new ExceptionClassifierRetryPolicy(); - HashMap, RetryPolicy> exceptionTypeMap = new HashMap, RetryPolicy>(); - for (Class cls : retryableExceptionClasses) { - exceptionTypeMap.put(cls, simpleRetryPolicy); - } - classifierRetryPolicy.setPolicyMap(exceptionTypeMap); - retryPolicy = classifierRetryPolicy; - - } - BatchRetryTemplate batchRetryTemplate = new BatchRetryTemplate(); - if (backOffPolicy != null) { - batchRetryTemplate.setBackOffPolicy(backOffPolicy); - } - batchRetryTemplate.setRetryPolicy(retryPolicy); - - // Co-ordinate the retry policy with the exception handler: - RepeatOperations stepOperations = getStepOperations(); - if (stepOperations instanceof RepeatTemplate) { - SimpleRetryExceptionHandler exceptionHandler = new SimpleRetryExceptionHandler(retryPolicy, - getExceptionHandler(), fatalExceptionClasses); - ((RepeatTemplate) stepOperations).setExceptionHandler(exceptionHandler); - } - - if (retryContextCache == null) { - if (cacheCapacity > 0) { - batchRetryTemplate.setRetryContextCache(new MapRetryContextCache(cacheCapacity)); - } - } - else { - batchRetryTemplate.setRetryContextCache(retryContextCache); - } - - if (retryListeners != null) { - batchRetryTemplate.setListeners(retryListeners); - } - - List> exceptions = new ArrayList>( - skippableExceptionClasses); - SkipPolicy readSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, skippableExceptionClasses, - new ArrayList>(fatalExceptionClasses)); - exceptions.addAll(new ArrayList>(retryableExceptionClasses)); - SkipPolicy writeSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, exceptions, - new ArrayList>(fatalExceptionClasses)); - - Classifier rollbackClassifier = new Classifier() { - public Boolean classify(Throwable classifiable) { - return getTransactionAttribute().rollbackOn(classifiable); - } - }; - - FaultTolerantChunkProvider chunkProvider = new FaultTolerantChunkProvider(getItemReader(), - getChunkOperations()); - chunkProvider.setSkipPolicy(readSkipPolicy); - chunkProvider.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemReadListener.class)); - chunkProvider.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), SkipListener.class)); - - FaultTolerantChunkProcessor chunkProcessor = new FaultTolerantChunkProcessor(getItemProcessor(), getItemWriter(), batchRetryTemplate); - chunkProcessor.setBuffering(!isReaderTransactionalQueue); - chunkProcessor.setWriteSkipPolicy(writeSkipPolicy); - chunkProcessor.setProcessSkipPolicy(writeSkipPolicy); - chunkProcessor.setRollbackClassifier(rollbackClassifier); - chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemProcessListener.class)); - chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemWriteListener.class)); - chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), SkipListener.class)); - - ChunkOrientedTasklet tasklet = new ChunkOrientedTasklet(chunkProvider, chunkProcessor); - tasklet.setBuffering(!isReaderTransactionalQueue); - - step.setTasklet(tasklet); - - } - - } - - public void addFatalExceptionIfMissing(Class cls) { - List> fatalExceptionList = new ArrayList>(); - for (Class exceptionClass : fatalExceptionClasses) { - fatalExceptionList.add(exceptionClass); - } - if (!fatalExceptionList.contains(cls)) { - fatalExceptionList.add(cls); - } - fatalExceptionClasses = fatalExceptionList; - } - -} +/* + * Copyright 2006-2007 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.step.item; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +import org.springframework.batch.core.ItemProcessListener; +import org.springframework.batch.core.ItemReadListener; +import org.springframework.batch.core.ItemWriteListener; +import org.springframework.batch.core.SkipListener; +import org.springframework.batch.core.step.skip.LimitCheckingItemSkipPolicy; +import org.springframework.batch.core.step.skip.NonSkippableReadException; +import org.springframework.batch.core.step.skip.SkipLimitExceededException; +import org.springframework.batch.core.step.skip.SkipListenerFailedException; +import org.springframework.batch.core.step.skip.SkipPolicy; +import org.springframework.batch.core.step.tasklet.TaskletStep; +import org.springframework.batch.repeat.RepeatOperations; +import org.springframework.batch.repeat.support.RepeatTemplate; +import org.springframework.batch.retry.RetryException; +import org.springframework.batch.retry.RetryListener; +import org.springframework.batch.retry.RetryPolicy; +import org.springframework.batch.retry.backoff.BackOffPolicy; +import org.springframework.batch.retry.policy.ExceptionClassifierRetryPolicy; +import org.springframework.batch.retry.policy.MapRetryContextCache; +import org.springframework.batch.retry.policy.RetryContextCache; +import org.springframework.batch.retry.policy.SimpleRetryPolicy; +import org.springframework.batch.support.Classifier; + +/** + * Factory bean for step that provides options for configuring skip behaviour. + * User can set {@link #setSkipLimit(int)} to set how many exceptions of + * {@link #setSkippableExceptionClasses(Collection)} types are tolerated. + * {@link #setFatalExceptionClasses(Collection)} will cause immediate + * termination of job - they are treated as higher priority than + * {@link #setSkippableExceptionClasses(Collection)}, so the two lists don't + * need to be exclusive. + * + * Skippable exceptions on write will by default cause transaction rollback - to + * avoid rollback for specific exception class include it in the transaction + * attribute as "no rollback for". + * + * @see SimpleStepFactoryBean + * + * @author Dave Syer + * @author Robert Kasanicky + * + */ +public class FaultTolerantStepFactoryBean extends SimpleStepFactoryBean { + + private int skipLimit = 0; + + private Collection> skippableExceptionClasses = new HashSet>(); + + private Collection> fatalExceptionClasses = new HashSet>(); + + { + fatalExceptionClasses.add(Error.class); + skippableExceptionClasses.add(Exception.class); + } + + private int cacheCapacity = 0; + + private int retryLimit = 0; + + private Collection> retryableExceptionClasses = new HashSet>(); + + private BackOffPolicy backOffPolicy; + + private RetryListener[] retryListeners; + + private RetryPolicy retryPolicy; + + private RetryContextCache retryContextCache; + + private boolean isReaderTransactionalQueue = false; + + public void setIsReaderTransactionalQueue(boolean isReaderTransactionalQueue) { + this.isReaderTransactionalQueue = isReaderTransactionalQueue; + } + + /** + * Setter for the retry policy. If this is specified the other retry + * properties are ignored (retryLimit, backOffPolicy, + * retryableExceptionClasses). + * + * @param retryPolicy a stateless {@link RetryPolicy} + */ + public void setRetryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + } + + /** + * Public setter for the retry limit. Each item can be retried up to this + * limit. + * @param retryLimit the retry limit to set + */ + public void setRetryLimit(int retryLimit) { + this.retryLimit = retryLimit; + } + + /** + * Public setter for the capacity of the cache in the retry policy. If more + * items than this fail without being skipped or recovered an exception will + * be thrown. This is to guard against inadvertent infinite loops generated + * by item identity problems.
+ * + * The default value should be high enough and more for most purposes. To + * breach the limit in a single-threaded step typically you have to have + * this many failures in a single transaction. Defaults to the value in the + * {@link MapRetryContextCache}.
+ * + * This property is ignored if the + * {@link #setRetryContextCache(RetryContextCache)} is set directly. + * + * @param cacheCapacity the cache capacity to set (greater than 0 else + * ignored) + */ + public void setCacheCapacity(int cacheCapacity) { + this.cacheCapacity = cacheCapacity; + } + + /** + * Override the default retry context cache for retry of chunk processing. + * If this property is set then {@link #setCacheCapacity(int)} is ignored. + * + * @param retryContextCache the {@link RetryContextCache} to set + */ + public void setRetryContextCache(RetryContextCache retryContextCache) { + this.retryContextCache = retryContextCache; + } + + /** + * Public setter for the Class[]. + * @param retryableExceptionClasses the retryableExceptionClasses to set + */ + public void setRetryableExceptionClasses(Collection> retryableExceptionClasses) { + this.retryableExceptionClasses = retryableExceptionClasses; + } + + /** + * Public setter for the {@link BackOffPolicy}. + * @param backOffPolicy the {@link BackOffPolicy} to set + */ + public void setBackOffPolicy(BackOffPolicy backOffPolicy) { + this.backOffPolicy = backOffPolicy; + } + + /** + * Public setter for the {@link RetryListener}s. + * @param retryListeners the {@link RetryListener}s to set + */ + public void setRetryListeners(RetryListener[] retryListeners) { + this.retryListeners = retryListeners; + } + + /** + * Public setter for a limit that determines skip policy. If this value is + * positive then an exception in chunk processing will cause the item to be + * skipped and no exception propagated until the limit is reached. If it is + * zero then all exceptions will be propagated from the chunk and cause the + * step to abort. + * + * @param skipLimit the value to set. Default is 0 (never skip). + */ + public void setSkipLimit(int skipLimit) { + this.skipLimit = skipLimit; + } + + /** + * Public setter for exception classes that when raised won't crash the job + * but will result in transaction rollback and the item which handling + * caused the exception will be skipped. + * + * @param exceptionClasses defaults to Exception + */ + public void setSkippableExceptionClasses(Collection> exceptionClasses) { + this.skippableExceptionClasses = exceptionClasses; + } + + /** + * Public setter for exception classes that should cause immediate failure. + * + * @param fatalExceptionClasses {@link Error} by default + */ + public void setFatalExceptionClasses(Collection> fatalExceptionClasses) { + this.fatalExceptionClasses = fatalExceptionClasses; + } + + /** + * Uses the {@link #setSkipLimit(int)} value to configure item handler and + * and exception handler. + */ + protected void applyConfiguration(TaskletStep step) { + super.applyConfiguration(step); + + if (retryLimit > 0 || skipLimit > 0 || retryPolicy != null) { + + addFatalExceptionIfMissing(SkipLimitExceededException.class); + addFatalExceptionIfMissing(NonSkippableReadException.class); + addFatalExceptionIfMissing(SkipListenerFailedException.class); + addFatalExceptionIfMissing(RetryException.class); + + if (retryPolicy == null) { + + SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(retryLimit); + if (!retryableExceptionClasses.isEmpty()) { // otherwise we + // retry all exceptions + simpleRetryPolicy.setRetryableExceptionClasses(retryableExceptionClasses); + } + simpleRetryPolicy.setFatalExceptionClasses(fatalExceptionClasses); + + ExceptionClassifierRetryPolicy classifierRetryPolicy = new ExceptionClassifierRetryPolicy(); + HashMap, RetryPolicy> exceptionTypeMap = new HashMap, RetryPolicy>(); + for (Class cls : retryableExceptionClasses) { + exceptionTypeMap.put(cls, simpleRetryPolicy); + } + classifierRetryPolicy.setPolicyMap(exceptionTypeMap); + retryPolicy = classifierRetryPolicy; + + } + BatchRetryTemplate batchRetryTemplate = new BatchRetryTemplate(); + if (backOffPolicy != null) { + batchRetryTemplate.setBackOffPolicy(backOffPolicy); + } + batchRetryTemplate.setRetryPolicy(retryPolicy); + + // Co-ordinate the retry policy with the exception handler: + RepeatOperations stepOperations = getStepOperations(); + if (stepOperations instanceof RepeatTemplate) { + SimpleRetryExceptionHandler exceptionHandler = new SimpleRetryExceptionHandler(retryPolicy, + getExceptionHandler(), fatalExceptionClasses); + ((RepeatTemplate) stepOperations).setExceptionHandler(exceptionHandler); + } + + if (retryContextCache == null) { + if (cacheCapacity > 0) { + batchRetryTemplate.setRetryContextCache(new MapRetryContextCache(cacheCapacity)); + } + } + else { + batchRetryTemplate.setRetryContextCache(retryContextCache); + } + + if (retryListeners != null) { + batchRetryTemplate.setListeners(retryListeners); + } + + List> exceptions = new ArrayList>( + skippableExceptionClasses); + SkipPolicy readSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, skippableExceptionClasses, + new ArrayList>(fatalExceptionClasses)); + exceptions.addAll(new ArrayList>(retryableExceptionClasses)); + SkipPolicy writeSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, exceptions, + new ArrayList>(fatalExceptionClasses)); + + Classifier rollbackClassifier = new Classifier() { + public Boolean classify(Throwable classifiable) { + return getTransactionAttribute().rollbackOn(classifiable); + } + }; + + FaultTolerantChunkProvider chunkProvider = new FaultTolerantChunkProvider(getItemReader(), + getChunkOperations()); + chunkProvider.setSkipPolicy(readSkipPolicy); + chunkProvider.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemReadListener.class)); + chunkProvider.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), SkipListener.class)); + + FaultTolerantChunkProcessor chunkProcessor = new FaultTolerantChunkProcessor(getItemProcessor(), getItemWriter(), batchRetryTemplate); + chunkProcessor.setBuffering(!isReaderTransactionalQueue); + chunkProcessor.setWriteSkipPolicy(writeSkipPolicy); + chunkProcessor.setProcessSkipPolicy(writeSkipPolicy); + chunkProcessor.setRollbackClassifier(rollbackClassifier); + chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemProcessListener.class)); + chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), ItemWriteListener.class)); + chunkProcessor.setListeners(BatchListenerFactoryHelper.>getListeners(getListeners(), SkipListener.class)); + + ChunkOrientedTasklet tasklet = new ChunkOrientedTasklet(chunkProvider, chunkProcessor); + tasklet.setBuffering(!isReaderTransactionalQueue); + + step.setTasklet(tasklet); + + } + + } + + public void addFatalExceptionIfMissing(Class cls) { + List> fatalExceptionList = new ArrayList>(); + for (Class exceptionClass : fatalExceptionClasses) { + fatalExceptionList.add(exceptionClass); + } + if (!fatalExceptionList.contains(cls)) { + fatalExceptionList.add(cls); + } + fatalExceptionClasses = fatalExceptionList; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java index eef3134da..eea908696 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; import java.util.List; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java index 0e4696c26..d6dd035dd 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java @@ -1,114 +1,130 @@ -package org.springframework.batch.core.step.item; - -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.StepListener; -import org.springframework.batch.core.listener.MulticasterBatchListener; -import org.springframework.batch.core.step.skip.SkipListenerFailedException; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.repeat.RepeatCallback; -import org.springframework.batch.repeat.RepeatContext; -import org.springframework.batch.repeat.RepeatOperations; -import org.springframework.batch.repeat.RepeatStatus; - -/** - * - * @author Dave Syer - * - * @param input item type - */ -public class SimpleChunkProvider implements ChunkProvider { - - protected final Log logger = LogFactory.getLog(getClass()); - - protected final ItemReader itemReader; - - private final MulticasterBatchListener listener = new MulticasterBatchListener(); - - private final RepeatOperations repeatOperations; - - public SimpleChunkProvider(ItemReader itemReader, RepeatOperations repeatOperations) { - this.itemReader = itemReader; - this.repeatOperations = repeatOperations; - } - - /** - * Register some {@link StepListener}s with the handler. Each will get the - * callbacks in the order specified at the correct stage. - * - * @param listeners - */ - public void setListeners(List listeners) { - for (StepListener listener : listeners) { - registerListener(listener); - } - } - - /** - * Register a listener for callbacks at the appropriate stages in a process. - * - * @param listener a {@link StepListener} - */ - public void registerListener(StepListener listener) { - this.listener.register(listener); - } - - /** - * Surrounds the read call with listener callbacks. - * @return item - * @throws Exception - */ - protected final I doRead() throws Exception { - try { - listener.beforeRead(); - I item = itemReader.read(); - listener.afterRead(item); - return item; - } - catch (Exception e) { - listener.onReadError(e); - throw e; - } - } - - public Chunk provide(final StepContribution contribution) throws Exception { - - final Chunk inputs = new Chunk(); - repeatOperations.iterate(new RepeatCallback() { - - public RepeatStatus doInIteration(final RepeatContext context) throws Exception { - I item = read(contribution, inputs); - if (item == null) { - inputs.setEnd(); - return RepeatStatus.FINISHED; - } - inputs.add(item); - contribution.incrementReadCount(); - return RepeatStatus.CONTINUABLE; - } - - }); - - return inputs; - - } - - public void postProcess(StepContribution contribution, Chunk chunk) { - for (Exception e : chunk.getErrors()) { - try { - listener.onSkipInRead(e); - } - catch (RuntimeException ex) { - throw new SkipListenerFailedException("Fatal exception in SkipListener.", ex, e); - } - } - } - - protected I read(StepContribution contribution, Chunk chunk) throws Exception { - return doRead(); - } - -} +/* + * Copyright 2006-2007 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.step.item; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.StepListener; +import org.springframework.batch.core.listener.MulticasterBatchListener; +import org.springframework.batch.core.step.skip.SkipListenerFailedException; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.repeat.RepeatCallback; +import org.springframework.batch.repeat.RepeatContext; +import org.springframework.batch.repeat.RepeatOperations; +import org.springframework.batch.repeat.RepeatStatus; + +/** + * + * @author Dave Syer + * + * @param input item type + */ +public class SimpleChunkProvider implements ChunkProvider { + + protected final Log logger = LogFactory.getLog(getClass()); + + protected final ItemReader itemReader; + + private final MulticasterBatchListener listener = new MulticasterBatchListener(); + + private final RepeatOperations repeatOperations; + + public SimpleChunkProvider(ItemReader itemReader, RepeatOperations repeatOperations) { + this.itemReader = itemReader; + this.repeatOperations = repeatOperations; + } + + /** + * Register some {@link StepListener}s with the handler. Each will get the + * callbacks in the order specified at the correct stage. + * + * @param listeners + */ + public void setListeners(List listeners) { + for (StepListener listener : listeners) { + registerListener(listener); + } + } + + /** + * Register a listener for callbacks at the appropriate stages in a process. + * + * @param listener a {@link StepListener} + */ + public void registerListener(StepListener listener) { + this.listener.register(listener); + } + + /** + * Surrounds the read call with listener callbacks. + * @return item + * @throws Exception + */ + protected final I doRead() throws Exception { + try { + listener.beforeRead(); + I item = itemReader.read(); + listener.afterRead(item); + return item; + } + catch (Exception e) { + listener.onReadError(e); + throw e; + } + } + + public Chunk provide(final StepContribution contribution) throws Exception { + + final Chunk inputs = new Chunk(); + repeatOperations.iterate(new RepeatCallback() { + + public RepeatStatus doInIteration(final RepeatContext context) throws Exception { + I item = read(contribution, inputs); + if (item == null) { + inputs.setEnd(); + return RepeatStatus.FINISHED; + } + inputs.add(item); + contribution.incrementReadCount(); + return RepeatStatus.CONTINUABLE; + } + + }); + + return inputs; + + } + + public void postProcess(StepContribution contribution, Chunk chunk) { + for (Exception e : chunk.getErrors()) { + try { + listener.onSkipInRead(e); + } + catch (RuntimeException ex) { + throw new SkipListenerFailedException("Fatal exception in SkipListener.", ex, e); + } + } + } + + protected I read(StepContribution contribution, Chunk chunk) throws Exception { + return doRead(); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SkipWrapper.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SkipWrapper.java index b272f4bce..74bdba1f0 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SkipWrapper.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SkipWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.step.item; /** diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/skip/NonSkippableReadException.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/skip/NonSkippableReadException.java index 6a76ebdd5..eee28a77f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/skip/NonSkippableReadException.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/skip/NonSkippableReadException.java @@ -1,11 +1,27 @@ -package org.springframework.batch.core.step.skip; - -import org.springframework.core.NestedRuntimeException; - -public class NonSkippableReadException extends NestedRuntimeException { - - public NonSkippableReadException(String msg, Throwable cause) { - super(msg, cause); - } - -} +/* + * Copyright 2006-2007 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.step.skip; + +import org.springframework.core.NestedRuntimeException; + +public class NonSkippableReadException extends NestedRuntimeException { + + public NonSkippableReadException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/ConfigurableSystemProcessExitCodeMapper.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/ConfigurableSystemProcessExitCodeMapper.java index 74ebd19cf..ee1e6ab0c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/ConfigurableSystemProcessExitCodeMapper.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/ConfigurableSystemProcessExitCodeMapper.java @@ -1,40 +1,56 @@ -package org.springframework.batch.core.step.tasklet; - -import java.util.Map; - -import org.springframework.batch.core.ExitStatus; -import org.springframework.util.Assert; - -/** - * Maps exit codes to {@link org.springframework.batch.core.ExitStatus} - * according to injected map. The injected map is required to contain a value - * for 'else' key, this value will be returned if the injected map - * does not contain value for the exit code returned by the system process. - * - * @author Robert Kasanicky - */ -public class ConfigurableSystemProcessExitCodeMapper implements SystemProcessExitCodeMapper { - - public static final String ELSE_KEY = "else"; - - private Map mappings; - - public ExitStatus getExitStatus(int exitCode) { - ExitStatus exitStatus = mappings.get(exitCode); - if (exitStatus != null) { - return exitStatus; - } else { - return mappings.get(ELSE_KEY); - } - } - - /** - * @param mappings Integer exit code keys to - * {@link org.springframework.batch.core.ExitStatus} values. - */ - public void setMappings(Map mappings) { - Assert.notNull(mappings.get(ELSE_KEY)); - this.mappings = mappings; - } - -} +/* + * Copyright 2006-2007 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.step.tasklet; + +import java.util.Map; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.util.Assert; + +/** + * Maps exit codes to {@link org.springframework.batch.core.ExitStatus} + * according to injected map. The injected map is required to contain a value + * for 'else' key, this value will be returned if the injected map + * does not contain value for the exit code returned by the system process. + * + * @author Robert Kasanicky + */ +public class ConfigurableSystemProcessExitCodeMapper implements SystemProcessExitCodeMapper { + + public static final String ELSE_KEY = "else"; + + private Map mappings; + + public ExitStatus getExitStatus(int exitCode) { + ExitStatus exitStatus = mappings.get(exitCode); + if (exitStatus != null) { + return exitStatus; + } else { + return mappings.get(ELSE_KEY); + } + } + + /** + * @param mappings Integer exit code keys to + * {@link org.springframework.batch.core.ExitStatus} values. + */ + public void setMappings(Map mappings) { + Assert.notNull(mappings.get(ELSE_KEY)); + this.mappings = mappings; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SimpleSystemProcessExitCodeMapper.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SimpleSystemProcessExitCodeMapper.java index a74409087..314f5573c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SimpleSystemProcessExitCodeMapper.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SimpleSystemProcessExitCodeMapper.java @@ -1,22 +1,38 @@ -package org.springframework.batch.core.step.tasklet; - -import org.springframework.batch.core.ExitStatus; - -/** - * Simple {@link SystemProcessExitCodeMapper} implementation that performs following mapping: - * - * 0 -> ExitStatus.FINISHED - * else -> ExitStatus.FAILED - * - * @author Robert Kasanicky - */ -public class SimpleSystemProcessExitCodeMapper implements SystemProcessExitCodeMapper { - public ExitStatus getExitStatus(int exitCode) { - if (exitCode == 0) { - return ExitStatus.FINISHED; - } else { - return ExitStatus.FAILED; - } - } - -} +/* + * Copyright 2006-2007 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.step.tasklet; + +import org.springframework.batch.core.ExitStatus; + +/** + * Simple {@link SystemProcessExitCodeMapper} implementation that performs following mapping: + * + * 0 -> ExitStatus.FINISHED + * else -> ExitStatus.FAILED + * + * @author Robert Kasanicky + */ +public class SimpleSystemProcessExitCodeMapper implements SystemProcessExitCodeMapper { + public ExitStatus getExitStatus(int exitCode) { + if (exitCode == 0) { + return ExitStatus.FINISHED; + } else { + return ExitStatus.FAILED; + } + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandException.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandException.java index c5a234612..9a8e850bb 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandException.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandException.java @@ -1,18 +1,34 @@ -package org.springframework.batch.core.step.tasklet; - -/** - * Exception indicating failed execution of system command. - */ -public class SystemCommandException extends RuntimeException { - - // generated - private static final long serialVersionUID = 5139355923336176733L; - - public SystemCommandException(String message) { - super(message); - } - - public SystemCommandException(String message, Throwable cause) { - super(message, cause); - } -} +/* + * Copyright 2006-2007 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.step.tasklet; + +/** + * Exception indicating failed execution of system command. + */ +public class SystemCommandException extends RuntimeException { + + // generated + private static final long serialVersionUID = 5139355923336176733L; + + public SystemCommandException(String message) { + super(message); + } + + public SystemCommandException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java index 38c582b25..8bf954bec 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java @@ -1,199 +1,215 @@ -package org.springframework.batch.core.step.tasklet; - -import java.io.File; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; - -import org.apache.commons.lang.time.StopWatch; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.JobInterruptedException; -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.listener.StepExecutionListenerSupport; -import org.springframework.batch.core.scope.context.ChunkContext; -import org.springframework.batch.repeat.RepeatStatus; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.util.Assert; - -/** - * {@link Tasklet} that executes a system command. - * - * The system command is executed asynchronously using injected - * {@link #setTaskExecutor(TaskExecutor)} - timeout value is required to be set, - * so that the batch job does not hang forever if the external process hangs. - * - * Tasklet periodically checks for termination status (i.e. - * {@link #setCommand(String)} finished its execution or - * {@link #setTimeout(long)} expired or job was interrupted). The check interval - * is given by {@link #setTerminationCheckInterval(long)}. - * - * When job interrupt is detected tasklet's execution is terminated immediately - * by throwing {@link JobInterruptedException}. - * - * {@link #setInterruptOnCancel(boolean)} specifies whether the tasklet should - * attempt to interrupt the thread that executes the system command if it is - * still running when tasklet exits (abnormally). - * - * @author Robert Kasanicky - */ -public class SystemCommandTasklet extends StepExecutionListenerSupport implements Tasklet, InitializingBean { - - protected static final Log logger = LogFactory.getLog(SystemCommandTasklet.class); - - private String command; - - private String[] environmentParams = null; - - private File workingDirectory = null; - - private SystemProcessExitCodeMapper systemProcessExitCodeMapper = new SimpleSystemProcessExitCodeMapper(); - - private long timeout = 0; - - private long checkInterval = 1000; - - private StepExecution execution = null; - - private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - - private boolean interruptOnCancel = false; - - /** - * Execute system command and map its exit code to {@link ExitStatus} using - * {@link SystemProcessExitCodeMapper}. - */ - public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { - - FutureTask systemCommandTask = new FutureTask(new Callable() { - - public Integer call() throws Exception { - Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory); - return process.waitFor(); - } - - }); - - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - taskExecutor.execute(systemCommandTask); - - try { - while (true) { - Thread.sleep(checkInterval); - if (systemCommandTask.isDone()) { - contribution.setExitStatus(systemProcessExitCodeMapper.getExitStatus(systemCommandTask.get())); - return RepeatStatus.FINISHED; - } - else if (stopWatch.getTime() > timeout) { - systemCommandTask.cancel(interruptOnCancel); - throw new SystemCommandException("Execution of system command did not finish within the timeout"); - } - else if (execution.isTerminateOnly()) { - systemCommandTask.cancel(interruptOnCancel); - throw new JobInterruptedException("Job interrupted while executing system command '" + command - + "'"); - } - } - } - finally { - stopWatch.stop(); - } - - } - - /** - * @param command command to be executed in a separate system process - */ - public void setCommand(String command) { - this.command = command; - } - - /** - * @param envp environment parameter values, inherited from parent process - * when not set (or set to null). - */ - public void setEnvironmentParams(String[] envp) { - this.environmentParams = envp; - } - - /** - * @param dir working directory of the spawned process, inherited from - * parent process when not set (or set to null). - */ - public void setWorkingDirectory(String dir) { - if (dir == null) { - this.workingDirectory = null; - return; - } - this.workingDirectory = new File(dir); - Assert.isTrue(workingDirectory.exists(), "working directory must exist"); - Assert.isTrue(workingDirectory.isDirectory(), "working directory value must be a directory"); - - } - - public void afterPropertiesSet() throws Exception { - Assert.hasLength(command, "'command' property value is required"); - Assert.notNull(systemProcessExitCodeMapper, "SystemProcessExitCodeMapper must be set"); - Assert.isTrue(timeout > 0, "timeout value must be greater than zero"); - Assert.notNull(taskExecutor, "taskExecutor is required"); - } - - /** - * @param systemProcessExitCodeMapper maps system process return value to - * ExitStatus returned by Tasklet. - * {@link SimpleSystemProcessExitCodeMapper} is used by default. - */ - public void setSystemProcessExitCodeMapper(SystemProcessExitCodeMapper systemProcessExitCodeMapper) { - this.systemProcessExitCodeMapper = systemProcessExitCodeMapper; - } - - /** - * @param timeout upper limit for how long the execution of the external - * program is allowed to last. - */ - public void setTimeout(long timeout) { - this.timeout = timeout; - } - - /** - * The time interval how often the tasklet will check for termination - * status. - * - * @param checkInterval time interval in milliseconds (1 second by default). - */ - public void setTerminationCheckInterval(long checkInterval) { - this.checkInterval = checkInterval; - } - - /** - * Get a reference to {@link StepExecution} for interrupt checks during - * system command execution. - */ - @Override - public void beforeStep(StepExecution stepExecution) { - this.execution = stepExecution; - } - - /** - * Sets the task executor that will be used to execute the system command - * NB! Avoid using a synchronous task executor - */ - public void setTaskExecutor(TaskExecutor taskExecutor) { - this.taskExecutor = taskExecutor; - } - - /** - * If true tasklet will attempt to interrupt the thread - * executing the system command if {@link #setTimeout(long)} has been - * exceeded or user interrupts the job. false by default - */ - public void setInterruptOnCancel(boolean interruptOnCancel) { - this.interruptOnCancel = interruptOnCancel; - } - -} +/* + * Copyright 2006-2007 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.step.tasklet; + +import java.io.File; +import java.util.concurrent.Callable; +import java.util.concurrent.FutureTask; + +import org.apache.commons.lang.time.StopWatch; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobInterruptedException; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.listener.StepExecutionListenerSupport; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskExecutor; +import org.springframework.util.Assert; + +/** + * {@link Tasklet} that executes a system command. + * + * The system command is executed asynchronously using injected + * {@link #setTaskExecutor(TaskExecutor)} - timeout value is required to be set, + * so that the batch job does not hang forever if the external process hangs. + * + * Tasklet periodically checks for termination status (i.e. + * {@link #setCommand(String)} finished its execution or + * {@link #setTimeout(long)} expired or job was interrupted). The check interval + * is given by {@link #setTerminationCheckInterval(long)}. + * + * When job interrupt is detected tasklet's execution is terminated immediately + * by throwing {@link JobInterruptedException}. + * + * {@link #setInterruptOnCancel(boolean)} specifies whether the tasklet should + * attempt to interrupt the thread that executes the system command if it is + * still running when tasklet exits (abnormally). + * + * @author Robert Kasanicky + */ +public class SystemCommandTasklet extends StepExecutionListenerSupport implements Tasklet, InitializingBean { + + protected static final Log logger = LogFactory.getLog(SystemCommandTasklet.class); + + private String command; + + private String[] environmentParams = null; + + private File workingDirectory = null; + + private SystemProcessExitCodeMapper systemProcessExitCodeMapper = new SimpleSystemProcessExitCodeMapper(); + + private long timeout = 0; + + private long checkInterval = 1000; + + private StepExecution execution = null; + + private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); + + private boolean interruptOnCancel = false; + + /** + * Execute system command and map its exit code to {@link ExitStatus} using + * {@link SystemProcessExitCodeMapper}. + */ + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + + FutureTask systemCommandTask = new FutureTask(new Callable() { + + public Integer call() throws Exception { + Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory); + return process.waitFor(); + } + + }); + + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + taskExecutor.execute(systemCommandTask); + + try { + while (true) { + Thread.sleep(checkInterval); + if (systemCommandTask.isDone()) { + contribution.setExitStatus(systemProcessExitCodeMapper.getExitStatus(systemCommandTask.get())); + return RepeatStatus.FINISHED; + } + else if (stopWatch.getTime() > timeout) { + systemCommandTask.cancel(interruptOnCancel); + throw new SystemCommandException("Execution of system command did not finish within the timeout"); + } + else if (execution.isTerminateOnly()) { + systemCommandTask.cancel(interruptOnCancel); + throw new JobInterruptedException("Job interrupted while executing system command '" + command + + "'"); + } + } + } + finally { + stopWatch.stop(); + } + + } + + /** + * @param command command to be executed in a separate system process + */ + public void setCommand(String command) { + this.command = command; + } + + /** + * @param envp environment parameter values, inherited from parent process + * when not set (or set to null). + */ + public void setEnvironmentParams(String[] envp) { + this.environmentParams = envp; + } + + /** + * @param dir working directory of the spawned process, inherited from + * parent process when not set (or set to null). + */ + public void setWorkingDirectory(String dir) { + if (dir == null) { + this.workingDirectory = null; + return; + } + this.workingDirectory = new File(dir); + Assert.isTrue(workingDirectory.exists(), "working directory must exist"); + Assert.isTrue(workingDirectory.isDirectory(), "working directory value must be a directory"); + + } + + public void afterPropertiesSet() throws Exception { + Assert.hasLength(command, "'command' property value is required"); + Assert.notNull(systemProcessExitCodeMapper, "SystemProcessExitCodeMapper must be set"); + Assert.isTrue(timeout > 0, "timeout value must be greater than zero"); + Assert.notNull(taskExecutor, "taskExecutor is required"); + } + + /** + * @param systemProcessExitCodeMapper maps system process return value to + * ExitStatus returned by Tasklet. + * {@link SimpleSystemProcessExitCodeMapper} is used by default. + */ + public void setSystemProcessExitCodeMapper(SystemProcessExitCodeMapper systemProcessExitCodeMapper) { + this.systemProcessExitCodeMapper = systemProcessExitCodeMapper; + } + + /** + * @param timeout upper limit for how long the execution of the external + * program is allowed to last. + */ + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + /** + * The time interval how often the tasklet will check for termination + * status. + * + * @param checkInterval time interval in milliseconds (1 second by default). + */ + public void setTerminationCheckInterval(long checkInterval) { + this.checkInterval = checkInterval; + } + + /** + * Get a reference to {@link StepExecution} for interrupt checks during + * system command execution. + */ + @Override + public void beforeStep(StepExecution stepExecution) { + this.execution = stepExecution; + } + + /** + * Sets the task executor that will be used to execute the system command + * NB! Avoid using a synchronous task executor + */ + public void setTaskExecutor(TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + } + + /** + * If true tasklet will attempt to interrupt the thread + * executing the system command if {@link #setTimeout(long)} has been + * exceeded or user interrupts the job. false by default + */ + public void setInterruptOnCancel(boolean interruptOnCancel) { + this.interruptOnCancel = interruptOnCancel; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemProcessExitCodeMapper.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemProcessExitCodeMapper.java index be012a5bf..1531aa2ac 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemProcessExitCodeMapper.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemProcessExitCodeMapper.java @@ -1,20 +1,36 @@ -package org.springframework.batch.core.step.tasklet; - -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.step.tasklet.SystemCommandTasklet; - -/** - * Maps the exit code of a system process to ExitStatus value - * returned by a system command. Designed for use with the - * {@link SystemCommandTasklet}. - * - * @author Robert Kasanicky - */ -public interface SystemProcessExitCodeMapper { - - /** - * @param exitCode exit code returned by the system process - * @return ExitStatus appropriate for the systemExitCode parameter value - */ - ExitStatus getExitStatus(int exitCode); -} +/* + * Copyright 2006-2007 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.step.tasklet; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.step.tasklet.SystemCommandTasklet; + +/** + * Maps the exit code of a system process to ExitStatus value + * returned by a system command. Designed for use with the + * {@link SystemCommandTasklet}. + * + * @author Robert Kasanicky + */ +public interface SystemProcessExitCodeMapper { + + /** + * @param exitCode exit code returned by the system process + * @return ExitStatus appropriate for the systemExitCode parameter value + */ + ExitStatus getExitStatus(int exitCode); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemProcessor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemProcessor.java index 168f54ef4..361046a4a 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemProcessor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item; /** diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/DynamicMethodInvocationException.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/DynamicMethodInvocationException.java index 2886c1742..9ca66af1c 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/DynamicMethodInvocationException.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/DynamicMethodInvocationException.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.adapter; import org.springframework.util.MethodInvoker; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java index 42e3791e5..8cacde167 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/KeyCollector.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.database; import java.util.List; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapItemPreparedStatementSetter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapItemPreparedStatementSetter.java index f8334fa40..b4e7148ee 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapItemPreparedStatementSetter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/ColumnMapItemPreparedStatementSetter.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.item.database.support; import java.sql.PreparedStatement; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java index ce8f1c050..681e657a1 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/IbatisKeyCollector.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.database.support; import java.util.List; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileFooterCallback.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileFooterCallback.java index dbe0e4b22..5c5583866 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileFooterCallback.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileFooterCallback.java @@ -1,18 +1,34 @@ -package org.springframework.batch.item.file; - -import java.io.Writer; -import java.io.IOException; - -/** - * Callback interface for writing a footer to a file. - * - * @author Robert Kasanicky - */ -public interface FlatFileFooterCallback { - - /** - * Write contents to a file using the supplied {@link Writer}. It is not - * required to flush the writer inside this method. - */ - void writeFooter(Writer writer) throws IOException; -} +/* + * Copyright 2006-2007 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.item.file; + +import java.io.Writer; +import java.io.IOException; + +/** + * Callback interface for writing a footer to a file. + * + * @author Robert Kasanicky + */ +public interface FlatFileFooterCallback { + + /** + * Write contents to a file using the supplied {@link Writer}. It is not + * required to flush the writer inside this method. + */ + void writeFooter(Writer writer) throws IOException; +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileHeaderCallback.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileHeaderCallback.java index 8c63fe703..b4374cdbf 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileHeaderCallback.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileHeaderCallback.java @@ -1,18 +1,34 @@ -package org.springframework.batch.item.file; - -import java.io.Writer; -import java.io.IOException; - -/** - * Callback interface for writing to a header to a file. - * - * @author Robert Kasanicky - */ -public interface FlatFileHeaderCallback { - - /** - * Write contents to a file using the supplied {@link Writer}. It is not - * required to flush the writer inside this method. - */ - void writeHeader(Writer writer) throws IOException; -} +/* + * Copyright 2006-2007 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.item.file; + +import java.io.Writer; +import java.io.IOException; + +/** + * Callback interface for writing to a header to a file. + * + * @author Robert Kasanicky + */ +public interface FlatFileHeaderCallback { + + /** + * Write contents to a file using the supplied {@link Writer}. It is not + * required to flush the writer inside this method. + */ + void writeHeader(Writer writer) throws IOException; +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java index d47becc8b..b65a135e6 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java @@ -1,227 +1,243 @@ -package org.springframework.batch.item.file; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.Charset; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ReaderNotOpenException; -import org.springframework.batch.item.file.mapping.LineMapper; -import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; -import org.springframework.batch.item.file.separator.SimpleRecordSeparatorPolicy; -import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Restartable {@link ItemReader} that reads lines from input - * {@link #setResource(Resource)}. Line is defined by the - * {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} and mapped to item - * using {@link #setLineMapper(LineMapper)}. - * - * @author Robert Kasanicky - */ -public class FlatFileItemReader extends AbstractItemCountingItemStreamItemReader implements - ResourceAwareItemReaderItemStream, InitializingBean { - - private static final Log logger = LogFactory.getLog(FlatFileItemReader.class); - - // default encoding for input files - public static final String DEFAULT_CHARSET = Charset.defaultCharset().name(); - - private RecordSeparatorPolicy recordSeparatorPolicy = new SimpleRecordSeparatorPolicy(); - - private Resource resource; - - private BufferedReader reader; - - private int lineCount = 0; - - private String[] comments = new String[] { "#" }; - - private boolean noInput = false; - - private String encoding = DEFAULT_CHARSET; - - private LineMapper lineMapper; - - private int linesToSkip = 0; - - private LineCallbackHandler skippedLinesCallback; - - public FlatFileItemReader() { - setName(ClassUtils.getShortName(FlatFileItemReader.class)); - } - - /** - * @param skippedLinesCallback will be called for each one of the initial skipped - * lines before any items are read. - */ - public void setSkippedLinesCallback(LineCallbackHandler skippedLinesCallback) { - this.skippedLinesCallback = skippedLinesCallback; - } - - /** - * Public setter for the number of lines to skip at the start of a file. Can - * be used if the file contains a header without useful (column name) - * information, and without a comment delimiter at the beginning of the - * lines. - * - * @param linesToSkip the number of lines to skip - */ - public void setLinesToSkip(int linesToSkip) { - this.linesToSkip = linesToSkip; - } - - /** - * Setter for line mapper. This property is required to be set. - * @param lineMapper maps line to item - */ - public void setLineMapper(LineMapper lineMapper) { - this.lineMapper = lineMapper; - } - - /** - * Setter for the encoding for this input source. Default value is - * {@link #DEFAULT_CHARSET}. - * - * @param encoding a properties object which possibly contains the encoding - * for this input file; - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Setter for comment prefixes. Can be used to ignore header lines as well - * by using e.g. the first couple of column names as a prefix. - * - * @param comments an array of comment line prefixes. - */ - public void setComments(String[] comments) { - this.comments = new String[comments.length]; - System.arraycopy(comments, 0, this.comments, 0, comments.length); - } - - /** - * Public setter for the input resource. - */ - public void setResource(Resource resource) { - this.resource = resource; - } - - /** - * Public setter for the recordSeparatorPolicy. Used to determine where the - * line endings are and do things like continue over a line ending if inside - * a quoted string. - * - * @param recordSeparatorPolicy the recordSeparatorPolicy to set - */ - public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) { - this.recordSeparatorPolicy = recordSeparatorPolicy; - } - - /** - * @return string corresponding to logical record according to - * {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} (might span - * multiple lines in file). - */ - @Override - protected T doRead() throws Exception { - if (noInput) { - return null; - } - String line = readLine(); - String record = line; - if (line != null) { - while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) { - record = recordSeparatorPolicy.preProcess(record) + (line = readLine()); - } - } - String logicalLine = recordSeparatorPolicy.postProcess(record); - if (logicalLine == null) { - return null; - } - else { - return lineMapper.mapLine(logicalLine, lineCount); - } - } - - /** - * @return next line (skip comments). - */ - private String readLine() { - - if (reader == null) { - throw new ReaderNotOpenException("Reader must be open before it can be read."); - } - - String line = null; - - try { - line = this.reader.readLine(); - if (line == null) { - return null; - } - lineCount++; - while (isComment(line)) { - line = reader.readLine(); - if (line == null) { - return null; - } - lineCount++; - } - } - catch (IOException e) { - throw new FlatFileParseException("Unable to read from resource: [" + resource + "]", e, line, lineCount ); - } - return line; - } - - private boolean isComment(String line) { - for (String prefix : comments) { - if (line.startsWith(prefix)) { - return true; - } - } - return false; - } - - @Override - protected void doClose() throws Exception { - lineCount = 0; - reader.close(); - - } - - @Override - protected void doOpen() throws Exception { - Assert.notNull(resource, "Input resource must be set"); - Assert.notNull(recordSeparatorPolicy, "RecordSeparatorPolicy must be set"); - - noInput = false; - if (!resource.exists()) { - noInput = true; - logger.warn("Input resource does not exist"); - return; - } - - reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding)); - for (int i = 0; i < linesToSkip; i++) { - String line = readLine(); - if (skippedLinesCallback != null) { - skippedLinesCallback.handleLine(line); - } - } - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(lineMapper, "LineMapper is required"); - } - -} +/* + * Copyright 2006-2007 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.item.file; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ReaderNotOpenException; +import org.springframework.batch.item.file.mapping.LineMapper; +import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; +import org.springframework.batch.item.file.separator.SimpleRecordSeparatorPolicy; +import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Restartable {@link ItemReader} that reads lines from input + * {@link #setResource(Resource)}. Line is defined by the + * {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} and mapped to item + * using {@link #setLineMapper(LineMapper)}. + * + * @author Robert Kasanicky + */ +public class FlatFileItemReader extends AbstractItemCountingItemStreamItemReader implements + ResourceAwareItemReaderItemStream, InitializingBean { + + private static final Log logger = LogFactory.getLog(FlatFileItemReader.class); + + // default encoding for input files + public static final String DEFAULT_CHARSET = Charset.defaultCharset().name(); + + private RecordSeparatorPolicy recordSeparatorPolicy = new SimpleRecordSeparatorPolicy(); + + private Resource resource; + + private BufferedReader reader; + + private int lineCount = 0; + + private String[] comments = new String[] { "#" }; + + private boolean noInput = false; + + private String encoding = DEFAULT_CHARSET; + + private LineMapper lineMapper; + + private int linesToSkip = 0; + + private LineCallbackHandler skippedLinesCallback; + + public FlatFileItemReader() { + setName(ClassUtils.getShortName(FlatFileItemReader.class)); + } + + /** + * @param skippedLinesCallback will be called for each one of the initial skipped + * lines before any items are read. + */ + public void setSkippedLinesCallback(LineCallbackHandler skippedLinesCallback) { + this.skippedLinesCallback = skippedLinesCallback; + } + + /** + * Public setter for the number of lines to skip at the start of a file. Can + * be used if the file contains a header without useful (column name) + * information, and without a comment delimiter at the beginning of the + * lines. + * + * @param linesToSkip the number of lines to skip + */ + public void setLinesToSkip(int linesToSkip) { + this.linesToSkip = linesToSkip; + } + + /** + * Setter for line mapper. This property is required to be set. + * @param lineMapper maps line to item + */ + public void setLineMapper(LineMapper lineMapper) { + this.lineMapper = lineMapper; + } + + /** + * Setter for the encoding for this input source. Default value is + * {@link #DEFAULT_CHARSET}. + * + * @param encoding a properties object which possibly contains the encoding + * for this input file; + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Setter for comment prefixes. Can be used to ignore header lines as well + * by using e.g. the first couple of column names as a prefix. + * + * @param comments an array of comment line prefixes. + */ + public void setComments(String[] comments) { + this.comments = new String[comments.length]; + System.arraycopy(comments, 0, this.comments, 0, comments.length); + } + + /** + * Public setter for the input resource. + */ + public void setResource(Resource resource) { + this.resource = resource; + } + + /** + * Public setter for the recordSeparatorPolicy. Used to determine where the + * line endings are and do things like continue over a line ending if inside + * a quoted string. + * + * @param recordSeparatorPolicy the recordSeparatorPolicy to set + */ + public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) { + this.recordSeparatorPolicy = recordSeparatorPolicy; + } + + /** + * @return string corresponding to logical record according to + * {@link #setRecordSeparatorPolicy(RecordSeparatorPolicy)} (might span + * multiple lines in file). + */ + @Override + protected T doRead() throws Exception { + if (noInput) { + return null; + } + String line = readLine(); + String record = line; + if (line != null) { + while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) { + record = recordSeparatorPolicy.preProcess(record) + (line = readLine()); + } + } + String logicalLine = recordSeparatorPolicy.postProcess(record); + if (logicalLine == null) { + return null; + } + else { + return lineMapper.mapLine(logicalLine, lineCount); + } + } + + /** + * @return next line (skip comments). + */ + private String readLine() { + + if (reader == null) { + throw new ReaderNotOpenException("Reader must be open before it can be read."); + } + + String line = null; + + try { + line = this.reader.readLine(); + if (line == null) { + return null; + } + lineCount++; + while (isComment(line)) { + line = reader.readLine(); + if (line == null) { + return null; + } + lineCount++; + } + } + catch (IOException e) { + throw new FlatFileParseException("Unable to read from resource: [" + resource + "]", e, line, lineCount ); + } + return line; + } + + private boolean isComment(String line) { + for (String prefix : comments) { + if (line.startsWith(prefix)) { + return true; + } + } + return false; + } + + @Override + protected void doClose() throws Exception { + lineCount = 0; + reader.close(); + + } + + @Override + protected void doOpen() throws Exception { + Assert.notNull(resource, "Input resource must be set"); + Assert.notNull(recordSeparatorPolicy, "RecordSeparatorPolicy must be set"); + + noInput = false; + if (!resource.exists()) { + noInput = true; + logger.warn("Input resource does not exist"); + return; + } + + reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding)); + for (int i = 0; i < linesToSkip; i++) { + String line = readLine(); + if (skippedLinesCallback != null) { + skippedLinesCallback.handleLine(line); + } + } + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(lineMapper, "LineMapper is required"); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/LineCallbackHandler.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/LineCallbackHandler.java index e1ba89400..1c3e34923 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/LineCallbackHandler.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/LineCallbackHandler.java @@ -1,12 +1,28 @@ -package org.springframework.batch.item.file; - -/** - * Callback interface for handling a line from file. Useful e.g. for header - * processing. - * - * @author Robert Kasanicky - */ -public interface LineCallbackHandler { - - void handleLine(String line); -} +/* + * Copyright 2006-2007 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.item.file; + +/** + * Callback interface for handling a line from file. Useful e.g. for header + * processing. + * + * @author Robert Kasanicky + */ +public interface LineCallbackHandler { + + void handleLine(String line); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java index 2cd8b161c..0d9495356 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java @@ -1,245 +1,261 @@ -package org.springframework.batch.item.file; - -import java.util.Arrays; -import java.util.Comparator; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.NoWorkFoundException; -import org.springframework.batch.item.ParseException; -import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.batch.item.util.ExecutionContextUserSupport; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Reads items from multiple resources sequentially - resource list is given by - * {@link #setResources(Resource[])}, the actual reading is delegated to - * {@link #setDelegate(ResourceAwareItemReaderItemStream)}. - * - * Input resources are ordered using {@link #setComparator(Comparator)} to make - * sure resource ordering is preserved between job runs in restart scenario. - * - * Reset (rollback) capability is implemented by item buffering. - * - * - * @author Robert Kasanicky - */ -public class MultiResourceItemReader implements ItemReader, ItemStream { - - private static final Log logger = LogFactory.getLog(MultiResourceItemReader.class); - - private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport(); - - private ResourceAwareItemReaderItemStream delegate; - - private Resource[] resources; - - private MultiResourceIndex index = new MultiResourceIndex(); - - private boolean saveState = true; - - // signals there are no resources to read -> just return null on first read - private boolean noInput; - - private Comparator comparator = new Comparator() { - - /** - * Compares resource filenames. - */ - public int compare(Resource r1, Resource r2) { - return r1.getFilename().compareTo(r2.getFilename()); - } - - }; - - public MultiResourceItemReader() { - executionContextUserSupport.setName(ClassUtils.getShortName(MultiResourceItemReader.class)); - } - - /** - * Reads the next item, jumping to next resource if necessary. - */ - public T read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException { - - if (noInput) { - return null; - } - - T item; - item = readNextItem(); - index.incrementItemCount(); - - return item; - } - - /** - * Use the delegate to read the next item, jump to next resource if current - * one is exhausted. Items are appended to the buffer. - * @return next item from input - */ - private T readNextItem() throws Exception { - - T item = delegate.read(); - - while (item == null) { - - index.incrementResourceCount(); - - if (index.currentResource >= resources.length) { - return null; - } - - delegate.close(); - delegate.setResource(resources[index.currentResource]); - delegate.open(new ExecutionContext()); - - item = delegate.read(); - } - - return item; - } - - /** - * Close the {@link #setDelegate(ResourceAwareItemReaderItemStream)} reader - * and reset instance variable values. - */ - public void close() throws ItemStreamException { - index = new MultiResourceIndex(); - delegate.close(); - noInput = false; - } - - /** - * Figure out which resource to start with in case of restart, open the - * delegate and restore delegate's position in the resource. - */ - public void open(ExecutionContext executionContext) throws ItemStreamException { - - Assert.notNull(resources, "Resources must be set"); - - noInput = false; - if (resources.length == 0) { - logger.warn("No resources to read"); - noInput = true; - return; - } - - Arrays.sort(resources, comparator); - - index.open(executionContext); - - delegate.setResource(resources[index.currentResource]); - - delegate.open(new ExecutionContext()); - - try { - for (int i = 0; i < index.currentItem; i++) { - delegate.read(); - } - } - catch (Exception e) { - throw new ItemStreamException("Could not restore position on restart", e); - } - } - - /** - * Store the current resource index and position in the resource. - */ - public void update(ExecutionContext executionContext) throws ItemStreamException { - if (saveState) { - index.update(executionContext); - } - } - - /** - * @param delegate reads items from single {@link Resource}. - */ - public void setDelegate(ResourceAwareItemReaderItemStream delegate) { - this.delegate = delegate; - } - - /** - * Set the boolean indicating whether or not state should be saved in the - * provided {@link ExecutionContext} during the {@link ItemStream} call to - * update. - * - * @param saveState - */ - public void setSaveState(boolean saveState) { - this.saveState = saveState; - } - - /** - * @param comparator used to order the injected resources, by default - * compares {@link Resource#getFilename()} values. - */ - public void setComparator(Comparator comparator) { - this.comparator = comparator; - } - - /** - * @param resources input resources - */ - public void setResources(Resource[] resources) { - this.resources = resources; - } - - /** - * Facilitates keeping track of the position within multi-resource input. - */ - private class MultiResourceIndex { - - private static final String RESOURCE_KEY = "resourceIndex"; - - private static final String ITEM_KEY = "itemIndex"; - - private int currentResource = 0; - - private int markedResource = 0; - - private int currentItem = 0; - - private int markedItem = 0; - - public void incrementItemCount() { - currentItem++; - } - - public void incrementResourceCount() { - currentResource++; - currentItem = 0; - } - - public void mark() { - markedResource = currentResource; - markedItem = currentItem; - } - - public void reset() { - currentResource = markedResource; - currentItem = markedItem; - } - - public void open(ExecutionContext ctx) { - if (ctx.containsKey(executionContextUserSupport.getKey(RESOURCE_KEY))) { - currentResource = ctx.getInt(executionContextUserSupport.getKey(RESOURCE_KEY)); - } - - if (ctx.containsKey(executionContextUserSupport.getKey(ITEM_KEY))) { - currentItem = ctx.getInt(executionContextUserSupport.getKey(ITEM_KEY)); - } - } - - public void update(ExecutionContext ctx) { - ctx.putInt(executionContextUserSupport.getKey(RESOURCE_KEY), index.currentResource); - ctx.putInt(executionContextUserSupport.getKey(ITEM_KEY), index.currentItem); - } - } - -} +/* + * Copyright 2006-2007 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.item.file; + +import java.util.Arrays; +import java.util.Comparator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.NoWorkFoundException; +import org.springframework.batch.item.ParseException; +import org.springframework.batch.item.UnexpectedInputException; +import org.springframework.batch.item.util.ExecutionContextUserSupport; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Reads items from multiple resources sequentially - resource list is given by + * {@link #setResources(Resource[])}, the actual reading is delegated to + * {@link #setDelegate(ResourceAwareItemReaderItemStream)}. + * + * Input resources are ordered using {@link #setComparator(Comparator)} to make + * sure resource ordering is preserved between job runs in restart scenario. + * + * Reset (rollback) capability is implemented by item buffering. + * + * + * @author Robert Kasanicky + */ +public class MultiResourceItemReader implements ItemReader, ItemStream { + + private static final Log logger = LogFactory.getLog(MultiResourceItemReader.class); + + private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport(); + + private ResourceAwareItemReaderItemStream delegate; + + private Resource[] resources; + + private MultiResourceIndex index = new MultiResourceIndex(); + + private boolean saveState = true; + + // signals there are no resources to read -> just return null on first read + private boolean noInput; + + private Comparator comparator = new Comparator() { + + /** + * Compares resource filenames. + */ + public int compare(Resource r1, Resource r2) { + return r1.getFilename().compareTo(r2.getFilename()); + } + + }; + + public MultiResourceItemReader() { + executionContextUserSupport.setName(ClassUtils.getShortName(MultiResourceItemReader.class)); + } + + /** + * Reads the next item, jumping to next resource if necessary. + */ + public T read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException { + + if (noInput) { + return null; + } + + T item; + item = readNextItem(); + index.incrementItemCount(); + + return item; + } + + /** + * Use the delegate to read the next item, jump to next resource if current + * one is exhausted. Items are appended to the buffer. + * @return next item from input + */ + private T readNextItem() throws Exception { + + T item = delegate.read(); + + while (item == null) { + + index.incrementResourceCount(); + + if (index.currentResource >= resources.length) { + return null; + } + + delegate.close(); + delegate.setResource(resources[index.currentResource]); + delegate.open(new ExecutionContext()); + + item = delegate.read(); + } + + return item; + } + + /** + * Close the {@link #setDelegate(ResourceAwareItemReaderItemStream)} reader + * and reset instance variable values. + */ + public void close() throws ItemStreamException { + index = new MultiResourceIndex(); + delegate.close(); + noInput = false; + } + + /** + * Figure out which resource to start with in case of restart, open the + * delegate and restore delegate's position in the resource. + */ + public void open(ExecutionContext executionContext) throws ItemStreamException { + + Assert.notNull(resources, "Resources must be set"); + + noInput = false; + if (resources.length == 0) { + logger.warn("No resources to read"); + noInput = true; + return; + } + + Arrays.sort(resources, comparator); + + index.open(executionContext); + + delegate.setResource(resources[index.currentResource]); + + delegate.open(new ExecutionContext()); + + try { + for (int i = 0; i < index.currentItem; i++) { + delegate.read(); + } + } + catch (Exception e) { + throw new ItemStreamException("Could not restore position on restart", e); + } + } + + /** + * Store the current resource index and position in the resource. + */ + public void update(ExecutionContext executionContext) throws ItemStreamException { + if (saveState) { + index.update(executionContext); + } + } + + /** + * @param delegate reads items from single {@link Resource}. + */ + public void setDelegate(ResourceAwareItemReaderItemStream delegate) { + this.delegate = delegate; + } + + /** + * Set the boolean indicating whether or not state should be saved in the + * provided {@link ExecutionContext} during the {@link ItemStream} call to + * update. + * + * @param saveState + */ + public void setSaveState(boolean saveState) { + this.saveState = saveState; + } + + /** + * @param comparator used to order the injected resources, by default + * compares {@link Resource#getFilename()} values. + */ + public void setComparator(Comparator comparator) { + this.comparator = comparator; + } + + /** + * @param resources input resources + */ + public void setResources(Resource[] resources) { + this.resources = resources; + } + + /** + * Facilitates keeping track of the position within multi-resource input. + */ + private class MultiResourceIndex { + + private static final String RESOURCE_KEY = "resourceIndex"; + + private static final String ITEM_KEY = "itemIndex"; + + private int currentResource = 0; + + private int markedResource = 0; + + private int currentItem = 0; + + private int markedItem = 0; + + public void incrementItemCount() { + currentItem++; + } + + public void incrementResourceCount() { + currentResource++; + currentItem = 0; + } + + public void mark() { + markedResource = currentResource; + markedItem = currentItem; + } + + public void reset() { + currentResource = markedResource; + currentItem = markedItem; + } + + public void open(ExecutionContext ctx) { + if (ctx.containsKey(executionContextUserSupport.getKey(RESOURCE_KEY))) { + currentResource = ctx.getInt(executionContextUserSupport.getKey(RESOURCE_KEY)); + } + + if (ctx.containsKey(executionContextUserSupport.getKey(ITEM_KEY))) { + currentItem = ctx.getInt(executionContextUserSupport.getKey(ITEM_KEY)); + } + } + + public void update(ExecutionContext ctx) { + ctx.putInt(executionContextUserSupport.getKey(RESOURCE_KEY), index.currentResource); + ctx.putInt(executionContextUserSupport.getKey(ITEM_KEY), index.currentItem); + } + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java index 0834ab820..b3361ac6b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemWriter.java @@ -1,141 +1,157 @@ -package org.springframework.batch.item.file; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.item.util.ExecutionContextUserSupport; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Wraps a {@link ResourceAwareItemWriterItemStream} and creates a new output - * resource when the count of items written in current resource exceeds - * {@link #setItemCountLimitPerResource(int)}. Suffix creation can be customized - * with {@link #setResourceSuffixCreator(ResourceSuffixCreator)}. - * - * Note that new resources are created only at chunk boundaries i.e. the number - * of items written into one resource is between the limit set by - * {@link #setItemCountLimitPerResource(int)} and (limit + chunk size). - * - * @param item type - * - * @author Robert Kasanicky - */ -public class MultiResourceItemWriter extends ExecutionContextUserSupport implements ItemWriter, ItemStream { - - final static private String RESOURCE_INDEX_KEY = "resource.index"; - - final static private String CURRENT_RESOURCE_ITEM_COUNT = "resource.item.count"; - - private Resource resource; - - private ResourceAwareItemWriterItemStream delegate; - - private int itemCountLimitPerResource = Integer.MAX_VALUE; - - private int currentResourceItemCount = 0; - - private int resourceIndex = 1; - - private ResourceSuffixCreator suffixCreator = new SimpleResourceSuffixCreator(); - - private boolean saveState = true; - - public MultiResourceItemWriter() { - setName(ClassUtils.getShortName(MultiResourceItemWriter.class)); - } - - public void write(List items) throws Exception { - if (currentResourceItemCount >= itemCountLimitPerResource) { - delegate.close(); - resourceIndex++; - currentResourceItemCount = 0; - setResourceToDelegate(); - delegate.open(new ExecutionContext()); - } - delegate.write(items); - currentResourceItemCount += items.size(); - } - - /** - * Allows customization of the suffix of the created resources based on the - * index. - */ - public void setResourceSuffixCreator(ResourceSuffixCreator suffixCreator) { - this.suffixCreator = suffixCreator; - } - - /** - * After this limit is exceeded the next chunk will be written into newly - * created resource. - */ - public void setItemCountLimitPerResource(int itemCountLimitPerResource) { - this.itemCountLimitPerResource = itemCountLimitPerResource; - } - - /** - * Delegate used for actual writing of the output. - */ - public void setDelegate(ResourceAwareItemWriterItemStream delegate) { - this.delegate = delegate; - } - - /** - * Prototype for output resources. Actual output files will be created in - * the same directory and use the same name as this prototype with appended - * suffix (according to - * {@link #setResourceSuffixCreator(ResourceSuffixCreator)}. - */ - public void setResource(Resource resource) { - this.resource = resource; - } - - public void setSaveState(boolean saveState) { - this.saveState = saveState; - } - - public void close() throws ItemStreamException { - resourceIndex = 1; - currentResourceItemCount = 0; - delegate.close(); - } - - public void open(ExecutionContext executionContext) throws ItemStreamException { - resourceIndex = executionContext.getInt(getKey(RESOURCE_INDEX_KEY), 1); - currentResourceItemCount = executionContext.getInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), 0); - - try { - setResourceToDelegate(); - } - catch (IOException e) { - throw new ItemStreamException("Couldn't open resource", e); - } - delegate.open(executionContext); - } - - public void update(ExecutionContext executionContext) throws ItemStreamException { - if (saveState) { - delegate.update(executionContext); - executionContext.putInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), currentResourceItemCount); - executionContext.putInt(getKey(RESOURCE_INDEX_KEY), resourceIndex); - } - } - - /** - * Create output resource (if necessary) and point the delegate to it. - */ - private void setResourceToDelegate() throws IOException { - String path = resource.getFile().getAbsolutePath() + suffixCreator.getSuffix(resourceIndex); - File file = new File(path); - file.createNewFile(); - Assert.state(file.canWrite(), "Output resource " + path + " must be writable"); - delegate.setResource(new FileSystemResource(file)); - } -} +/* + * Copyright 2006-2007 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.item.file; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.util.ExecutionContextUserSupport; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Wraps a {@link ResourceAwareItemWriterItemStream} and creates a new output + * resource when the count of items written in current resource exceeds + * {@link #setItemCountLimitPerResource(int)}. Suffix creation can be customized + * with {@link #setResourceSuffixCreator(ResourceSuffixCreator)}. + * + * Note that new resources are created only at chunk boundaries i.e. the number + * of items written into one resource is between the limit set by + * {@link #setItemCountLimitPerResource(int)} and (limit + chunk size). + * + * @param item type + * + * @author Robert Kasanicky + */ +public class MultiResourceItemWriter extends ExecutionContextUserSupport implements ItemWriter, ItemStream { + + final static private String RESOURCE_INDEX_KEY = "resource.index"; + + final static private String CURRENT_RESOURCE_ITEM_COUNT = "resource.item.count"; + + private Resource resource; + + private ResourceAwareItemWriterItemStream delegate; + + private int itemCountLimitPerResource = Integer.MAX_VALUE; + + private int currentResourceItemCount = 0; + + private int resourceIndex = 1; + + private ResourceSuffixCreator suffixCreator = new SimpleResourceSuffixCreator(); + + private boolean saveState = true; + + public MultiResourceItemWriter() { + setName(ClassUtils.getShortName(MultiResourceItemWriter.class)); + } + + public void write(List items) throws Exception { + if (currentResourceItemCount >= itemCountLimitPerResource) { + delegate.close(); + resourceIndex++; + currentResourceItemCount = 0; + setResourceToDelegate(); + delegate.open(new ExecutionContext()); + } + delegate.write(items); + currentResourceItemCount += items.size(); + } + + /** + * Allows customization of the suffix of the created resources based on the + * index. + */ + public void setResourceSuffixCreator(ResourceSuffixCreator suffixCreator) { + this.suffixCreator = suffixCreator; + } + + /** + * After this limit is exceeded the next chunk will be written into newly + * created resource. + */ + public void setItemCountLimitPerResource(int itemCountLimitPerResource) { + this.itemCountLimitPerResource = itemCountLimitPerResource; + } + + /** + * Delegate used for actual writing of the output. + */ + public void setDelegate(ResourceAwareItemWriterItemStream delegate) { + this.delegate = delegate; + } + + /** + * Prototype for output resources. Actual output files will be created in + * the same directory and use the same name as this prototype with appended + * suffix (according to + * {@link #setResourceSuffixCreator(ResourceSuffixCreator)}. + */ + public void setResource(Resource resource) { + this.resource = resource; + } + + public void setSaveState(boolean saveState) { + this.saveState = saveState; + } + + public void close() throws ItemStreamException { + resourceIndex = 1; + currentResourceItemCount = 0; + delegate.close(); + } + + public void open(ExecutionContext executionContext) throws ItemStreamException { + resourceIndex = executionContext.getInt(getKey(RESOURCE_INDEX_KEY), 1); + currentResourceItemCount = executionContext.getInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), 0); + + try { + setResourceToDelegate(); + } + catch (IOException e) { + throw new ItemStreamException("Couldn't open resource", e); + } + delegate.open(executionContext); + } + + public void update(ExecutionContext executionContext) throws ItemStreamException { + if (saveState) { + delegate.update(executionContext); + executionContext.putInt(getKey(CURRENT_RESOURCE_ITEM_COUNT), currentResourceItemCount); + executionContext.putInt(getKey(RESOURCE_INDEX_KEY), resourceIndex); + } + } + + /** + * Create output resource (if necessary) and point the delegate to it. + */ + private void setResourceToDelegate() throws IOException { + String path = resource.getFile().getAbsolutePath() + suffixCreator.getSuffix(resourceIndex); + File file = new File(path); + file.createNewFile(); + Assert.state(file.canWrite(), "Output resource " + path + " must be writable"); + delegate.setResource(new FileSystemResource(file)); + } +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemReaderItemStream.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemReaderItemStream.java index b57c4638c..aa1229a2f 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemReaderItemStream.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemReaderItemStream.java @@ -1,16 +1,32 @@ -package org.springframework.batch.item.file; - -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemStream; -import org.springframework.core.io.Resource; - -/** - * Interface for {@link ItemReader}s that implement {@link ItemStream} and read - * input from {@link Resource}. - * - * @author Robert Kasanicky - */ -public interface ResourceAwareItemReaderItemStream extends ItemReader, ItemStream { - - void setResource(Resource resource); -} +/* + * Copyright 2006-2007 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.item.file; + +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemStream; +import org.springframework.core.io.Resource; + +/** + * Interface for {@link ItemReader}s that implement {@link ItemStream} and read + * input from {@link Resource}. + * + * @author Robert Kasanicky + */ +public interface ResourceAwareItemReaderItemStream extends ItemReader, ItemStream { + + void setResource(Resource resource); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemWriterItemStream.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemWriterItemStream.java index 5f37c2237..91be8a6e4 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemWriterItemStream.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceAwareItemWriterItemStream.java @@ -1,16 +1,32 @@ -package org.springframework.batch.item.file; - -import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ItemWriter; -import org.springframework.core.io.Resource; - -/** - * Interface for {@link ItemWriter}s that implement {@link ItemStream} and write - * output to {@link Resource}. - * - * @author Robert Kasanicky - */ -public interface ResourceAwareItemWriterItemStream extends ItemStream, ItemWriter { - - void setResource(Resource resource); -} +/* + * Copyright 2006-2007 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.item.file; + +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.ItemWriter; +import org.springframework.core.io.Resource; + +/** + * Interface for {@link ItemWriter}s that implement {@link ItemStream} and write + * output to {@link Resource}. + * + * @author Robert Kasanicky + */ +public interface ResourceAwareItemWriterItemStream extends ItemStream, ItemWriter { + + void setResource(Resource resource); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceSuffixCreator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceSuffixCreator.java index bdfa806f1..97f01ad85 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceSuffixCreator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/ResourceSuffixCreator.java @@ -1,15 +1,31 @@ -package org.springframework.batch.item.file; - -/** - * Strategy interface for translating resource index into unique filename - * suffix. - * - * @see MultiResourceItemWriter - * @see SimpleResourceSuffixCreator - * - * @author Robert Kasanicky - */ -public interface ResourceSuffixCreator { - - String getSuffix(int index); -} +/* + * Copyright 2006-2007 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.item.file; + +/** + * Strategy interface for translating resource index into unique filename + * suffix. + * + * @see MultiResourceItemWriter + * @see SimpleResourceSuffixCreator + * + * @author Robert Kasanicky + */ +public interface ResourceSuffixCreator { + + String getSuffix(int index); +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleResourceSuffixCreator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleResourceSuffixCreator.java index 3b1b36237..aeb58d1d1 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleResourceSuffixCreator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/SimpleResourceSuffixCreator.java @@ -1,15 +1,31 @@ -package org.springframework.batch.item.file; - -/** - * Trivial implementation of {@link ResourceSuffixCreator} that uses the index - * itself as suffix, separated by dot. - * - * @author Robert Kasanicky - */ -public class SimpleResourceSuffixCreator implements ResourceSuffixCreator { - - public String getSuffix(int index) { - return "." + index; - } - -} +/* + * Copyright 2006-2007 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.item.file; + +/** + * Trivial implementation of {@link ResourceSuffixCreator} that uses the index + * itself as suffix, separated by dot. + * + * @author Robert Kasanicky + */ +public class SimpleResourceSuffixCreator implements ResourceSuffixCreator { + + public String getSuffix(int index) { + return "." + index; + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/DefaultLineMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/DefaultLineMapper.java index fa6ce2c1f..daedfc5d5 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/DefaultLineMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/DefaultLineMapper.java @@ -1,39 +1,55 @@ -package org.springframework.batch.item.file.mapping; - -import org.springframework.batch.item.file.transform.FieldSet; -import org.springframework.batch.item.file.transform.LineTokenizer; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - -/** - * Two-phase {@link LineMapper} implementation consisting of tokenization of the - * line into {@link FieldSet} followed by mapping to item. - * - * @author Robert Kasanicky - * - * @param type of the item - */ -public class DefaultLineMapper implements LineMapper, InitializingBean { - - private LineTokenizer tokenizer; - - private FieldSetMapper fieldSetMapper; - - public T mapLine(String line, int lineNumber) throws Exception { - return fieldSetMapper.mapFieldSet(tokenizer.tokenize(line)); - } - - public void setLineTokenizer(LineTokenizer tokenizer) { - this.tokenizer = tokenizer; - } - - public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { - this.fieldSetMapper = fieldSetMapper; - } - - public void afterPropertiesSet() { - Assert.notNull(tokenizer, "The LineTokenizer must be set"); - Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set"); - } - -} +/* + * Copyright 2006-2007 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.item.file.mapping; + +import org.springframework.batch.item.file.transform.FieldSet; +import org.springframework.batch.item.file.transform.LineTokenizer; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; + +/** + * Two-phase {@link LineMapper} implementation consisting of tokenization of the + * line into {@link FieldSet} followed by mapping to item. + * + * @author Robert Kasanicky + * + * @param type of the item + */ +public class DefaultLineMapper implements LineMapper, InitializingBean { + + private LineTokenizer tokenizer; + + private FieldSetMapper fieldSetMapper; + + public T mapLine(String line, int lineNumber) throws Exception { + return fieldSetMapper.mapFieldSet(tokenizer.tokenize(line)); + } + + public void setLineTokenizer(LineTokenizer tokenizer) { + this.tokenizer = tokenizer; + } + + public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { + this.fieldSetMapper = fieldSetMapper; + } + + public void afterPropertiesSet() { + Assert.notNull(tokenizer, "The LineTokenizer must be set"); + Assert.notNull(fieldSetMapper, "The FieldSetMapper must be set"); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/LineMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/LineMapper.java index 06177c469..30455720a 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/LineMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/LineMapper.java @@ -1,31 +1,47 @@ -package org.springframework.batch.item.file.mapping; - -import org.springframework.batch.item.file.transform.LineTokenizer; - - -/** - * Interface for mapping lines (strings) to domain objects typically used to map lines read from a file to domain objects - * on a per line basis. Implementations of this interface perform the actual - * work of parsing a line without having to deal with how the line was - * obtained. - * - * @author Robert Kasanicky - * @param type of the domain object - * @see FieldSetMapper - * @see LineTokenizer - * @since 2.0 - */ -public interface LineMapper { - - /** - * Implementations must implement this method to map the provided line to - * the parameter type T. The line number represents the number of lines - * into a file the current line resides. - * - * @param line to be mapped - * @param lineNumber of the current line - * @return mapped object of type T - * @throws Exception if error occured while parsing. - */ - T mapLine(String line, int lineNumber) throws Exception; -} +/* + * Copyright 2006-2007 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.item.file.mapping; + +import org.springframework.batch.item.file.transform.LineTokenizer; + + +/** + * Interface for mapping lines (strings) to domain objects typically used to map lines read from a file to domain objects + * on a per line basis. Implementations of this interface perform the actual + * work of parsing a line without having to deal with how the line was + * obtained. + * + * @author Robert Kasanicky + * @param type of the domain object + * @see FieldSetMapper + * @see LineTokenizer + * @since 2.0 + */ +public interface LineMapper { + + /** + * Implementations must implement this method to map the provided line to + * the parameter type T. The line number represents the number of lines + * into a file the current line resides. + * + * @param line to be mapped + * @param lineNumber of the current line + * @return mapped object of type T + * @throws Exception if error occured while parsing. + */ + T mapLine(String line, int lineNumber) throws Exception; +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PassThroughLineMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PassThroughLineMapper.java index 03b6e355e..bc5698efe 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PassThroughLineMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PassThroughLineMapper.java @@ -1,9 +1,25 @@ -package org.springframework.batch.item.file.mapping; - -public class PassThroughLineMapper implements LineMapper{ - - public String mapLine(String line, int lineNumber) throws Exception { - return line; - } - -} +/* + * Copyright 2006-2007 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.item.file.mapping; + +public class PassThroughLineMapper implements LineMapper{ + + public String mapLine(String line, int lineNumber) throws Exception { + return line; + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PassThroughLineAggregator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PassThroughLineAggregator.java index dffb2fb62..e88adda30 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PassThroughLineAggregator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PassThroughLineAggregator.java @@ -1,15 +1,31 @@ -package org.springframework.batch.item.file.transform; - - -public class PassThroughLineAggregator implements LineAggregator { - - /** - * Simply convert to a String with toString(). - * - * @see org.springframework.batch.item.file.transform.LineAggregator#aggregate(java.lang.Object) - */ - public String aggregate(T item) { - return item.toString(); - } - -} +/* + * Copyright 2006-2007 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.item.file.transform; + + +public class PassThroughLineAggregator implements LineAggregator { + + /** + * Simply convert to a String with toString(). + * + * @see org.springframework.batch.item.file.transform.LineAggregator#aggregate(java.lang.Object) + */ + public String aggregate(T item) { + return item.toString(); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/Range.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/Range.java index cd13489dd..3f53d47f4 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/Range.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/Range.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.file.transform; import org.springframework.util.Assert; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RangeArrayPropertyEditor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RangeArrayPropertyEditor.java index 6ece783ba..30a0b51ee 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RangeArrayPropertyEditor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RangeArrayPropertyEditor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.file.transform; import java.beans.PropertyEditorSupport; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RecursiveCollectionLineAggregator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RecursiveCollectionLineAggregator.java index 1d5cef1c7..6a5e7760d 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RecursiveCollectionLineAggregator.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/RecursiveCollectionLineAggregator.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.file.transform; import java.util.Collection; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java index 952a1b5b3..4b0384ccd 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java @@ -1,129 +1,145 @@ -package org.springframework.batch.item.support; - -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.ParseException; -import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.batch.item.util.ExecutionContextUserSupport; -import org.springframework.util.Assert; - -/** - * Abstract superclass for {@link ItemReader}s that supports restart by storing - * item count in the {@link ExecutionContext} (therefore requires item ordering - * to be preserved between runs). - * - * Subclasses are inherently *not* thread-safe. - * - * @author Robert Kasanicky - */ -public abstract class AbstractItemCountingItemStreamItemReader implements ItemReader, ItemStream { - - private static final String READ_COUNT = "read.count"; - - private int currentItemCount = 0; - - private ExecutionContextUserSupport ecSupport = new ExecutionContextUserSupport(); - - private boolean saveState = true; - - /** - * Read next item from input. - * @return item - * @throws Exception - */ - protected abstract T doRead() throws Exception; - - /** - * Open resources necessary to start reading input. - */ - protected abstract void doOpen() throws Exception; - - /** - * Close the resources opened in {@link #doOpen()}. - */ - protected abstract void doClose() throws Exception; - - /** - * Move to the given item index. Subclasses should override this method if - * there is a more efficient way of moving to given index than re-reading - * the input using {@link #doRead()}. - */ - protected void jumpToItem(int itemIndex) throws Exception { - for (int i = 0; i < itemIndex; i++) { - doRead(); - } - } - - public T read() throws Exception, UnexpectedInputException, ParseException { - currentItemCount++; - return doRead(); - } - - protected int getCurrentItemCount() { - return currentItemCount; - } - - protected void setCurrentItemCount(int count) { - this.currentItemCount = count; - } - - public void close() throws ItemStreamException { - currentItemCount = 0; - try { - doClose(); - } - catch (Exception e) { - throw new ItemStreamException("Error while closing item reader", e); - } - } - - public void open(ExecutionContext executionContext) throws ItemStreamException { - - try { - doOpen(); - } - catch (Exception e) { - throw new ItemStreamException("Failed to initialize the reader", e); - } - - if (executionContext.containsKey(ecSupport.getKey(READ_COUNT))) { - int itemCount = executionContext.getInt(ecSupport.getKey(READ_COUNT)); - - try { - jumpToItem(itemCount); - } - catch (Exception e) { - throw new ItemStreamException("Could not move to stored position on restart", e); - } - - currentItemCount = itemCount; - } - - } - - public void update(ExecutionContext executionContext) throws ItemStreamException { - if (saveState) { - Assert.notNull(executionContext, "ExecutionContext must not be null"); - executionContext.putInt(ecSupport.getKey(READ_COUNT), currentItemCount); - } - - } - - public void setName(String name) { - ecSupport.setName(name); - } - - /** - * Set the flag that determines whether to save internal data for - * {@link ExecutionContext}. Only switch this to false if you don't want to - * save any state from this stream, and you don't need it to be restartable. - * - * @param saveState flag value (default true). - */ - public void setSaveState(boolean saveState) { - this.saveState = saveState; - } - -} +/* + * Copyright 2006-2007 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.item.support; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.ParseException; +import org.springframework.batch.item.UnexpectedInputException; +import org.springframework.batch.item.util.ExecutionContextUserSupport; +import org.springframework.util.Assert; + +/** + * Abstract superclass for {@link ItemReader}s that supports restart by storing + * item count in the {@link ExecutionContext} (therefore requires item ordering + * to be preserved between runs). + * + * Subclasses are inherently *not* thread-safe. + * + * @author Robert Kasanicky + */ +public abstract class AbstractItemCountingItemStreamItemReader implements ItemReader, ItemStream { + + private static final String READ_COUNT = "read.count"; + + private int currentItemCount = 0; + + private ExecutionContextUserSupport ecSupport = new ExecutionContextUserSupport(); + + private boolean saveState = true; + + /** + * Read next item from input. + * @return item + * @throws Exception + */ + protected abstract T doRead() throws Exception; + + /** + * Open resources necessary to start reading input. + */ + protected abstract void doOpen() throws Exception; + + /** + * Close the resources opened in {@link #doOpen()}. + */ + protected abstract void doClose() throws Exception; + + /** + * Move to the given item index. Subclasses should override this method if + * there is a more efficient way of moving to given index than re-reading + * the input using {@link #doRead()}. + */ + protected void jumpToItem(int itemIndex) throws Exception { + for (int i = 0; i < itemIndex; i++) { + doRead(); + } + } + + public T read() throws Exception, UnexpectedInputException, ParseException { + currentItemCount++; + return doRead(); + } + + protected int getCurrentItemCount() { + return currentItemCount; + } + + protected void setCurrentItemCount(int count) { + this.currentItemCount = count; + } + + public void close() throws ItemStreamException { + currentItemCount = 0; + try { + doClose(); + } + catch (Exception e) { + throw new ItemStreamException("Error while closing item reader", e); + } + } + + public void open(ExecutionContext executionContext) throws ItemStreamException { + + try { + doOpen(); + } + catch (Exception e) { + throw new ItemStreamException("Failed to initialize the reader", e); + } + + if (executionContext.containsKey(ecSupport.getKey(READ_COUNT))) { + int itemCount = executionContext.getInt(ecSupport.getKey(READ_COUNT)); + + try { + jumpToItem(itemCount); + } + catch (Exception e) { + throw new ItemStreamException("Could not move to stored position on restart", e); + } + + currentItemCount = itemCount; + } + + } + + public void update(ExecutionContext executionContext) throws ItemStreamException { + if (saveState) { + Assert.notNull(executionContext, "ExecutionContext must not be null"); + executionContext.putInt(ecSupport.getKey(READ_COUNT), currentItemCount); + } + + } + + public void setName(String name) { + ecSupport.setName(name); + } + + /** + * Set the flag that determines whether to save internal data for + * {@link ExecutionContext}. Only switch this to false if you don't want to + * save any state from this stream, and you don't need it to be restartable. + * + * @param saveState flag value (default true). + */ + public void setSaveState(boolean saveState) { + this.saveState = saveState; + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java index 92ef3af07..076bd330b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.support; import java.util.List; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java index b66912b87..d1bb73f7b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.support; import java.util.Arrays; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/PassthroughItemProcessor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/PassthroughItemProcessor.java index 19d76c72e..e38afcd62 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/PassthroughItemProcessor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/PassthroughItemProcessor.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.support; import org.springframework.batch.item.ItemProcessor; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/util/FileUtils.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/util/FileUtils.java index 9932e6cae..26c48b845 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/util/FileUtils.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/util/FileUtils.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.util; import java.io.File; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/validator/ValidatingItemProcessor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/validator/ValidatingItemProcessor.java index cea6e86a9..dc1e8fa67 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/validator/ValidatingItemProcessor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/validator/ValidatingItemProcessor.java @@ -1,42 +1,58 @@ -package org.springframework.batch.item.validator; - -import org.springframework.batch.item.ItemProcessor; -import org.springframework.util.Assert; - -/** - * Simple implementation of {@link ItemProcessor} validates and input and - * returns it without modifications. - * - * @author Robert Kasanicky - * - */ -public class ValidatingItemProcessor implements ItemProcessor { - - private Validator validator; - - public ValidatingItemProcessor(Validator validator){ - Assert.notNull(validator, "Validator must not be null."); - this.validator = validator; - } - - /** - * Set the validator used to validate each item. - * - * @param validator - */ - public void setValidator(Validator validator) { - this.validator = validator; - } - - /** - * Validate the item and return it unmodified - * - * @return the input item - * @throws ValidationException if validation fails - */ - public T process(T item) throws ValidationException { - validator.validate(item); - return item; - } - -} +/* + * Copyright 2006-2007 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.item.validator; + +import org.springframework.batch.item.ItemProcessor; +import org.springframework.util.Assert; + +/** + * Simple implementation of {@link ItemProcessor} validates and input and + * returns it without modifications. + * + * @author Robert Kasanicky + * + */ +public class ValidatingItemProcessor implements ItemProcessor { + + private Validator validator; + + public ValidatingItemProcessor(Validator validator){ + Assert.notNull(validator, "Validator must not be null."); + this.validator = validator; + } + + /** + * Set the validator used to validate each item. + * + * @param validator + */ + public void setValidator(Validator validator) { + this.validator = validator; + } + + /** + * Validate the item and return it unmodified + * + * @return the input item + * @throws ValidationException if validation fails + */ + public T process(T item) throws ValidationException { + validator.validate(item); + return item; + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java index cf7f48292..7c49830be 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml; import java.io.InputStream; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java index 4f68990cc..3fa405145 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml; import java.io.File; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxWriterCallback.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxWriterCallback.java index 6b6065b63..496e5a057 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxWriterCallback.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxWriterCallback.java @@ -1,20 +1,36 @@ -package org.springframework.batch.item.xml; - -import java.io.IOException; - -import javax.xml.stream.XMLEventWriter; - -/** - * Callback interface for writing to an XML file - useful e.g. for handling headers - * and footers. - * - * @author Robert Kasanicky - */ -public interface StaxWriterCallback { - - /** - * Write contents using the supplied {@link XMLEventWriter}. It is not - * required to flush the writer inside this method. - */ - void write(XMLEventWriter writer) throws IOException; -} +/* + * Copyright 2006-2007 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.item.xml; + +import java.io.IOException; + +import javax.xml.stream.XMLEventWriter; + +/** + * Callback interface for writing to an XML file - useful e.g. for handling headers + * and footers. + * + * @author Robert Kasanicky + */ +public interface StaxWriterCallback { + + /** + * Write contents using the supplied {@link XMLEventWriter}. It is not + * required to flush the writer inside this method. + */ + void write(XMLEventWriter writer) throws IOException; +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventReaderWrapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventReaderWrapper.java index 4eb3b6eee..12ff67fa2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventReaderWrapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventReaderWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml.stax; import javax.xml.stream.XMLEventReader; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventWriterWrapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventWriterWrapper.java index 18a40c616..98d988c5b 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventWriterWrapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/AbstractEventWriterWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml.stax; import javax.xml.namespace.NamespaceContext; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReader.java index 698ac3275..313f287ae 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReader.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml.stax; import java.util.NoSuchElementException; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/FragmentEventReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/FragmentEventReader.java index 414d64cdf..030bc99a8 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/FragmentEventReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/FragmentEventReader.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml.stax; import javax.xml.stream.XMLEventReader; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/NoStartEndDocumentStreamWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/NoStartEndDocumentStreamWriter.java index 80353b8e8..049ac74d2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/NoStartEndDocumentStreamWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/stax/NoStartEndDocumentStreamWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.item.xml.stax; import javax.xml.stream.XMLEventWriter; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/RepeatStatus.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/RepeatStatus.java index 9fea44380..8ccc705f2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/RepeatStatus.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/RepeatStatus.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repeat; public enum RepeatStatus { diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/support/ResultHolder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/support/ResultHolder.java index 413717394..7321f4076 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/support/ResultHolder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/support/ResultHolder.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.repeat.support; import org.springframework.batch.repeat.RepeatStatus; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java index 8b3f0f887..419ae17af 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/DatabaseType.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.support; import java.util.HashMap; diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/AsynchronousFailureException.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/AsynchronousFailureException.java index e56ef64dc..a3c49628f 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/AsynchronousFailureException.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/AsynchronousFailureException.java @@ -1,37 +1,53 @@ -package org.springframework.batch.integration.chunk; - -import org.springframework.batch.item.ItemWriterException; - -/** - * Exception indicating that a failure or early completion condition was - * detected in a remote worker. - * - * @author Dave Syer - * - */ -public class AsynchronousFailureException extends ItemWriterException { - - /** - * Create a new {@link AsynchronousFailureException} based on a message and - * another exception. - * - * @param message - * the message for this exception - * @param cause - * the other exception - */ - public AsynchronousFailureException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Create a new {@link AsynchronousFailureException} based on a message. - * - * @param message - * the message for this exception - */ - public AsynchronousFailureException(String message) { - super(message); - } - -} +/* + * Copyright 2006-2007 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.integration.chunk; + +import org.springframework.batch.item.ItemWriterException; + +/** + * Exception indicating that a failure or early completion condition was + * detected in a remote worker. + * + * @author Dave Syer + * + */ +public class AsynchronousFailureException extends ItemWriterException { + + /** + * Create a new {@link AsynchronousFailureException} based on a message and + * another exception. + * + * @param message + * the message for this exception + * @param cause + * the other exception + */ + public AsynchronousFailureException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Create a new {@link AsynchronousFailureException} based on a message. + * + * @param message + * the message for this exception + */ + public AsynchronousFailureException(String message) { + super(message); + } + +} diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkHandler.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkHandler.java index b771a7aba..9eddc4e39 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkHandler.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkHandler.java @@ -1,7 +1,23 @@ -package org.springframework.batch.integration.chunk; - -public interface ChunkHandler { - - ChunkResponse handleChunk(ChunkRequest chunk); - +/* + * Copyright 2006-2007 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.integration.chunk; + +public interface ChunkHandler { + + ChunkResponse handleChunk(ChunkRequest chunk); + } \ No newline at end of file diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkMessageChannelItemWriter.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkMessageChannelItemWriter.java index bcc73f0fb..2d56277b3 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkMessageChannelItemWriter.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkMessageChannelItemWriter.java @@ -1,179 +1,195 @@ -package org.springframework.batch.integration.chunk; - -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.BatchStatus; -import org.springframework.batch.core.ExitStatus; -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.listener.StepExecutionListenerSupport; -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.ItemStream; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.ItemWriter; -import org.springframework.integration.gateway.MessagingGateway; -import org.springframework.util.Assert; - -public class ChunkMessageChannelItemWriter extends StepExecutionListenerSupport implements ItemWriter, ItemStream { - - private static final Log logger = LogFactory.getLog(ChunkMessageChannelItemWriter.class); - - static final String ACTUAL = ChunkMessageChannelItemWriter.class.getName() + ".ACTUAL"; - - static final String EXPECTED = ChunkMessageChannelItemWriter.class.getName() + ".EXPECTED"; - - private static final long DEFAULT_THROTTLE_LIMIT = 6; - - private MessagingGateway messagingGateway; - - private LocalState localState = new LocalState(); - - private long throttleLimit = DEFAULT_THROTTLE_LIMIT; - - /** - * Public setter for the throttle limit. This limits the number of pending - * requests for chunk processing to avoid overwhelming the receivers. - * @param throttleLimit the throttle limit to set - */ - public void setThrottleLimit(long throttleLimit) { - this.throttleLimit = throttleLimit; - } - - public void setMessagingGateway(MessagingGateway messagingGateway) { - this.messagingGateway = messagingGateway; - } - - public void write(List items) throws Exception { - - // Block until expecting <= throttle limit - while (localState.getExpecting() > throttleLimit) { - getNextResult(); - } - - if (!items.isEmpty()) { - - logger.debug("Dispatching chunk: " + items); - ChunkRequest request = new ChunkRequest(items, localState.getJobId(), localState - .createStepContribution()); - messagingGateway.send(request); - localState.expected++; - - } - - } - - @Override - public void beforeStep(StepExecution stepExecution) { - localState.setStepExecution(stepExecution); - } - - @Override - public ExitStatus afterStep(StepExecution stepExecution) { - if (!(stepExecution.getStatus() == BatchStatus.COMPLETED)) { - return ExitStatus.EXECUTING; - } - long expecting = localState.getExpecting(); - boolean timedOut; - try { - logger.debug("Waiting for results in step listener..."); - timedOut = !waitForResults(); - logger.debug("Finished waiting for results in step listener."); - } - catch (RuntimeException e) { - logger.debug("Detected failure waiting for results in step listener.", e); - stepExecution.setStatus(BatchStatus.FAILED); - return ExitStatus.FAILED.addExitDescription(e.getClass().getName() + ": " + e.getMessage()); - } - if (timedOut) { - stepExecution.setStatus(BatchStatus.FAILED); - throw new ItemStreamException("Timed out waiting for back log at end of step"); - } - return ExitStatus.FINISHED.addExitDescription("Waited for " + expecting + " results."); - } - - public void close() throws ItemStreamException { - localState.reset(); - } - - public void open(ExecutionContext executionContext) throws ItemStreamException { - if (executionContext.containsKey(EXPECTED)) { - localState.expected = executionContext.getLong(EXPECTED); - localState.actual = executionContext.getLong(ACTUAL); - if (!waitForResults()) { - throw new ItemStreamException("Timed out waiting for back log on open"); - } - } - } - - public void update(ExecutionContext executionContext) throws ItemStreamException { - executionContext.putLong(EXPECTED, localState.expected); - executionContext.putLong(ACTUAL, localState.actual); - } - - /** - * Wait until all the results that are in the pipeline come back to the - * reply channel. - * - * @return true if successfully received a result, false if timed out - */ - private boolean waitForResults() { - // TODO: cumulative timeout, or throw an exception? - int count = 0; - int maxCount = 40; - while (localState.getExpecting() > 0 && count++ < maxCount) { - getNextResult(); - } - return count < maxCount; - } - - /** - * Get the next result if it is available within the timeout specified, - * otherwise return null. - */ - private void getNextResult() { - ChunkResponse payload = (ChunkResponse) messagingGateway.receive(); - if (payload != null) { - Long jobInstanceId = payload.getJobId(); - Assert.state(jobInstanceId != null, "Message did not contain job instance id."); - Assert.state(jobInstanceId.equals(localState.getJobId()), "Message contained wrong job instance id [" - + jobInstanceId + "] should have been [" + localState.getJobId() + "]."); - localState.actual++; - // TODO: apply the skip count - if (!payload.isSuccessful()) { - throw new AsynchronousFailureException("Failure or interrupt detected in handler: " - + payload.getMessage()); - } - } - } - - private static class LocalState { - private long actual; - - private long expected; - - private StepExecution stepExecution; - - public long getExpecting() { - return expected - actual; - } - - public StepContribution createStepContribution() { - return stepExecution.createStepContribution(); - } - - public Long getJobId() { - return stepExecution.getJobExecution().getJobId(); - } - - public void setStepExecution(StepExecution stepExecution) { - this.stepExecution = stepExecution; - } - - public void reset() { - expected = actual = 0; - } - } - -} +/* + * Copyright 2006-2007 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.integration.chunk; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.listener.StepExecutionListenerSupport; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStream; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.ItemWriter; +import org.springframework.integration.gateway.MessagingGateway; +import org.springframework.util.Assert; + +public class ChunkMessageChannelItemWriter extends StepExecutionListenerSupport implements ItemWriter, ItemStream { + + private static final Log logger = LogFactory.getLog(ChunkMessageChannelItemWriter.class); + + static final String ACTUAL = ChunkMessageChannelItemWriter.class.getName() + ".ACTUAL"; + + static final String EXPECTED = ChunkMessageChannelItemWriter.class.getName() + ".EXPECTED"; + + private static final long DEFAULT_THROTTLE_LIMIT = 6; + + private MessagingGateway messagingGateway; + + private LocalState localState = new LocalState(); + + private long throttleLimit = DEFAULT_THROTTLE_LIMIT; + + /** + * Public setter for the throttle limit. This limits the number of pending + * requests for chunk processing to avoid overwhelming the receivers. + * @param throttleLimit the throttle limit to set + */ + public void setThrottleLimit(long throttleLimit) { + this.throttleLimit = throttleLimit; + } + + public void setMessagingGateway(MessagingGateway messagingGateway) { + this.messagingGateway = messagingGateway; + } + + public void write(List items) throws Exception { + + // Block until expecting <= throttle limit + while (localState.getExpecting() > throttleLimit) { + getNextResult(); + } + + if (!items.isEmpty()) { + + logger.debug("Dispatching chunk: " + items); + ChunkRequest request = new ChunkRequest(items, localState.getJobId(), localState + .createStepContribution()); + messagingGateway.send(request); + localState.expected++; + + } + + } + + @Override + public void beforeStep(StepExecution stepExecution) { + localState.setStepExecution(stepExecution); + } + + @Override + public ExitStatus afterStep(StepExecution stepExecution) { + if (!(stepExecution.getStatus() == BatchStatus.COMPLETED)) { + return ExitStatus.EXECUTING; + } + long expecting = localState.getExpecting(); + boolean timedOut; + try { + logger.debug("Waiting for results in step listener..."); + timedOut = !waitForResults(); + logger.debug("Finished waiting for results in step listener."); + } + catch (RuntimeException e) { + logger.debug("Detected failure waiting for results in step listener.", e); + stepExecution.setStatus(BatchStatus.FAILED); + return ExitStatus.FAILED.addExitDescription(e.getClass().getName() + ": " + e.getMessage()); + } + if (timedOut) { + stepExecution.setStatus(BatchStatus.FAILED); + throw new ItemStreamException("Timed out waiting for back log at end of step"); + } + return ExitStatus.FINISHED.addExitDescription("Waited for " + expecting + " results."); + } + + public void close() throws ItemStreamException { + localState.reset(); + } + + public void open(ExecutionContext executionContext) throws ItemStreamException { + if (executionContext.containsKey(EXPECTED)) { + localState.expected = executionContext.getLong(EXPECTED); + localState.actual = executionContext.getLong(ACTUAL); + if (!waitForResults()) { + throw new ItemStreamException("Timed out waiting for back log on open"); + } + } + } + + public void update(ExecutionContext executionContext) throws ItemStreamException { + executionContext.putLong(EXPECTED, localState.expected); + executionContext.putLong(ACTUAL, localState.actual); + } + + /** + * Wait until all the results that are in the pipeline come back to the + * reply channel. + * + * @return true if successfully received a result, false if timed out + */ + private boolean waitForResults() { + // TODO: cumulative timeout, or throw an exception? + int count = 0; + int maxCount = 40; + while (localState.getExpecting() > 0 && count++ < maxCount) { + getNextResult(); + } + return count < maxCount; + } + + /** + * Get the next result if it is available within the timeout specified, + * otherwise return null. + */ + private void getNextResult() { + ChunkResponse payload = (ChunkResponse) messagingGateway.receive(); + if (payload != null) { + Long jobInstanceId = payload.getJobId(); + Assert.state(jobInstanceId != null, "Message did not contain job instance id."); + Assert.state(jobInstanceId.equals(localState.getJobId()), "Message contained wrong job instance id [" + + jobInstanceId + "] should have been [" + localState.getJobId() + "]."); + localState.actual++; + // TODO: apply the skip count + if (!payload.isSuccessful()) { + throw new AsynchronousFailureException("Failure or interrupt detected in handler: " + + payload.getMessage()); + } + } + } + + private static class LocalState { + private long actual; + + private long expected; + + private StepExecution stepExecution; + + public long getExpecting() { + return expected - actual; + } + + public StepContribution createStepContribution() { + return stepExecution.createStepContribution(); + } + + public Long getJobId() { + return stepExecution.getJobExecution().getJobId(); + } + + public void setStepExecution(StepExecution stepExecution) { + this.stepExecution = stepExecution; + } + + public void reset() { + expected = actual = 0; + } + } + +} diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkProcessorChunkHandler.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkProcessorChunkHandler.java index f1b722f33..a2dbfd386 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkProcessorChunkHandler.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkProcessorChunkHandler.java @@ -1,61 +1,77 @@ -package org.springframework.batch.integration.chunk; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.step.item.ChunkProcessor; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.integration.annotation.MessageEndpoint; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.util.Assert; - -@MessageEndpoint -public class ChunkProcessorChunkHandler implements ChunkHandler, InitializingBean { - - private static final Log logger = LogFactory.getLog(ChunkProcessorChunkHandler.class); - - private ChunkProcessor chunkProcessor; - - /* - * (non-Javadoc) - * - * @see - * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - public void afterPropertiesSet() throws Exception { - Assert.notNull(chunkProcessor, "A ChunkProcessor must be provided"); - } - - /** - * Public setter for the {@link ChunkProcessor}. - * - * @param chunkProcessor the chunkProcessor to set - */ - public void setChunkProcessor(ChunkProcessor chunkProcessor) { - this.chunkProcessor = chunkProcessor; - } - - /** - * - * @see ChunkHandler#handleChunk(ChunkRequest) - */ - @ServiceActivator - public ChunkResponse handleChunk(ChunkRequest chunkRequest) { - - logger.debug("Handling chunk: " + chunkRequest); - - StepContribution stepContribution = chunkRequest.getStepContribution(); - try { - chunkProcessor.process(stepContribution, chunkRequest.getChunk()); - } - catch (Exception e) { - logger.debug("Failed chunk", e); - return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, e.getClass().getName() + ": " - + e.getMessage()); - } - - logger.debug("Completed chunk handling with " + stepContribution); - return new ChunkResponse(true, chunkRequest.getJobId(), stepContribution); - - } -} +/* + * Copyright 2006-2007 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.integration.chunk; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.step.item.ChunkProcessor; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.integration.annotation.MessageEndpoint; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.util.Assert; + +@MessageEndpoint +public class ChunkProcessorChunkHandler implements ChunkHandler, InitializingBean { + + private static final Log logger = LogFactory.getLog(ChunkProcessorChunkHandler.class); + + private ChunkProcessor chunkProcessor; + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + Assert.notNull(chunkProcessor, "A ChunkProcessor must be provided"); + } + + /** + * Public setter for the {@link ChunkProcessor}. + * + * @param chunkProcessor the chunkProcessor to set + */ + public void setChunkProcessor(ChunkProcessor chunkProcessor) { + this.chunkProcessor = chunkProcessor; + } + + /** + * + * @see ChunkHandler#handleChunk(ChunkRequest) + */ + @ServiceActivator + public ChunkResponse handleChunk(ChunkRequest chunkRequest) { + + logger.debug("Handling chunk: " + chunkRequest); + + StepContribution stepContribution = chunkRequest.getStepContribution(); + try { + chunkProcessor.process(stepContribution, chunkRequest.getChunk()); + } + catch (Exception e) { + logger.debug("Failed chunk", e); + return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, e.getClass().getName() + ": " + + e.getMessage()); + } + + logger.debug("Completed chunk handling with " + stepContribution); + return new ChunkResponse(true, chunkRequest.getJobId(), stepContribution); + + } +} diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkRequest.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkRequest.java index e7fe535c2..216dd2c79 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkRequest.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkRequest.java @@ -1,44 +1,60 @@ -package org.springframework.batch.integration.chunk; - -import java.io.Serializable; -import java.util.Collection; - -import org.springframework.batch.core.StepContribution; -import org.springframework.batch.core.step.item.Chunk; - -public class ChunkRequest implements Serializable { - - private final Long jobId; - private final Chunk items; - private final StepContribution stepContribution; - - public ChunkRequest(Collection items, Long jobId, StepContribution stepContribution) { - this.items = new Chunk(items); - this.jobId = jobId; - this.stepContribution = stepContribution; - } - - public Long getJobId() { - return jobId; - } - - public Chunk getChunk() { - return items; - } - - /** - * @return the {@link StepContribution} for this chunk - */ - public StepContribution getStepContribution() { - return stepContribution; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getClass().getSimpleName()+": jobId="+jobId+", contribution="+stepContribution+", item count="+items.size(); - } - -} +/* + * Copyright 2006-2007 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.integration.chunk; + +import java.io.Serializable; +import java.util.Collection; + +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.step.item.Chunk; + +public class ChunkRequest implements Serializable { + + private final Long jobId; + private final Chunk items; + private final StepContribution stepContribution; + + public ChunkRequest(Collection items, Long jobId, StepContribution stepContribution) { + this.items = new Chunk(items); + this.jobId = jobId; + this.stepContribution = stepContribution; + } + + public Long getJobId() { + return jobId; + } + + public Chunk getChunk() { + return items; + } + + /** + * @return the {@link StepContribution} for this chunk + */ + public StepContribution getStepContribution() { + return stepContribution; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getClass().getSimpleName()+": jobId="+jobId+", contribution="+stepContribution+", item count="+items.size(); + } + +} diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkResponse.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkResponse.java index 2d358e38b..fec255ab3 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkResponse.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/ChunkResponse.java @@ -1,53 +1,69 @@ -package org.springframework.batch.integration.chunk; - -import java.io.Serializable; - -import org.springframework.batch.core.StepContribution; - -public class ChunkResponse implements Serializable { - - private final StepContribution stepContribution; - private final Long jobId; - private final boolean status; - private final String message; - - public ChunkResponse(Long jobId, StepContribution stepContribution) { - this(true, jobId, stepContribution, null); - } - - public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution) { - this(status, jobId, stepContribution, null); - } - - public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution, String message) { - this.status = status; - this.jobId = jobId; - this.stepContribution = stepContribution; - this.message = message; - } - - public StepContribution getStepContribution() { - return stepContribution; - } - - public Long getJobId() { - return jobId; - } - - public boolean isSuccessful() { - return status; - } - - public String getMessage() { - return message; - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getClass().getSimpleName()+": jobId="+jobId+", stepContribution="+stepContribution+", successful="+status; - } - -} +/* + * Copyright 2006-2007 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.integration.chunk; + +import java.io.Serializable; + +import org.springframework.batch.core.StepContribution; + +public class ChunkResponse implements Serializable { + + private final StepContribution stepContribution; + private final Long jobId; + private final boolean status; + private final String message; + + public ChunkResponse(Long jobId, StepContribution stepContribution) { + this(true, jobId, stepContribution, null); + } + + public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution) { + this(status, jobId, stepContribution, null); + } + + public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution, String message) { + this.status = status; + this.jobId = jobId; + this.stepContribution = stepContribution; + this.message = message; + } + + public StepContribution getStepContribution() { + return stepContribution; + } + + public Long getJobId() { + return jobId; + } + + public boolean isSuccessful() { + return status; + } + + public String getMessage() { + return message; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getClass().getSimpleName()+": jobId="+jobId+", stepContribution="+stepContribution+", successful="+status; + } + +} diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/file/MessageToJobParametersStrategy.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/file/MessageToJobParametersStrategy.java index eaf5758c0..9fff389f0 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/file/MessageToJobParametersStrategy.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/file/MessageToJobParametersStrategy.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.integration.file; import org.springframework.batch.core.JobParameters; diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/launch/JobLaunchingMessageHandler.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/launch/JobLaunchingMessageHandler.java index c9b16dda2..ca02f07c8 100644 --- a/spring-batch-integration/src/main/java/org/springframework/batch/integration/launch/JobLaunchingMessageHandler.java +++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/launch/JobLaunchingMessageHandler.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.integration.launch; import org.springframework.batch.core.Job; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/InfiniteLoopReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/InfiniteLoopReader.java index 24f47ed7f..95894990c 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/InfiniteLoopReader.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/InfiniteLoopReader.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.common; import org.springframework.batch.item.ItemReader; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemListener.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemListener.java index eb4d92e82..c7c6fe96f 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemListener.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemListener.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.common; import javax.sql.DataSource; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemReader.java index eb55f81ef..27820252f 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemReader.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemReader.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.common; import java.sql.ResultSet; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemWriter.java index a8a84ca11..cb61337c8 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/common/StagingItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.common; import java.io.Serializable; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java index cd7b56e20..56bb51c15 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Game.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football; import java.io.Serializable; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java index dfd9e5ef2..b97c26cf5 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/Player.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football; import java.io.Serializable; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java index 806950dfe..6d22b55b3 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java index 7a257c08a..8b6aeced5 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/PlayerSummary.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football; import org.apache.commons.lang.builder.EqualsBuilder; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java index ba6796b00..a1ff7afcb 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/FootballExceptionHandler.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import org.apache.commons.logging.Log; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java index f803e771c..3121b50fe 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/GameFieldSetMapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import org.springframework.batch.item.file.mapping.FieldSetMapper; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java index 4c39b47d0..9bf50cc36 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcGameDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java index 3d665e2c0..ccd8cf813 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerDao.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import org.springframework.batch.sample.domain.football.Player; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java index e1966d616..8f998c2cc 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/JdbcPlayerSummaryDao.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java index eab26b717..7fdadf1e2 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerFieldSetMapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import org.springframework.batch.item.file.mapping.FieldSetMapper; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java index 4e5d3b8b4..57945a217 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/football/internal/PlayerItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.football.internal; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CompositeCustomerUpdateLineTokenizer.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CompositeCustomerUpdateLineTokenizer.java index a52e10370..3f10b7281 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CompositeCustomerUpdateLineTokenizer.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CompositeCustomerUpdateLineTokenizer.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import org.springframework.batch.core.StepExecution; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerDao.java index c6535c7e0..fcfd68836 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerDao.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import java.math.BigDecimal; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerOperation.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerOperation.java index cfc5037dd..de5dcc5f9 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerOperation.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerOperation.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import java.util.HashMap; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdate.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdate.java index fbdfb8ffe..22e510667 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdate.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdate.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import java.math.BigDecimal; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateFieldSetMapper.java index 6750f7057..2fe41953d 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateFieldSetMapper.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateFieldSetMapper.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import java.math.BigDecimal; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateProcessor.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateProcessor.java index b42f4eb1c..74f5737ce 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateProcessor.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateProcessor.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import static org.springframework.batch.sample.domain.trade.CustomerOperation.*; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateWriter.java index 432cc9ce0..3c32bf639 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/CustomerUpdateWriter.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/InvalidCustomerLogger.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/InvalidCustomerLogger.java index c1025b98d..a3c7079f0 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/InvalidCustomerLogger.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/InvalidCustomerLogger.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade; /** diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CommonsLoggingInvalidCustomerLogger.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CommonsLoggingInvalidCustomerLogger.java index 84380d87c..71c3b8a2c 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CommonsLoggingInvalidCustomerLogger.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CommonsLoggingInvalidCustomerLogger.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; import org.apache.commons.logging.Log; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditIncreaseProcessor.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditIncreaseProcessor.java index 8c5f4c565..0987183f3 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditIncreaseProcessor.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditIncreaseProcessor.java @@ -1,20 +1,36 @@ -package org.springframework.batch.sample.domain.trade.internal; - -import java.math.BigDecimal; - -import org.springframework.batch.item.ItemProcessor; -import org.springframework.batch.sample.domain.trade.CustomerCredit; - -/** - * Increases customer's credit by a fixed amount. - * - * @author Robert Kasanicky - */ -public class CustomerCreditIncreaseProcessor implements ItemProcessor { - - public static final BigDecimal FIXED_AMOUNT = new BigDecimal("5"); - - public CustomerCredit process(CustomerCredit item) throws Exception { - return item.increaseCreditBy(FIXED_AMOUNT); - } -} +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; + +import java.math.BigDecimal; + +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.sample.domain.trade.CustomerCredit; + +/** + * Increases customer's credit by a fixed amount. + * + * @author Robert Kasanicky + */ +public class CustomerCreditIncreaseProcessor implements ItemProcessor { + + public static final BigDecimal FIXED_AMOUNT = new BigDecimal("5"); + + public CustomerCredit process(CustomerCredit item) throws Exception { + return item.increaseCreditBy(FIXED_AMOUNT); + } +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditItemWriter.java index 7005eede0..47a111634 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditItemWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditRowMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditRowMapper.java index f6db64c4c..17cc4a44f 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditRowMapper.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/CustomerCreditRowMapper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; import java.sql.ResultSet; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/GeneratingTradeItemReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/GeneratingTradeItemReader.java index 25d818a80..0f2d5ef63 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/GeneratingTradeItemReader.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/GeneratingTradeItemReader.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; import java.math.BigDecimal; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/HibernateAwareCustomerCreditItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/HibernateAwareCustomerCreditItemWriter.java index 1b17405fc..a394f90cd 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/HibernateAwareCustomerCreditItemWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/HibernateAwareCustomerCreditItemWriter.java @@ -1,54 +1,70 @@ -package org.springframework.batch.sample.domain.trade.internal; - -import java.util.List; - -import org.hibernate.SessionFactory; -import org.springframework.batch.item.ItemWriter; -import org.springframework.batch.sample.domain.trade.CustomerCredit; -import org.springframework.batch.sample.domain.trade.CustomerCreditDao; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.orm.hibernate3.HibernateOperations; -import org.springframework.orm.hibernate3.HibernateTemplate; -import org.springframework.util.Assert; - -/** - * Delegates writing to a custom DAO and flushes + clears hibernate session to - * fulfill the {@link ItemWriter} contract. - * - * @author Robert Kasanicky - */ -public class HibernateAwareCustomerCreditItemWriter implements ItemWriter, InitializingBean { - - private CustomerCreditDao dao; - - private HibernateOperations hibernateTemplate; - - public void write(List items) throws Exception { - for (CustomerCredit credit : items) { - dao.writeCredit(credit); - } - try { - hibernateTemplate.flush(); - } - finally { - // this should happen automatically on commit, but to be on the safe - // side... - hibernateTemplate.clear(); - } - - } - - public void setDao(CustomerCreditDao dao) { - this.dao = dao; - } - - public void setSessionFactory(SessionFactory sessionFactory) { - this.hibernateTemplate = new HibernateTemplate(sessionFactory); - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(hibernateTemplate, "Hibernate session factory must be set"); - Assert.notNull(dao, "Delegate DAO must be set"); - } - -} +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; + +import java.util.List; + +import org.hibernate.SessionFactory; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.sample.domain.trade.CustomerCredit; +import org.springframework.batch.sample.domain.trade.CustomerCreditDao; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.orm.hibernate3.HibernateOperations; +import org.springframework.orm.hibernate3.HibernateTemplate; +import org.springframework.util.Assert; + +/** + * Delegates writing to a custom DAO and flushes + clears hibernate session to + * fulfill the {@link ItemWriter} contract. + * + * @author Robert Kasanicky + */ +public class HibernateAwareCustomerCreditItemWriter implements ItemWriter, InitializingBean { + + private CustomerCreditDao dao; + + private HibernateOperations hibernateTemplate; + + public void write(List items) throws Exception { + for (CustomerCredit credit : items) { + dao.writeCredit(credit); + } + try { + hibernateTemplate.flush(); + } + finally { + // this should happen automatically on commit, but to be on the safe + // side... + hibernateTemplate.clear(); + } + + } + + public void setDao(CustomerCreditDao dao) { + this.dao = dao; + } + + public void setSessionFactory(SessionFactory sessionFactory) { + this.hibernateTemplate = new HibernateTemplate(sessionFactory); + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(hibernateTemplate, "Hibernate session factory must be set"); + Assert.notNull(dao, "Delegate DAO must be set"); + } + +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/JdbcCustomerDao.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/JdbcCustomerDao.java index 3c9a45af6..c7b5f24e2 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/JdbcCustomerDao.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/domain/trade/internal/JdbcCustomerDao.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.domain.trade.internal; import java.math.BigDecimal; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/jmx/SimpleMessageApplicationEvent.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/jmx/SimpleMessageApplicationEvent.java index e2f942143..45f81e20e 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/jmx/SimpleMessageApplicationEvent.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/jmx/SimpleMessageApplicationEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.jmx; import org.springframework.context.ApplicationEvent; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/launch/DefaultJobLoader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/launch/DefaultJobLoader.java index 2f362ea4a..01d936af9 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/launch/DefaultJobLoader.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/launch/DefaultJobLoader.java @@ -1,6 +1,19 @@ -/** - * +/* + * Copyright 2006-2007 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.sample.launch; import java.util.HashMap; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java index eefa602c9..f3025235e 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/HeaderCopyCallback.java @@ -1,31 +1,47 @@ -package org.springframework.batch.sample.support; - -import java.io.IOException; -import java.io.Writer; - -import org.springframework.batch.item.file.FlatFileHeaderCallback; -import org.springframework.batch.item.file.FlatFileItemReader; -import org.springframework.batch.item.file.FlatFileItemWriter; -import org.springframework.batch.item.file.LineCallbackHandler; -import org.springframework.util.Assert; - -/** - * Designed to be registered with both {@link FlatFileItemReader} and - * {@link FlatFileItemWriter} and copy header line from input file to output - * file. - */ -public class HeaderCopyCallback implements LineCallbackHandler, FlatFileHeaderCallback { - - private String header = ""; - - public void handleLine(String line) { - Assert.notNull(line); - this.header = line; - } - - public void writeHeader(Writer writer) throws IOException { - writer.write("header from input: " + header); - - } - -} +/* + * Copyright 2006-2007 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.sample.support; + +import java.io.IOException; +import java.io.Writer; + +import org.springframework.batch.item.file.FlatFileHeaderCallback; +import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.FlatFileItemWriter; +import org.springframework.batch.item.file.LineCallbackHandler; +import org.springframework.util.Assert; + +/** + * Designed to be registered with both {@link FlatFileItemReader} and + * {@link FlatFileItemWriter} and copy header line from input file to output + * file. + */ +public class HeaderCopyCallback implements LineCallbackHandler, FlatFileHeaderCallback { + + private String header = ""; + + public void handleLine(String line) { + Assert.notNull(line); + this.header = line; + } + + public void writeHeader(Writer writer) throws IOException { + writer.write("header from input: " + header); + + } + +} diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/RetrySampleItemWriter.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/RetrySampleItemWriter.java index 220f46cf4..4920caf00 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/RetrySampleItemWriter.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/RetrySampleItemWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.sample.support; import java.util.List; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/SummaryFooterCallback.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/SummaryFooterCallback.java index a21f8ed2a..9cfc152a2 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/SummaryFooterCallback.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/support/SummaryFooterCallback.java @@ -1,27 +1,43 @@ -package org.springframework.batch.sample.support; - -import java.io.IOException; -import java.io.Writer; - -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.listener.StepExecutionListenerSupport; -import org.springframework.batch.item.file.FlatFileFooterCallback; - -/** - * Writes summary info in the footer of a file. - */ -public class SummaryFooterCallback extends StepExecutionListenerSupport implements FlatFileFooterCallback{ - - private StepExecution stepExecution; - - public void writeFooter(Writer writer) throws IOException { - writer.write("footer - number of items written: " + stepExecution.getWriteCount()); - } - - @Override - public void beforeStep(StepExecution stepExecution) { - this.stepExecution = stepExecution; - } - - -} +/* + * Copyright 2006-2007 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.sample.support; + +import java.io.IOException; +import java.io.Writer; + +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.listener.StepExecutionListenerSupport; +import org.springframework.batch.item.file.FlatFileFooterCallback; + +/** + * Writes summary info in the footer of a file. + */ +public class SummaryFooterCallback extends StepExecutionListenerSupport implements FlatFileFooterCallback{ + + private StepExecution stepExecution; + + public void writeFooter(Writer writer) throws IOException { + writer.write("footer - number of items written: " + stepExecution.getWriteCount()); + } + + @Override + public void beforeStep(StepExecution stepExecution) { + this.stepExecution = stepExecution; + } + + +} diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java index bf8a70f44..cc3e654cf 100644 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.test; import java.util.Date; diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractSimpleJobTests.java b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractSimpleJobTests.java index 6b7daec0e..c49b4d022 100755 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractSimpleJobTests.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractSimpleJobTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.test; import java.util.ArrayList; diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/AssertFile.java b/spring-batch-test/src/main/java/org/springframework/batch/test/AssertFile.java index e19a88925..e151ec4fd 100644 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/AssertFile.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/AssertFile.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.test; import java.io.BufferedReader; diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/StepRunner.java b/spring-batch-test/src/main/java/org/springframework/batch/test/StepRunner.java index dfb50bb2b..3e239c1c8 100755 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/StepRunner.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/StepRunner.java @@ -1,3 +1,19 @@ +/* + * Copyright 2006-2007 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.test; import java.util.ArrayList;