All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redislabs.riot.file.FlatResourceItemWriterBuilder Maven / Gradle / Ivy

package com.redislabs.riot.file;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.springframework.batch.item.file.FlatFileFooterCallback;
import org.springframework.batch.item.file.FlatFileHeaderCallback;
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.batch.item.file.transform.FieldExtractor;
import org.springframework.batch.item.file.transform.FormatterLineAggregator;
import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

public class FlatResourceItemWriterBuilder {

	private WritableResource resource;

	private String lineSeparator = FlatResourceItemWriter.DEFAULT_LINE_SEPARATOR;

	private LineAggregator lineAggregator;

	private String encoding = FlatResourceItemWriter.DEFAULT_CHARSET;

	private boolean shouldDeleteIfExists = true;

	private boolean append = false;

	private boolean shouldDeleteIfEmpty = false;

	private FlatFileHeaderCallback headerCallback;

	private FlatFileFooterCallback footerCallback;

	private boolean saveState = true;

	private String name;

	private DelimitedBuilder delimitedBuilder;

	private FormattedBuilder formattedBuilder;

	/**
	 * Configure if the state of the
	 * {@link org.springframework.batch.item.ItemStreamSupport} should be persisted
	 * within the {@link org.springframework.batch.item.ExecutionContext} for
	 * restart purposes.
	 *
	 * @param saveState defaults to true
	 * @return The current instance of the builder.
	 */
	public FlatResourceItemWriterBuilder saveState(boolean saveState) {
		this.saveState = saveState;

		return this;
	}

	/**
	 * The name used to calculate the key within the
	 * {@link org.springframework.batch.item.ExecutionContext}. Required if
	 * {@link #saveState(boolean)} is set to true.
	 *
	 * @param name name of the reader instance
	 * @return The current instance of the builder.
	 * @see org.springframework.batch.item.ItemStreamSupport#setName(String)
	 */
	public FlatResourceItemWriterBuilder name(String name) {
		this.name = name;

		return this;
	}

	/**
	 * The {@link Resource} to be used as output.
	 *
	 * @param resource the output of the writer.
	 * @return The current instance of the builder.
	 * @see FlatResourceItemWriter#setResource(Resource)
	 */
	public FlatResourceItemWriterBuilder resource(Resource resource) {
		Assert.isInstanceOf(WritableResource.class, resource);
		this.resource = (WritableResource) resource;

		return this;
	}

	/**
	 * String used to separate lines in output. Defaults to the System property
	 * line.separator.
	 *
	 * @param lineSeparator value to use for a line separator
	 * @return The current instance of the builder.
	 * @see FlatResourceItemWriter#setLineSeparator(String)
	 */
	public FlatResourceItemWriterBuilder lineSeparator(String lineSeparator) {
		this.lineSeparator = lineSeparator;

		return this;
	}

	/**
	 * Line aggregator used to build the String version of each item.
	 *
	 * @param lineAggregator {@link LineAggregator} implementation
	 * @return The current instance of the builder.
	 * @see FlatResourceItemWriter#setLineAggregator(LineAggregator)
	 */
	public FlatResourceItemWriterBuilder lineAggregator(LineAggregator lineAggregator) {
		this.lineAggregator = lineAggregator;

		return this;
	}

	/**
	 * Encoding used for output.
	 *
	 * @param encoding encoding type.
	 * @return The current instance of the builder.
	 * @see FlatResourceItemWriter#setEncoding(String)
	 */
	public FlatResourceItemWriterBuilder encoding(String encoding) {
		this.encoding = encoding;

		return this;
	}

	/**
	 * If set to true, once the step is complete, if the resource previously
	 * provided is empty, it will be deleted.
	 *
	 * @param shouldDelete defaults to false
	 * @return The current instance of the builder
	 * @see FlatResourceItemWriter#setShouldDeleteIfEmpty(boolean)
	 */
	public FlatResourceItemWriterBuilder shouldDeleteIfEmpty(boolean shouldDelete) {
		this.shouldDeleteIfEmpty = shouldDelete;

		return this;
	}

	/**
	 * If set to true, upon the start of the step, if the resource already exists,
	 * it will be deleted and recreated.
	 *
	 * @param shouldDelete defaults to true
	 * @return The current instance of the builder
	 * @see FlatResourceItemWriter#setShouldDeleteIfExists(boolean)
	 */
	public FlatResourceItemWriterBuilder shouldDeleteIfExists(boolean shouldDelete) {
		this.shouldDeleteIfExists = shouldDelete;

		return this;
	}

	/**
	 * If set to true and the file exists, the output will be appended to the
	 * existing file.
	 *
	 * @param append defaults to false
	 * @return The current instance of the builder
	 * @see FlatResourceItemWriter#setAppendAllowed(boolean)
	 */
	public FlatResourceItemWriterBuilder append(boolean append) {
		this.append = append;

		return this;
	}

