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 d0c874401..f31ce3a36 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 @@ -41,6 +41,14 @@ public class CompositeItemWriter implements ItemStreamWriter, Initializing private boolean ignoreItemStream = false; + /** + * Establishes the policy whether to call the open, close, or update methods for the + * item writer delegates associated with the CompositeItemWriter. + * + * @param ignoreItemStream if false the delegates' open, close, or update methods will + * be called when the corresponding methods on the CompositeItemWriter are called. If + * true the delegates' open, close, nor update methods will not be called (default is false). + */ public void setIgnoreItemStream(boolean ignoreItemStream) { this.ignoreItemStream = ignoreItemStream; } @@ -58,6 +66,12 @@ public class CompositeItemWriter implements ItemStreamWriter, Initializing Assert.notEmpty(delegates, "The 'delegates' may not be empty"); } + /** + * The list of item writers to use as delegates. Items are written to each of the + * delegates. + * + * @param delegates the list of delegates to use. The delegates list must not be null nor be empty. + */ public void setDelegates(List> delegates) { this.delegates = delegates; } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilder.java new file mode 100644 index 000000000..79554b6a4 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilder.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017 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.builder; + +import java.util.List; + +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.support.CompositeItemWriter; +import org.springframework.util.Assert; + +/** + * Creates a fully qualified CompositeItemWriter. + * + * @author Glenn Renfro + * + * @since 4.0 + */ +public class CompositeItemWriterBuilder { + private List> delegates; + + private boolean ignoreItemStream = false; + + /** + * Establishes the policy whether to call the open, close, or update methods for the + * item writer delegates associated with the CompositeItemWriter. + * + * @param ignoreItemStream if false the delegates' open, close, or update methods will + * be called when the corresponding methods on the CompositeItemWriter are called. If + * true the delegates' open, close, nor update methods will not be called (default is false). + * @return this instance for method chaining. + * + * @see CompositeItemWriter#setIgnoreItemStream(boolean) + */ + public CompositeItemWriterBuilder ignoreItemStream(boolean ignoreItemStream) { + this.ignoreItemStream = ignoreItemStream; + + return this; + } + + /** + * The list of item writers to use as delegates. Items are written to each of the + * delegates. + * + * @param delegates the list of delegates to use. The delegates list must not be null + * nor be empty. + * @return this instance for method chaining. + * + * @see CompositeItemWriter#setDelegates(List) + */ + public CompositeItemWriterBuilder delegates(List> delegates) { + this.delegates = delegates; + + return this; + } + + /** + * Returns a fully constructed {@link CompositeItemWriter}. + * + * @return a new {@link CompositeItemWriter} + */ + public CompositeItemWriter build() { + Assert.notNull(delegates, "A list of delegates is required."); + Assert.notEmpty(delegates, "The delegates list must have one or more delegates."); + + CompositeItemWriter writer = new CompositeItemWriter<>(); + writer.setDelegates(this.delegates); + writer.setIgnoreItemStream(this.ignoreItemStream); + return writer; + } +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilderTests.java new file mode 100644 index 000000000..fa578f395 --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/builder/CompositeItemWriterBuilderTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2017 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.builder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemStreamWriter; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.support.CompositeItemWriter; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * @author Glenn Renfro + */ +public class CompositeItemWriterBuilderTests { + + @Test + public void testProcess() throws Exception { + + final int NUMBER_OF_WRITERS = 10; + List data = Collections.singletonList(new Object()); + + List> writers = new ArrayList>(); + + for (int i = 0; i < NUMBER_OF_WRITERS; i++) { + ItemWriter writer = mock(ItemWriter.class); + writers.add(writer); + } + CompositeItemWriter itemWriter = new CompositeItemWriterBuilder().delegates(writers).build(); + itemWriter.setDelegates(writers); + itemWriter.write(data); + + for (ItemWriter writer : writers) { + verify(writer).write(data); + } + + } + + @Test + public void isStreamOpen() throws Exception { + ignoreItemStream(false); + ignoreItemStream(true); + } + + private void ignoreItemStream(boolean ignoreItemStream) throws Exception { + ItemStreamWriter writer = mock(ItemStreamWriter.class); + List data = Collections.singletonList(new Object()); + ExecutionContext executionContext = new ExecutionContext(); + + List> writers = new ArrayList>(); + writers.add(writer); + CompositeItemWriter itemWriter = new CompositeItemWriterBuilder().delegates(writers) + .ignoreItemStream(ignoreItemStream).build(); + itemWriter.open(executionContext); + + int openCount = 0; + if (!ignoreItemStream) { + openCount = 1; + } + // If user has set ignoreItemStream to true, then it is expected that they opened the delegate writer. + verify(writer, times(openCount)).open(executionContext); + itemWriter.write(data); + } + +}