package org.epics.archiverappliance.mgmt.bpl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Small utility to sync the headers and footers from index.html to the other html files.
* Typically called from the build script on demand.
* This can also be used to do some simple site specific customization at startup time.
* <pre><code>Usage: java SyncStaticContentHeadersFooters <IndexFileName> <Locations of static html files></code></pre>
* @author mshankar
*
*/
public class SyncStaticContentHeadersFooters {
public static void main(String[] args) throws IOException {
if(args.length < 2) {
System.err.println("Usage: java SyncStaticContentHeadersFooters <IndexFileName> <Locations of other html files>");
return;
}
String srcFileName = args[0];
final File srcFile = new File(srcFileName);
String[] fileLocations = Arrays.copyOfRange(args, 1, args.length);
LinkedList<File> filesToModify = new LinkedList<File>();
for(String fileLocation : fileLocations) {
File fileLocationFile = new File(fileLocation);
if(fileLocationFile.isDirectory()) {
File[] htmlFiles = fileLocationFile.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".html") && !pathname.equals(srcFile)) {
return true;
}
return false;
}
});
for(File htmlFile : htmlFiles) filesToModify.add(htmlFile);
} else {
filesToModify.add(fileLocationFile);
}
}
LinkedList<TextChunk> srcTextChunks = breakFileIntoChunks(srcFile);
HashMap<String, String> mainSrcFileTextChunks = new HashMap<String, String>();
for(TextChunk textChunk : srcTextChunks) {
if(!textChunk.typeOfChunk.equals(REGULAR_TEXT)) {
mainSrcFileTextChunks.put(textChunk.typeOfChunk, textChunk.textChunk);
}
}
for(File fileToModify : filesToModify) {
System.out.println("Changing headers and footers for " + fileToModify.getAbsolutePath());
File outputFile = new File(fileToModify.getAbsolutePath().concat("_generated"));
try(PrintWriter out = new PrintWriter(new FileOutputStream(outputFile))) {
LinkedList<TextChunk> destTextChunks = breakFileIntoChunks(fileToModify);
for(TextChunk destTextChunk : destTextChunks) {
if(destTextChunk.typeOfChunk.equals(REGULAR_TEXT)) {
out.print(destTextChunk.textChunk);
} else {
String srcChunk = mainSrcFileTextChunks.get(destTextChunk.typeOfChunk);
if(srcChunk == null) {
out.print(destTextChunk.textChunk);
} else {
out.print(srcChunk);
}
}
}
}
if(outputFile.exists() && outputFile.length() > 0) {
Files.move(outputFile.toPath(), fileToModify.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
}
public static class TextChunk {
String typeOfChunk;
String textChunk;
public TextChunk(String typeOfChunk, String textChunk) {
this.typeOfChunk = typeOfChunk;
this.textChunk = textChunk;
}
}
private static final String REGULAR_TEXT = "RegularText";
/**
* Break down a file into a list of text chunks each of which is identified by the text string in the @begin(...) if any...
* Regular text chunks come as REGULAR_TEXT chunks
* @param file File
* @return LinkedList TextChunk
* @throws IOException
*/
public static LinkedList<TextChunk> breakFileIntoChunks(File file) throws IOException {
String startOfChunkIndicator = "<!-- @begin(";
String endOfChunkIndicator = "<!-- @end(";
FileInputStream fis = new FileInputStream(file);
return breakFileIntoChunks(fis, startOfChunkIndicator, endOfChunkIndicator);
}
/**
* Break down a file into a list of text chunks each of which is identified by the text string in the @begin(...) if any...
* Regular text chunks come as REGULAR_TEXT chunks
* This method closes the inputstream is after it is done.
* @param is InputStream
* @param startOfChunkIndicator
* @param endOfChunkIndicator
* @return LinkedList TextChunk
* @throws IOException
*/
public static LinkedList<TextChunk> breakFileIntoChunks(InputStream is, String startOfChunkIndicator, String endOfChunkIndicator) throws IOException {
LinkedList<TextChunk> textChunks = new LinkedList<TextChunk>();
String currentChunkType = REGULAR_TEXT;
StringBuffer currentTextChunk = new StringBuffer();
try(LineNumberReader lineReader = new LineNumberReader(new InputStreamReader(is))) {
String line = lineReader.readLine();
while(line != null) {
if(line.contains(startOfChunkIndicator)) {
if(currentTextChunk.length() > 0) {
textChunks.add(new TextChunk(currentChunkType, currentTextChunk.toString()));
currentTextChunk = new StringBuffer();
currentChunkType = REGULAR_TEXT;
}
currentTextChunk.append(line);
currentTextChunk.append("\n");
int startOfChunkType = line.indexOf(startOfChunkIndicator) + startOfChunkIndicator.length();
int endOfChunkType = line.indexOf(')', startOfChunkType);
currentChunkType = line.substring(startOfChunkType, endOfChunkType);
} else {
if(line.contains(endOfChunkIndicator)) {
currentTextChunk.append(line);
currentTextChunk.append("\n");
textChunks.add(new TextChunk(currentChunkType, currentTextChunk.toString()));
currentTextChunk = new StringBuffer();
currentChunkType = REGULAR_TEXT;
} else {
currentTextChunk.append(line);
currentTextChunk.append("\n");
}
}
line = lineReader.readLine();
}
}
textChunks.add(new TextChunk(currentChunkType, currentTextChunk.toString()));
return textChunks;
}
/**
* Breaks the HTML inputstream is into chunks and replaces the templates with the content in templateReplacements.
* The inputstream is is closed after this operation.
* @param is InputStream
* @param templateReplacements HashMap
* @return ByteArrayInputStream
* @throws IOException
*/
public static ByteArrayInputStream templateReplaceChunksHTML(InputStream is, HashMap<String, String> templateReplacements) throws IOException {
String startOfChunkIndicator = "<!-- @begin(";
String endOfChunkIndicator = "<!-- @end(";
String closingText = ") -->";
return templateReplaceChunks(is, templateReplacements, startOfChunkIndicator, endOfChunkIndicator, closingText);
}
/**
* Breaks the Javascript inputstream is into chunks and replaces the templates with the content in templateReplacements.
* The inputstream is is closed after this operation.
* @param is InputStream
* @param templateReplacements HashMap
* @return ByteArrayInputStream
* @throws IOException
*/
public static ByteArrayInputStream templateReplaceChunksJavascript(InputStream is, HashMap<String, String> templateReplacements) throws IOException {
String startOfChunkIndicator = "// @begin(";
String endOfChunkIndicator = "// @end(";
String closingText = ")";
return templateReplaceChunks(is, templateReplacements, startOfChunkIndicator, endOfChunkIndicator, closingText);
}
private static ByteArrayInputStream templateReplaceChunks(InputStream is, HashMap<String, String> templateReplacements, String startOfChunkIndicator, String endOfChunkIndicator, String closingText) throws IOException {
LinkedList<TextChunk> destTextChunks = SyncStaticContentHeadersFooters.breakFileIntoChunks(is, startOfChunkIndicator, endOfChunkIndicator);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(PrintWriter out = new PrintWriter(new OutputStreamWriter(bos))) {
for(TextChunk destTextChunk : destTextChunks) {
if(destTextChunk.typeOfChunk.equals(REGULAR_TEXT)) {
out.print(destTextChunk.textChunk);
} else {
String srcChunk = templateReplacements.get(destTextChunk.typeOfChunk);
if(srcChunk == null) {
out.print(destTextChunk.textChunk);
} else {
out.println(startOfChunkIndicator + destTextChunk.typeOfChunk + closingText);
out.println(srcChunk);
out.println(endOfChunkIndicator + destTextChunk.typeOfChunk + closingText);
}
}
}
}
return new ByteArrayInputStream(bos.toByteArray());
}
}