	/**
	 * A callback for header processing.
	 *
	 * @param callback {@link FlatFileHeaderCallback} impl
	 * @return The current instance of the builder
	 * @see FlatResourceItemWriter#setHeaderCallback(FlatFileHeaderCallback)
	 */
	public FlatResourceItemWriterBuilder headerCallback(FlatFileHeaderCallback callback) {
		this.headerCallback = callback;

		return this;
	}

	/**
	 * A callback for footer processing
	 * 
	 * @param callback {@link FlatFileFooterCallback} impl
	 * @return The current instance of the builder
	 * @see FlatResourceItemWriter#setFooterCallback(FlatFileFooterCallback)
	 */
	public FlatResourceItemWriterBuilder footerCallback(FlatFileFooterCallback callback) {
		this.footerCallback = callback;

		return this;
	}

	/**
	 * Returns an instance of a {@link DelimitedBuilder} for building a
	 * {@link DelimitedLineAggregator}. The {@link DelimitedLineAggregator}
	 * configured by this builder will only be used if one is not explicitly
	 * configured via {@link FlatResourceItemWriterBuilder#lineAggregator}
	 *
	 * @return a {@link DelimitedBuilder}
	 *
	 */
	public DelimitedBuilder delimited() {
		this.delimitedBuilder = new DelimitedBuilder<>(this);
		return this.delimitedBuilder;
	}

	/**
	 * Returns an instance of a {@link FormattedBuilder} for building a
	 * {@link FormatterLineAggregator}. The {@link FormatterLineAggregator}
	 * configured by this builder will only be used if one is not explicitly
	 * configured via {@link FlatResourceItemWriterBuilder#lineAggregator}
	 *
	 * @return a {@link FormattedBuilder}
	 *
	 */
	public FormattedBuilder formatted() {
		this.formattedBuilder = new FormattedBuilder<>(this);
		return this.formattedBuilder;
	}

	/**
	 * A builder for constructing a {@link FormatterLineAggregator}.
	 *
	 * @param  the type of the parent {@link FlatResourceItemWriterBuilder}
	 */
	public static class FormattedBuilder {

		private FlatResourceItemWriterBuilder parent;

		private String format;

		private Locale locale = Locale.getDefault();

		private int maximumLength = 0;

		private int minimumLength = 0;

		private FieldExtractor fieldExtractor;

		private List names = new ArrayList<>();

		protected FormattedBuilder(FlatResourceItemWriterBuilder parent) {
			this.parent = parent;
		}

		/**
		 * Set the format string used to aggregate items
		 * 
		 * @param format used to aggregate items
		 * @return The instance of the builder for chaining.
		 */
		public FormattedBuilder format(String format) {
			this.format = format;
			return this;
		}

		/**
		 * Set the locale.
		 * 
		 * @param locale to use
		 * @return The instance of the builder for chaining.
		 */
		public FormattedBuilder locale(Locale locale) {
			this.locale = locale;
			return this;
		}

		/**
		 * Set the minimum length of the formatted string. If this is not set the
		 * default is to allow any length.
		 * 
		 * @param minimumLength of the formatted string
		 * @return The instance of the builder for chaining.
		 */
		public FormattedBuilder minimumLength(int minimumLength) {
			this.minimumLength = minimumLength;
			return this;
		}

		/**
		 * Set the maximum length of the formatted string. If this is not set the
		 * default is to allow any length.
		 * 
		 * @param maximumLength of the formatted string
		 * @return The instance of the builder for chaining.
		 */
		public FormattedBuilder maximumLength(int maximumLength) {
			this.maximumLength = maximumLength;
			return this;
		}

		/**
		 * Set the {@link FieldExtractor} to use to extract fields from each item.
		 * 
		 * @param fieldExtractor to use to extract fields from each item
		 * @return The current instance of the builder
		 */
		public FlatResourceItemWriterBuilder fieldExtractor(FieldExtractor fieldExtractor) {
			this.fieldExtractor = fieldExtractor;
			return this.parent;
		}

		/**
		 * Names of each of the fields within the fields that are returned in the order
		 * they occur within the formatted file. These names will be used to create a
		 * {@link BeanWrapperFieldExtractor} only if no explicit field extractor is set
		 * via {@link FormattedBuilder#fieldExtractor(FieldExtractor)}.
		 *
		 * @param names names of each field
		 * @return The parent {@link FlatResourceItemWriterBuilder}
		 * @see BeanWrapperFieldExtractor#setNames(String[])
		 */
		public FlatResourceItemWriterBuilder names(String[] names) {
			this.names.addAll(Arrays.asList(names));
			return this.parent;
		}

