package org.holoeverywhere.resbuilder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.holoeverywhere.resbuilder.type.strings.TypeStrings;
import org.holoeverywhere.resbuilder.type.styles.TypeStyles;
import org.json.JSONObject;
public class FileProcesser {
public static class FileProcesserException extends Exception {
private static final long serialVersionUID = 3229067373448702029L;
public FileProcesserException(String message) {
super(message);
}
public FileProcesserException(Throwable cause) {
super(cause);
}
}
public static class ProcessResult extends ArrayList<ProcessResult> {
private static final class WriterState {
private File file;
private StringWriter tempWriter;
private XMLStreamWriter writer;
}
private static final long serialVersionUID = 6761878269956927443L;
private static final Transformer TRANSFORMER;
private static final TransformerFactory TRANSFORMER_FACTORY;
private static final Map<File, WriterState> WRITERS_MAP = new HashMap<File, WriterState>();
private static final XMLOutputFactory XML_OUTPUT_FACTORY;
static {
XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
TRANSFORMER_FACTORY = TransformerFactory.newInstance();
Transformer transformer = null;
try {
transformer = TRANSFORMER_FACTORY.newTransformer();
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
} catch (TransformerConfigurationException e) {
e.printStackTrace();
}
TRANSFORMER = transformer;
}
protected void close(BuildMojo mojo) throws FileProcesserException {
for (ProcessResult child : this) {
child.close(mojo);
}
try {
synchronized (WRITERS_MAP) {
for (WriterState state : WRITERS_MAP.values()) {
state.writer.writeEndElement();
state.writer.writeEndDocument();
state.writer.flush();
state.writer.close();
TRANSFORMER.transform(
new StreamSource(new StringReader(state.tempWriter.toString())),
new StreamResult(new FileOutputStream(state.file)));
}
WRITERS_MAP.clear();
}
} catch (Exception e) {
throw new FileProcesserException(e);
}
}
@SuppressWarnings("unchecked")
public <T extends ProcessResult> T find(Class<T> clazz) {
if (clazz.isAssignableFrom(getClass())) {
return (T) this;
}
T result;
for (ProcessResult child : this) {
result = child.find(clazz);
if (result != null) {
return result;
}
}
return null;
}
public void flush(BuildMojo mojo) throws FileProcesserException {
for (ProcessResult child : this) {
child.flush(mojo);
}
close(mojo);
}
protected XMLStreamWriter openWriter(BuildMojo mojo, File dir, String filename)
throws FileProcesserException {
try {
if (dir == null) {
dir = mojo.outputDir;
}
if (!dir.exists()) {
if (mojo.verbose) {
mojo.getLog().info("Create new folder: " + dir.getAbsolutePath());
}
dir.mkdirs();
}
File file = new File(dir, filename);
WriterState state;
synchronized (WRITERS_MAP) {
state = WRITERS_MAP.get(file);
if (state == null) {
if (mojo.verbose) {
mojo.getLog().info(" # Flush data to file " + file.getAbsolutePath());
}
state = new WriterState();
state.file = file;
state.tempWriter = new StringWriter();
state.writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(state.tempWriter);
state.writer.writeStartDocument("utf-8", "1.0");
state.writer.writeStartElement("resources");
WRITERS_MAP.put(file, state);
}
}
return state.writer;
} catch (Exception e) {
throw new FileProcesserException(e);
}
}
}
private static final Map<String, TypeProcesser> PROCESSERS_MAP;
static {
PROCESSERS_MAP = new HashMap<String, TypeProcesser>();
registerProcesser(TypeStrings.class);
registerProcesser(TypeStyles.class);
}
public static void process(BuildMojo mojo) throws FileProcesserException {
new FileProcesser(mojo).process();
}
public static void registerProcesser(Class<? extends TypeProcesser> clazz) {
try {
TypeProcesser processer = clazz.newInstance();
PROCESSERS_MAP.put(processer.getType(), processer);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private BuildMojo mojo;
public FileProcesser(BuildMojo mojo) {
setMojo(mojo);
}
public BuildMojo getMojo() {
return mojo;
}
public void process() throws FileProcesserException {
ProcessResult result = new ProcessResult();
for (String input : mojo.inputFiles) {
result.add(process(input));
}
result.flush(mojo);
}
@SuppressWarnings("unchecked")
public ProcessResult process(File file) throws FileProcesserException {
try {
mojo.getLog().info("Process file: " + file.getAbsolutePath());
String fileContent = readFile(file);
JSONObject json = new JSONObject(fileContent);
if (file.getName().startsWith("key_")) {
String key = file.getName();
int c = key.lastIndexOf('.');
key = key.substring(4, c > 0 ? c : key.length());
mojo.getLog().info("Handle all file by key '" + key + "'");
return process(key, json);
}
ProcessResult result = new ProcessResult();
Iterator<String> keys = json.sortedKeys();
while (keys.hasNext()) {
String key = keys.next();
ProcessResult subResult = process(key, json.optJSONObject(key));
if (subResult != null) {
result.add(subResult);
}
}
return result;
} catch (Exception e) {
throw new FileProcesserException(e);
}
}
public ProcessResult process(String filename) throws FileProcesserException {
File file;
for (File includeDir : mojo.includeDirs) {
file = new File(includeDir, filename);
if (file.exists()) {
return process(file);
}
}
if ((file = new File(filename)).exists()) {
return process(file);
}
throw new FileProcesserException("Couldn't find file for processing: " + filename);
}
public ProcessResult process(String key, JSONObject json) throws FileProcesserException {
TypeProcesser processer = PROCESSERS_MAP.get(key);
if (processer == null) {
mojo.getLog().warn(" # Couldn't find processer for key '" + key + "', skip");
return null;
}
mojo.getLog().info(" # Handle key '" + key + "' to processer '" + processer.getName()
+ "'");
ProcessResult subResult = processer.process(mojo, json);
if (subResult == null) {
String message = "Processer " + processer.getClass().getName()
+ " return null result";
mojo.getLog().error(" # " + message);
throw new FileProcesserException(message);
} else {
return subResult;
}
}
private String readFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
Reader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
StringBuilder builder = new StringBuilder();
char[] buffer = new char[1024];
int c;
while ((c = reader.read(buffer)) > 0) {
builder.append(buffer, 0, c);
}
reader.close();
is.close();
return builder.toString();
}
public void setMojo(BuildMojo mojo) {
this.mojo = mojo;
this.mojo.processer = this;
}
}