// Copyright 2012 Georg-August-Universität Göttingen, Germany
//
// 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.
package de.ugoe.cs.autoquest.plugin.html;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.xml.sax.SAXException;
import de.ugoe.cs.util.StringTools;
import de.ugoe.cs.util.console.Console;
/**
*
* TODO comment
*
*
* @author Fabian Glaser, Patrick Harms
* @version 1.0
*
*/
public class HTMLLogCompressor extends AbstractDefaultLogParser {
/**
*
*/
private PrintWriter outputWriter;
/**
* the GUI elements, that were already logged and need therefore not be logged again into
* the same file
*/
private Set loggedGUIElementIds = new HashSet();
/**
* the events that were read
*/
private List sortedEvents = new LinkedList();
/**
*
*/
public void compressFilesInDirectory(String directory) {
if (directory == null) {
throw new IllegalArgumentException("directory must not be null");
}
compressFilesInDirectory(new File(directory));
}
/**
*
*/
public void compressFilesInDirectory(File directory) {
if (directory == null) {
throw new IllegalArgumentException("directory must not be null");
}
if (!directory.exists()) {
throw new IllegalArgumentException("directory must denote an existing directory");
}
if (!directory.isDirectory()) {
throw new IllegalArgumentException("directory must denote a directory");
}
File[] files = directory.listFiles();
if ((files == null) || (files.length == 0)) {
Console.println("directory is empty");
return;
}
File outFile = null;
int logFileIndex = -1;
do {
outFile = new File(directory, getLogFileName(directory.getName(), logFileIndex));
logFileIndex++;
}
while (outFile.exists());
List compressedFiles = new LinkedList();
try {
FileOutputStream fis = new FileOutputStream(outFile);
outputWriter = new PrintWriter(new OutputStreamWriter(fis, "UTF-8"));
outputWriter.println("");
outputWriter.println("");
loggedGUIElementIds.clear();
sortedEvents.clear();
for (File file : files) {
if (file.isFile()) {
try {
super.parseFile(file);
Console.println("compressed " + file);
compressedFiles.add(file);
}
catch (Exception e) {
Console.printerrln("could not parse and compress file " + file);
}
}
}
for (EventEntry event : sortedEvents) {
event.dump();
}
outputWriter.println("");
outputWriter.flush();
}
catch (FileNotFoundException e) {
Console.printerrln("could not create compressed file " + outFile);
compressedFiles.clear();
}
catch (UnsupportedEncodingException e) {
// this should never happen
e.printStackTrace();
compressedFiles.clear();
}
finally {
if (outputWriter != null) {
outputWriter.close();
outputWriter = null;
}
}
for (File file : compressedFiles) {
if (!file.delete()) {
Console.printerrln("could not delete compressed file " + file);
}
}
if (outFile.exists()) {
File finalOutFile = null;
logFileIndex = -1;
do {
logFileIndex++;
finalOutFile =
new File(directory, getLogFileName(directory.getName(), logFileIndex));
}
while (finalOutFile.exists());
outFile.renameTo(finalOutFile);
Console.println("created " + finalOutFile);
}
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#parseFile(java.lang.String)
*/
@Override
public void parseFile(String filename) {
throw new IllegalStateException("this method must not be called externally");
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#parseFile(java.io.File)
*/
@Override
public void parseFile(File file) {
throw new IllegalStateException("this method must not be called externally");
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleGUIElement(String, Map)
*/
@Override
protected boolean handleGUIElement(String id, Map parameters)
throws SAXException
{
if (!loggedGUIElementIds.contains(id)) {
outputWriter.print("");
for (Map.Entry param : parameters.entrySet()) {
dumpParam(param.getKey(), param.getValue());
}
outputWriter.println("");
loggedGUIElementIds.add(id);
}
return true;
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(java.lang.String, java.util.Map)
*/
@Override
protected boolean handleEvent(String type, Map parameters) throws SAXException {
String timestampStr = parameters.get("timestamp");
long timestamp = Long.MAX_VALUE;
if (timestampStr != null) {
timestamp = Long.parseLong(timestampStr);
}
EventEntry newEvent = new EventEntry(type, parameters, timestamp);
boolean added = false;
for (int i = 0; i < sortedEvents.size(); i++) {
if (sortedEvents.get(i).timestamp > newEvent.timestamp) {
sortedEvents.add(i, newEvent);
added = true;
break;
}
}
if (!added) {
sortedEvents.add(newEvent);
}
return true;
}
/**
*
* dumps a parameter with the given name and value to the log file. The result is a
* tag named param with a name attribute and a value attribute. The value is transformed
* to a String if it is no String already. Furthermore, an XML entity replacement is performed
* if required.
*
*
* @param name the name of the parameter to be dumped
* @param value the value of the parameter to be dumped
*/
private void dumpParam(String name, Object value) {
if (value == null) {
return;
}
String val;
if (value instanceof String) {
val = (String) value;
}
else {
val = String.valueOf(value);
}
outputWriter.print(" ");
}
/**
*
* used to calculate a log file name. If the provided index is smaller 0, then no index
* is added to the file name. A filename is e.g. "htmlmonitor_12345_001.log".
*
*
* @param index the index of the log file or -1 one, if no index shall be added
*
* @return the file name as described
*/
private String getLogFileName(String clientId, int index) {
String result = "htmlmonitor_" + clientId;
if (index >= 0) {
result += "_" + new DecimalFormat("000" ).format(index);
}
result += ".log";
return result;
}
/**
*
*/
private class EventEntry {
/**
*
*/
private String type;
/**
*
*/
private Map parameters;
/**
*
*/
private long timestamp;
/**
*
* TODO: comment
*
*
* @param type
* @param parameters
* @param timestamp
*/
private EventEntry(String type, Map parameters, long timestamp) {
this.type = type;
this.parameters = parameters;
this.timestamp = timestamp;
}
/**
*
*/
private void dump() {
outputWriter.print("");
for (Map.Entry param : parameters.entrySet()) {
dumpParam(param.getKey(), param.getValue());
}
outputWriter.println("");
}
}
}