/*
* eGovFrame Easy Batch
* Copyright The eGovFrame Open Community (http://open.egovframe.go.kr)).
*
* 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.
*
* @author 서경석(슈퍼개발자K3)
*/
package egovframework.rte.bat.item;
import java.util.List;
import egovframework.rte.bat.core.item.database.EgovJdbcBatchItemWriter;
import egovframework.rte.bat.core.item.database.support.EgovMethodMapItemPreparedStatementSetter;
import egovframework.rte.bat.core.item.file.transform.EgovFieldExtractor;
import egovframework.rte.bat.core.item.file.transform.EgovFixedLengthLineAggregator;
import javax.sql.DataSource;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemStreamWriter;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
import org.springframework.batch.item.file.transform.FieldExtractor;
import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
/**
* @author 서경석
* @since 2014.11.05
* @version 1.0
* @see
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2014.11.05 서경석 최초 생성
* 2014.11.28 표준프레임워크 공통컴포넌트 추가 적용 (패키지 변경)
*
* </pre>
*/
public class DefaultItemWriter<T> implements ItemStreamWriter<T>{
// Output Resource Type - key
private static final String XML_CONF_FLAG_KEY = ".writer.xml.conf.flag";
private static final String WRITER_RESOURCE_TYPE_KEY = ".writer.resource.type";
private static final String WRITER_RESOURCE_NAME_KEY = ".writer.resource.name";
private static final String WRITER_FIELD_NAMES_KEY = ".writer.field.names";
private static final String WRITER_FIELD_RANGES_KEY = ".writer.field.ranges";
private static final String WRITER_DELIMITER_KEY = ".writer.delimiter";
private static final String WRITER_SQL_KEY = ".writer.sql";
private static final String WRITER_PARAMS_KEY = ".writer.params";
// Output Resource Type - Value
private static final String DELIMITED_FILE_TYPE = "delimitedFile";
private static final String FIXED_LENGTH_FILE_TYPE = "fixedLengthFile";
private static final String JDBC_DB_TYPE = "jdbcDb";
// XML 설정 내용을 출력하기 위한 설정
boolean printXmlConf = false;
// 실제 동작하는 Reader
private ItemWriter<T> writer;
// 공통 설정
private String stepName;
private JobParameters jobParameters;
private String writerResourceType;
// File 입력인 경우 사용되는 설정
private Resource resource; // 공통
private String resourceName; // 공통
private String[] fieldNames; // 공통
private String names; // 공통
private String delimiter; // delimited 방식인 경우
private int[] fieldRanges; // fixedLength 방식인 경우
private String ranges;
// DB 입력인 경우 사용되는 설정
private DataSource dataSource;
private String sql;
private String[] params;
private String tempParams;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@BeforeStep
public void beforeStep(StepExecution stepExecution) throws ClassNotFoundException{
this.stepName = stepExecution.getStepName();
this.jobParameters = stepExecution.getJobParameters();
String flag = jobParameters.getString(stepName + XML_CONF_FLAG_KEY);
if((flag != null) && "true".equalsIgnoreCase(flag)) {
printXmlConf = true;
}
// Input Resource Type에 따라 필요한 설정 값 세팅
makeWriterConfigValue();
}
@Override
public void open(ExecutionContext executionContext)
throws ItemStreamException {
// ItemReader 생성
makeItemWriter();
if(this.writer instanceof ItemStream) {
((ItemStream) this.writer).open(executionContext);
}
}
@Override
public void update(ExecutionContext executionContext)
throws ItemStreamException {
if(this.writer instanceof ItemStream) {
((ItemStream) this.writer).update(executionContext);
}
}
@Override
public void close() throws ItemStreamException {
if(this.writer instanceof ItemStream) {
((ItemStream) this.writer).close();
}
}
@Override
public void write(List<? extends T> items) throws Exception {
this.writer.write(items);
}
private void makeWriterConfigValue() {
if(jobParameters.getString(stepName + WRITER_RESOURCE_TYPE_KEY) != null) {
this.writerResourceType = jobParameters.getString(stepName + WRITER_RESOURCE_TYPE_KEY);
if(DELIMITED_FILE_TYPE.equalsIgnoreCase(this.writerResourceType) || FIXED_LENGTH_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)) {
// 입력 리소스가 File인 경우 공통 처리 부분
this.resourceName= jobParameters.getString(stepName + WRITER_RESOURCE_NAME_KEY);
this.names = jobParameters.getString(stepName + WRITER_FIELD_NAMES_KEY);
if(DELIMITED_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)){
this.delimiter = jobParameters.getString(stepName + WRITER_DELIMITER_KEY);
if(this.resourceName == null || this.delimiter == null || this.names == null ) {
throw new RuntimeException(stepName + "스텝의 Writer 설정에서 resourceName, delimiter, names는 필수입니다. 다음 처럼 설정하세요.\n"
+ stepName + ".writer.resourceName=file:./inputs/csvData.csv " + stepName + ".writer.delimiter=, " + stepName + ".writer.fieldNames=name,age ");
}
} else {
this.ranges = jobParameters.getString(stepName + WRITER_FIELD_RANGES_KEY);
if(this.resourceName == null || ranges == null || this.names == null ) {
throw new RuntimeException(stepName + "스텝의 Reader 설정에서 resourceName, fieldRanges, names는 필수입니다. 다음 처럼 설정하세요.\n"
+ stepName + ".writer.resourceName=file:./target/test-outputs/txtOutput.txt " + stepName + ".writer.fieldRanges=9,2 " + stepName + ".writer.fieldNames=name,age ");
}
String[] rangeArray = ranges.split(",");
this.fieldRanges = new int[rangeArray.length];
for(int idx=0; idx<rangeArray.length; idx++) {
fieldRanges[idx] = Integer.parseInt(rangeArray[idx]);
}
}
this.resource = new FileSystemResource(resourceName);
this.fieldNames = names.split(",");
} else if(JDBC_DB_TYPE.equalsIgnoreCase(this.writerResourceType)){
this.sql = jobParameters.getString(stepName + WRITER_SQL_KEY);
tempParams = jobParameters.getString(stepName + WRITER_PARAMS_KEY);
if(this.sql == null || tempParams == null) {
throw new RuntimeException(stepName + "스텝의 Writer 설정에서 sql, params는 필수입니다. 다음 처럼 설정하세요.\n"
+ stepName + ".writer.sql=UPDATE CUSTOMER set credit =? where name =? " + stepName + ".writer.params=credit,name ");
}
this.params = tempParams.split(",");
}
} else {
throw new RuntimeException(stepName + ".writerResourceType=delimitedFile'처럼, 출력 리소스 타입을 Job 파라미터로 입력하세요.\n"
+ "리소스 타입 종류) delimitedFile, fixedLengthFile, jdbcDb");
}
}
private DelimitedLineAggregator<T> makeDelimitedLineAggregator(FieldExtractor<T> fieldExtractor) {
DelimitedLineAggregator<T> lineAggregator = new DelimitedLineAggregator<T>();
lineAggregator.setDelimiter(this.delimiter);
lineAggregator.setFieldExtractor(fieldExtractor);
return lineAggregator;
}
private EgovFixedLengthLineAggregator<T> makeEgovFixedLengthLineAggregator(FieldExtractor<T> fieldExtractor) {
EgovFixedLengthLineAggregator<T> lineAggregator = new EgovFixedLengthLineAggregator<T>();
lineAggregator.setFieldExtractor(fieldExtractor);
lineAggregator.setFieldRanges(fieldRanges);
return lineAggregator;
}
private FieldExtractor<T> makeFieldExtractor() {
EgovFieldExtractor<T> fieldExtractor = new EgovFieldExtractor<T>();
fieldExtractor.setNames(this.fieldNames);
fieldExtractor.afterPropertiesSet();
return fieldExtractor;
}
private void makeItemWriter() {
if(DELIMITED_FILE_TYPE.equalsIgnoreCase(this.writerResourceType) || FIXED_LENGTH_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)) {
FieldExtractor<T> fieldExtractor = makeFieldExtractor();
LineAggregator<T> lineAggregator = null;
if(DELIMITED_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)) {
lineAggregator = makeDelimitedLineAggregator(fieldExtractor);
} else {
lineAggregator = makeEgovFixedLengthLineAggregator(fieldExtractor);
}
this.writer = new FlatFileItemWriter<T>();
((FlatFileItemWriter<T>)this.writer).setResource(this.resource);
((FlatFileItemWriter<T>)this.writer).setLineAggregator(lineAggregator);
try {
((FlatFileItemWriter<T>)this.writer).afterPropertiesSet();
} catch (Exception e) {
throw new RuntimeException(this.writerResourceType + " 타입의 File을 write 하기 위한 FlatFileItemWriter 생성에 실패 하였습니다.");
}
} else if(JDBC_DB_TYPE.equalsIgnoreCase(this.writerResourceType)){
EgovMethodMapItemPreparedStatementSetter<T> preparedStatementSetter = new EgovMethodMapItemPreparedStatementSetter<T>();
this.writer = new EgovJdbcBatchItemWriter<T>();
((EgovJdbcBatchItemWriter<T>)this.writer).setDataSource(this.dataSource);
((EgovJdbcBatchItemWriter<T>)this.writer).setParams(this.params);
((EgovJdbcBatchItemWriter<T>)this.writer).setSql(this.sql);
((EgovJdbcBatchItemWriter<T>)this.writer).setItemPreparedStatementSetter(preparedStatementSetter);
((EgovJdbcBatchItemWriter<T>)this.writer).setAssertUpdates(true);
try {
((EgovJdbcBatchItemWriter<T>)this.writer).afterPropertiesSet();
} catch (Exception e) {
throw new RuntimeException(this.writerResourceType + " 타입의 File을 write 하기 위한 FlatFileItemWriter 생성에 실패 하였습니다.");
}
}
printXmlConfig();
}
private void printXmlConfig() {
if(printXmlConf) {
if(DELIMITED_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)) {
System.out.println("======= " + stepName + " WRITER 설정(XML 버전) =========\n"
+ "<bean id=\"" + stepName + ".writer\" class=\"org.springframework.batch.item.file.FlatFileItemWriter\" scope=\"step\">\n"
+ " <property name=\"resource\" value=\"" + this.resourceName + "\" />\n"
+ " <property name=\"lineAggregator\">\n"
+ " <bean class=\"org.springframework.batch.item.file.transform.DelimitedLineAggregator\">\n"
+ " <property name=\"delimiter\" value=\"" + this.delimiter + "\" />\n"
+ " <property name=\"fieldExtractor\">\n"
+ " <bean class=\"egovframework.rte.bat.core.item.file.transform.EgovFieldExtractor\">\n"
+ " <property name=\"names\" value=\"" + this.names + "\" />\n"
+ " </bean>\n"
+ " </property>\n"
+ " </bean>\n"
+ " </property>\n"
+ "</bean>\n"
+ "================================================");
} else if(FIXED_LENGTH_FILE_TYPE.equalsIgnoreCase(this.writerResourceType)) {
System.out.println("======= " + stepName + " Writer 설정(XML 버전) =========\n"
+ "<bean id=\"" + stepName + ".writer\" class=\"org.springframework.batch.item.file.FlatFileItemWriter\" scope=\"step\">\n"
+ " <property name=\"resource\" value=\"" + this.resourceName + "\" />\n"
+ " <property name=\"lineAggregator\">\n"
+ " <bean class=\"egovframework.rte.bat.core.item.file.transform.EgovFixedLengthLineAggregator\">\n"
+ " <property name=\"fieldRanges\" value=\"" + this.ranges + "\" />\n"
+ " <property name=\"fieldExtractor\">\n"
+ " <bean class=\"egovframework.rte.bat.core.item.file.transform.EgovFieldExtractor\">\n"
+ " <property name=\"names\" value=\"" + this.names + "\" />\n"
+ " </bean>\n"
+ " </property>\n"
+ " </bean>\n"
+ " </property>\n"
+ "</bean>\n"
+ "================================================");
} else if(JDBC_DB_TYPE.equalsIgnoreCase(this.writerResourceType)){
System.out.println("======= " + stepName + " Writer 설정(XML 버전) =========\n"
+ "<bean id=\"" + stepName + ".writer\" class=\"egovframework.rte.bat.core.item.database.EgovJdbcBatchItemWriter\">\n"
+ " <property name=\"assertUpdates\" value=\"true\" />\n"
+ " <property name=\"itemPreparedStatementSetter\">\n"
+ " <bean class=\"egovframework.rte.bat.core.item.database.support.EgovMethodMapItemPreparedStatementSetter\" />\n"
+ " </property>\n"
+ " <property name=\"sql\" value=\"" + this.sql + "\" />\n"
+ " <property name=\"params\" value=\"" + this.tempParams + "\" />\n"
+ " <property name=\"dataSource\" ref=\"dataSource\" />\n"
+ "</bean>\n"
+ "================================================");
}
}
}
}