/*
* This file is part of aCSV.
*
* aCSV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aCSV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with aCSV. If not, see <http://www.gnu.org/licenses/>.
*/
package com.apelle.acsv;
import com.apelle.acsv.annotations.CSV;
import com.apelle.acsv.annotations.CSVBegin;
import com.apelle.acsv.annotations.CSVCase;
import com.apelle.acsv.annotations.CSVEnd;
import org.apache.log4j.Logger;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author FreeMan
* @version $Id$
*/
public class CSVProcessor {
private static final Logger LOGGER;
static {
LOGGER = Logger.getLogger(CSVProcessor.class.getName());
}
private CSV csvInformation;
private Map<Integer, CaseHolder> cases;
private Map<Integer, OutputStream> streams;
private CaseHolder defaultMethod;
private Method beginMethod;
private Method endMethod;
private Object processor;
public CSVProcessor(String className) throws ClassNotFoundException, FileNotFoundException, IllegalAccessException, InstantiationException {
int defaultCounter = 0;
int beginCounter = 0;
int endCounter = 0;
beginMethod = null;
endMethod = null;
Class<?> clazz = Class.forName(className);
processor = clazz.newInstance();
csvInformation = clazz.getAnnotation(CSV.class);
Method[] methods = clazz.getMethods();
cases = new TreeMap<Integer, CaseHolder>();
streams = new HashMap<Integer, OutputStream>();
for (Method m : methods) {
CSVCase csvCase = m.getAnnotation(CSVCase.class);
if (csvCase != null) {
if (csvCase.defaultCase()) {
defaultMethod = new CaseHolder(csvCase, m);
defaultCounter++;
} else {
cases.put(csvCase.caseNum(), new CaseHolder(csvCase, m));
}
if (defaultCounter > 1) {
LOGGER.fatal("Only one Method could be used as default case");
throw new RuntimeException("One one Method could be used as default case");
}
if (csvCase.type().equals(CSVCase.OutputType.FILE)) {
streams.put(csvCase.caseNum(), new FileOutputStream(new File(csvCase.file())));
}
}
if (m.getAnnotation(CSVBegin.class) != null) {
beginMethod = m;
beginCounter++;
}
if (m.getAnnotation(CSVEnd.class) != null) {
endMethod = m;
endCounter++;
}
if (beginCounter > 1) {
LOGGER.fatal("Only one Method could be used as BEGIN");
throw new RuntimeException("Only one Method could be used as BEGIN");
}
if (endCounter > 1) {
LOGGER.fatal("Only one Method could be used as END");
throw new RuntimeException("Only one Method could be used as END");
}
}
}
public void process(String inputFile) throws IOException, InvocationTargetException, IllegalAccessException {
long startTime = System.currentTimeMillis();
LOGGER.info("Start Process");
if (beginMethod != null) {
LOGGER.info("Running begin");
beginMethod.invoke(processor);
}
BufferedReader br = new BufferedReader(new FileReader(inputFile));
String line;
while ((line = br.readLine()) != null) {
String[] records = unpackLine(line);
boolean isMatch = false;
for (CaseHolder caseHolder : cases.values()) {
CSVCase csvCase = caseHolder.getCsvCase();
isMatch = false;
Pattern p = Pattern.compile(csvCase.regexp());
Matcher match;
switch (csvCase.matchType()) {
case LINE:
match = p.matcher(line);
break;
case FIELD:
match = p.matcher(records[csvCase.fieldToMatch()]);
break;
default:
LOGGER.fatal("Match type not found: " + csvCase.matchType());
throw new RuntimeException("Match time not found: " + csvCase.matchType());
}
Method method = caseHolder.getMethod();
LOGGER.info(method.getName() + ": " + csvCase.description());
if (match.matches()) {
isMatch = true;
LOGGER.info(" -> match!");
LOGGER.info(" -> LINE: " + line);
LOGGER.trace(" -> IN: " + Arrays.toString(records));
LineHolder lh = new LineHolder(line, records);
String[] outFields = (String[]) method.invoke(processor, lh);
LOGGER.trace(" -> OUT: " + Arrays.toString(records));
String outLine = packLine(outFields) + "\n";
switch (csvCase.type()) {
case FILE:
streams.get(csvCase.caseNum()).write(outLine.getBytes());
break;
case SYSTEM_ERR:
System.err.println(outLine);
break;
case SYSTEM_OUT:
System.out.println(outLine);
break;
default:
LOGGER.fatal("File output not valid: " + csvCase.type());
}
} else {
LOGGER.info(" -> NOT match!");
}
}
if (!isMatch) {
Method method = defaultMethod.getMethod();
CSVCase csvCase = defaultMethod.getCsvCase();
LOGGER.info(" -> default match!");
LOGGER.info(" -> LINE: " + line);
LOGGER.trace(" -> IN: " + Arrays.toString(records));
LineHolder lh = new LineHolder(line, records);
String[] outFields = (String[]) method.invoke(processor, lh);
LOGGER.trace(" -> OUT: " + Arrays.toString(records));
String outLine = packLine(outFields) + "\n";
switch (csvCase.type()) {
case FILE:
streams.get(csvCase.caseNum()).write(outLine.getBytes());
break;
case SYSTEM_ERR:
System.err.println(outLine);
break;
case SYSTEM_OUT:
System.out.println(outLine);
break;
default:
LOGGER.fatal("File output not valid: " + csvCase.type());
}
}
}
br.close();
for (OutputStream stream : streams.values()) {
stream.close();
LOGGER.trace("close stream");
}
if (endMethod != null) {
LOGGER.info("Running end");
endMethod.invoke(processor);
}
long time = System.currentTimeMillis() - startTime;
LOGGER.info("Process completed [" + time + " ms]");
}
private String[] unpackLine(String line) {
if (line == null) {
throw new IllegalArgumentException("Line could not be null");
}
String[] split = line.split(csvInformation.inputFieldSep());
if (split == null)
return new String[]{};
else
return split;
}
private String packLine(String[] records) {
if (records == null) {
throw new IllegalArgumentException("records could not be null");
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < records.length; i++) {
sb.append(records[i]);
if (i != records.length - 1) {
sb.append(csvInformation.outputFieldSep());
}
}
return sb.toString();
}
}