		public FormatterLineAggregator build() {
			Assert.notNull(this.format, "A format is required");
			Assert.isTrue((this.names != null && !this.names.isEmpty()) || this.fieldExtractor != null,
					"A list of field names or a field extractor is required");

			FormatterLineAggregator formatterLineAggregator = new FormatterLineAggregator<>();
			formatterLineAggregator.setFormat(this.format);
			formatterLineAggregator.setLocale(this.locale);
			formatterLineAggregator.setMinimumLength(this.minimumLength);
			formatterLineAggregator.setMaximumLength(this.maximumLength);

			if (this.fieldExtractor == null) {
				BeanWrapperFieldExtractor beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
				beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()]));
				try {
					beanWrapperFieldExtractor.afterPropertiesSet();
				} catch (Exception e) {
					throw new IllegalStateException("Unable to initialize FormatterLineAggregator", e);
				}
				this.fieldExtractor = beanWrapperFieldExtractor;
			}

			formatterLineAggregator.setFieldExtractor(this.fieldExtractor);
			return formatterLineAggregator;
		}
	}

	/**
	 * A builder for constructing a {@link DelimitedLineAggregator}
	 *
	 * @param  the type of the parent {@link FlatResourceItemWriterBuilder}
	 */
	public static class DelimitedBuilder {

		private FlatResourceItemWriterBuilder parent;

		private List names = new ArrayList<>();

		private String delimiter = ",";

		private FieldExtractor fieldExtractor;

		protected DelimitedBuilder(FlatResourceItemWriterBuilder parent) {
			this.parent = parent;
		}

		/**
		 * Define the delimiter for the file.
		 *
		 * @param delimiter String used as a delimiter between fields.
		 * @return The instance of the builder for chaining.
		 * @see DelimitedLineAggregator#setDelimiter(String)
		 */
		public DelimitedBuilder delimiter(String delimiter) {
			this.delimiter = delimiter;
			return this;
		}

		/**
		 * Names of each of the fields within the fields that are returned in the order
		 * they occur within the delimited file. These names will be used to create a
		 * {@link BeanWrapperFieldExtractor} only if no explicit field extractor is set
		 * via {@link DelimitedBuilder#fieldExtractor(FieldExtractor)}.
		 *
		 * @param names names of each field
		 * @return The parent {@link FlatResourceItemWriterBuilder}
		 * @see BeanWrapperFieldExtractor#setNames(String[])
		 */
		public FlatResourceItemWriterBuilder names(String[] names) {
			this.names.addAll(Arrays.asList(names));
			return this.parent;
		}

		/**
		 * Set the {@link FieldExtractor} to use to extract fields from each item.
		 * 
		 * @param fieldExtractor to use to extract fields from each item
		 * @return The parent {@link FlatResourceItemWriterBuilder}
		 */
		public FlatResourceItemWriterBuilder fieldExtractor(FieldExtractor fieldExtractor) {
			this.fieldExtractor = fieldExtractor;
			return this.parent;
		}

		public DelimitedLineAggregator build() {
			Assert.isTrue((this.names != null && !this.names.isEmpty()) || this.fieldExtractor != null,
					"A list of field names or a field extractor is required");

			DelimitedLineAggregator delimitedLineAggregator = new DelimitedLineAggregator<>();
			if (StringUtils.hasLength(this.delimiter)) {
				delimitedLineAggregator.setDelimiter(this.delimiter);
			}

			if (this.fieldExtractor == null) {
				BeanWrapperFieldExtractor beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
				beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()]));
				try {
					beanWrapperFieldExtractor.afterPropertiesSet();
				} catch (Exception e) {
					throw new IllegalStateException("Unable to initialize DelimitedLineAggregator", e);
				}
				this.fieldExtractor = beanWrapperFieldExtractor;
			}

			delimitedLineAggregator.setFieldExtractor(this.fieldExtractor);
			return delimitedLineAggregator;
		}
	}

	/**
	 * Validates and builds a {@link FlatResourceItemWriter}.
	 *
	 * @return a {@link FlatResourceItemWriter}
	 */
	public FlatResourceItemWriter build() {

		Assert.isTrue(this.lineAggregator != null || this.delimitedBuilder != null || this.formattedBuilder != null,
				"A LineAggregator or a DelimitedBuilder or a FormattedBuilder is required");
		Assert.notNull(this.resource, "A Resource is required");

		if (this.saveState) {
			Assert.hasText(this.name, "A name is required when saveState is true");
		}

		FlatResourceItemWriter writer = new FlatResourceItemWriter<>();

		writer.setName(this.name);
		writer.setAppendAllowed(this.append);
		writer.setEncoding(this.encoding);
		writer.setFooterCallback(this.footerCallback);
		writer.setHeaderCallback(this.headerCallback);
		if (this.lineAggregator == null) {
			Assert.state(this.delimitedBuilder == null || this.formattedBuilder == null,
					"Either a DelimitedLineAggregator or a FormatterLineAggregator should be provided, but not both");
			if (this.delimitedBuilder != null) {
				this.lineAggregator = this.delimitedBuilder.build();
			} else {
				this.lineAggregator = this.formattedBuilder.build();
			}
		}
		writer.setLineAggregator(this.lineAggregator);
		writer.setLineSeparator(this.lineSeparator);
		writer.setResource(this.resource);
		writer.setSaveState(this.saveState);
		writer.setShouldDeleteIfEmpty(this.shouldDeleteIfEmpty);
		writer.setShouldDeleteIfExists(this.shouldDeleteIfExists);
		return writer;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy