import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TemplateProcessor {
private static String slurpFile(File file) throws Exception {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int octet = 0;
while((octet = in.read())!= -1){
out.write(octet);
}
return out.toString("UTF-8");
}
private static String extractSnippet(String sourceFile) {
Pattern pattern = Pattern.compile(".*\\/\\*\\s*snippet\\s*\\*\\/(.*)\\/\\*\\s*snippet\\s*\\*\\/.*", Pattern.DOTALL | Pattern.MULTILINE);
Matcher matcher = pattern.matcher(sourceFile);
if(matcher.matches()) {
return matcher.group(1);
} else {
pattern = Pattern.compile(".*\\/\\/\\s*snippet\\s*(.*)\\/\\/\\s*snippet\\s*.*", Pattern.DOTALL | Pattern.MULTILINE);
matcher = pattern.matcher(sourceFile);
if(matcher.matches()) {
return matcher.group(1);
}
}
return "<font color='#ff0000'><i>Snippet not found</i></font>";
}
private static String fixJava(String text) {
return text.replaceAll("public static class", "public class").replaceAll("private static class", "public class");
}
private static String removeIndentation(String text) {
List<String> lines = LineStripper.stripLines(text);
int minimum = 10000;
String indent = "";
Pattern pattern = Pattern.compile("(\\s*).*");
for(String line : lines) {
Matcher matcher = pattern.matcher(line);
if(matcher.matches()) {
if(line.matches(".*\\w+.*")) { // only conider real code lines
String indentText = matcher.group(1);
int length = indentText.length();
if(length < minimum) {
minimum = length;
indent = indentText;
}
}
}
}
StringBuilder builder = new StringBuilder();
for(String line : lines) {
if(line.indexOf(indent) != -1) {
line = line.substring(minimum);
}
builder.append(line);
builder.append("\r\n");
}
return builder.toString().trim();
}
private static String indentText(String text, String indent) {
List<String> lines = LineStripper.stripLines(text);
StringBuilder builder = new StringBuilder();
builder.append(indent);
builder.append("\r\n");
for(String line : lines) {
builder.append(indent);
builder.append(line);
builder.append("\r\n");
}
return builder.toString();
}
private static String replaceVariable(String sourceFile, String text, String variableName) {
try {
return sourceFile.replace("${"+variableName+"}", text);
}catch(Exception e) {
throw new RuntimeException(variableName, e);
}
}
private static String escapeHtml(String text) {
return text.replaceAll(">", ">").replaceAll("<", "<");
}
// java TemplateProcessor ./template.xml ./examples/.
public static void main(String[] list) throws Exception {
if(list.length != 3) {
System.out.println("Incorrect arguments, length=["+list.length+"]");
System.exit(-1);
}
final File baseDir = new File(list[0]);
final File wholeFileTemplate = new File(list[1]);
final File outputResultFile = new File(list[2]);
final File[] fileList = baseDir.listFiles(new ExampleDirFilter());
final SortedSet<File> sortedFileSet = new TreeSet<File>(new ExampleDirComparator());
for(File file : fileList) {
if(file.isDirectory()) {
sortedFileSet.add(file);
}
}
System.out.println("Sorted as:"+sortedFileSet);
final List<String> exampleHtmlList = new ArrayList<String>();
final String wholeFileTemplateText = slurpFile(wholeFileTemplate);
for(File file : sortedFileSet) {
if(file.isDirectory()) {
String fileName = file.getName();
String javaFileName = "E" + fileName.substring(1);
File templateFile = new File(file,fileName + ".template.html");
if(templateFile.exists()) {
final String templateSource = slurpFile(templateFile);
final File sourceFile = new File(file, javaFileName + ".java");
final File xmlFile = new File(file, fileName + ".xml");
final File outputFile = new File(file, fileName + ".html");
final FileWriter outputWriter = new FileWriter(outputFile);
final String xmlSource = slurpFile(xmlFile);
final String javaSource = fixJava(slurpFile(sourceFile));
final String javaSnippet = removeIndentation(extractSnippet(javaSource));
String html = replaceVariable(templateSource, escapeHtml(xmlSource), "xmlSnippet");
html = replaceVariable(html, escapeHtml(javaSnippet), "javaSnippet");
html = replaceVariable(html, fileName+"/"+fileName+".zip", "downloadLink");
outputWriter.write(html);
outputWriter.close();
exampleHtmlList.add(html);
} else {
System.out.println("No template file exists for "+templateFile.getCanonicalPath());
}
}
}
StringBuilder fullContent = new StringBuilder();
for(String html : exampleHtmlList) {
fullContent.append(html);
}
String fullFile = replaceVariable(wholeFileTemplateText, fullContent.toString(), "content");
FileWriter w = new FileWriter(outputResultFile);
w.write(fullFile);
w.close();
}
private static class ExampleDirFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
return name.matches(".*example\\d+") && dir.isDirectory();
}
}
public static class LineStripper {
public static List<String> stripLines(InputStream text) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] chunk = new byte[8192];
int count = 0;
while ((count = text.read(chunk)) != -1) {
out.write(chunk, 0, count);
}
text.close();
return stripLines(out.toString("UTF-8"));
}
public static List<String> stripLines(String text) {
List<Token> list = new LinkedList<Token>();
char[] array = text.toCharArray();
int start = 0;
while(start < array.length) {
Token line = nextLine(array, start);
list.add(line);
start += line.length;
}
List<String> lines = new ArrayList<String>(list.size() + 1);
for(Token token : list) {
lines.add(token.toString());
}
return lines;
}
private static Token nextLine(char[] text, int startFrom) {
for(int i = startFrom; i < text.length; i++) {
if(text[i] == '\r') {
if(i + 1 < text.length && text[i + 1] == '\n') {
i++;
}
return new Token(text, startFrom, ++i - startFrom);
}
if(text[i] == '\n') {
return new Token(text, startFrom, ++i - startFrom);
}
}
return new Token(text, startFrom, text.length - startFrom);
}
private static class Token {
private final char[] source;
private final int start;
private final int length;
public Token(char[] source, int start, int length) {
this.source = source;
this.start = start;
this.length = length;
}
@Override
public String toString() {
for(int i = length - 1; i >= 0; i--) {
if(!Character.isWhitespace(source[start + i])) {
return new String(source, start, i + 1);
}
}
return "";
}
}
}
private static class ExampleDirComparator implements Comparator<File> {
public int compare(File o1, File o2) {
String name1 = o1.getName();
String name2 = o2.getName();
Pattern extractDigits = Pattern.compile("example(\\d+)");
Matcher matcher1 = extractDigits.matcher(name1);
if(matcher1.matches()) {
Matcher matcher2 = extractDigits.matcher(name2);
if(matcher2.matches()) {
Integer int1 = Integer.parseInt(matcher1.group(1));
Integer int2 = Integer.parseInt(matcher2.group(1));
return int1.compareTo(int2);
}
}
return name1.compareTo(name2);
}
}
}