blob: 416b7fc47061e8579fe0f0bd165d8d956dbeb53c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.core.vpg;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* VPG error/warning log.
*
* @author Jeff Overbey
* @author Kurt Hendle
*
* @param <T> token type
* @param <R> {@link IVPGNode}/{@link NodeRef} type
*
* @since 1.0
*/
public final class VPGLog<T, R extends IVPGNode<T>>
{
public class Entry
{
private boolean isWarning;
private String message;
private R tokenRef;
/** @since 3.0 */
public Entry(boolean isWarningOnly, String message, R tokenRef)
{
this.isWarning = isWarningOnly;
this.message = message;
this.tokenRef = tokenRef;
}
///////////////////////////////////////////////////////////////////////////
// Accessors
///////////////////////////////////////////////////////////////////////////
/** @return true iff this in a warning entry */
public boolean isWarning()
{
return isWarning;
}
/** @return true iff this is an error entry */
public boolean isError()
{
return !isWarning;
}
/** @return the message to display to the user */
public String getMessage()
{
return message;
}
/** @return the token associated with this error message, or <code>null</code>
* @since 3.0*/
public R getTokenRef()
{
return tokenRef;
}
}
///////////////////////////////////////////////////////////////////////////
// Fields
///////////////////////////////////////////////////////////////////////////
/** @since 3.0 */
protected final File logFile;
/** @since 3.0 */
protected IVPGComponentFactory<?, T, R> locator;
///////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////
/**
* @since 3.0
*/
public VPGLog(File logFile, IVPGComponentFactory<?, T, R> locator)
{
this.logFile = logFile;
this.locator = locator;
}
///////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////
/** The entries in the log */
protected List<Entry> log = new ArrayList<Entry>();
/** Clears the error/warning log. */
public void clear()
{
log.clear();
notifyListeners();
}
/** Removes all entries for the given file from the error/warning log. */
public void clearEntriesFor(String filename)
{
List<Entry> newLog = new LinkedList<Entry>();
// Iterate using indices to avoid ConcurrentModificationException
for (int i = 0; i < log.size(); i++)
{
Entry entry = log.get(i);
R tokenRef = entry.getTokenRef();
if (tokenRef == null || !tokenRef.getFilename().equals(filename))
newLog.add(entry);
}
log = newLog;
notifyListeners();
}
/**
* Adds the given warning to the error/warning log.
*
* @param message the warning message to display to the user
*/
public void logWarning(String message)
{
log.add(new Entry(true, message, null));
notifyListeners();
}
/**
* Adds the given warning to the error/warning log.
*
* @param message the warning message to display to the user
* @param filename the file with which the warning is associated
*/
public void logWarning(String message, String filename)
{
log.add(new Entry(true, message, locator.getVPGNode(filename, 0, 0)));
notifyListeners();
}
/**
* Adds the given warning to the error/warning log.
*
* @param message the warning message to display to the user
* @param tokenRef a specific token with which the warning is associated;
* for example, if an identifier was used without being
* initialized, it could reference that identifier
* @since 3.0
*/
public void logWarning(String message, R tokenRef)
{
log.add(new Entry(true, message, tokenRef));
notifyListeners();
}
/**
* Adds the given error to the error/warning log.
*
* @param e an exception that will be displayed to the user
*/
public void logError(Throwable e)
{
logError(e, null);
}
/**
* Adds the given error to the error/warning log.
*
* @param e an exception that will be displayed to the user
* @param tokenRef a specific token with which the warning is associated;
* for example, if an identifier was used without being
* initialized, it could reference that identifier
* @since 3.0
*/
public void logError(Throwable e, R tokenRef)
{
StringBuilder sb = new StringBuilder();
sb.append(e.getClass().getName());
sb.append(": "); //$NON-NLS-1$
sb.append(e.getMessage());
sb.append("\n"); //$NON-NLS-1$
ByteArrayOutputStream bs = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bs));
sb.append(bs);
log.add(new Entry(false, sb.toString(), tokenRef));
notifyListeners();
}
/**
* Adds the given error to the error/warning log.
*
* @param message the error message to display to the user
*/
public void logError(String message)
{
log.add(new Entry(false, message, null));
notifyListeners();
}
// /**
// * Adds the given error to the error/warning log.
// *
// * @param message the error message to display to the user
// * @param filename the file with which the warning is associated
// */
// public void logError(String message, String filename)
// {
// log.add(new Entry(false, message, createTokenRef(filename, 0, 0)));
// notifyListeners();
// }
/**
* Adds the given error to the error/warning log.
*
* @param message the error message to display to the user
* @param tokenRef a specific token with which the error is associated;
* for example, if an identifier was used but not
* declared, it could reference that identifier
* @since 3.0
*/
public void logError(String message, R tokenRef)
{
log.add(new Entry(false, message, tokenRef));
notifyListeners();
}
/** @return true iff at least one error exists in the error/warning log */
public boolean hasErrorsLogged()
{
for (int i = 0; i < log.size(); i++)
if (log.get(i).isError())
return true;
return false;
}
/** @return true iff at least one entry exists in the error/warning log */
public boolean hasErrorsOrWarningsLogged()
{
return !log.isEmpty();
}
/** @return the error/warning log */
public List<Entry> getEntries()
{
return log;
}
/** Prints the error/warning log on the given <code>PrintStream</code> */
public void printOn(PrintStream out)
{
for (int i = 0; i < log.size(); i++)
{
Entry entry = log.get(i);
out.print(entry.isError() ? Messages.VPGLog_ErrorLabel : Messages.VPGLog_WarningLabel);
out.println(entry.getMessage());
R t = entry.getTokenRef();
if (t != null)
{
out.print(
Messages.bind(
Messages.VPGLog_FilenameOffsetLength,
new Object[] { t.getFilename(), t.getOffset(), t.getLength() }));
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Listener Support
////////////////////////////////////////////////////////////////////////////////
/**
* An object which acts as an Observer [GoF] on the VPG error/warning log.
*
* @author Jeff Overbey
*/
public static interface ILogListener
{
/** Callback method invoked when the VPG error/warning log changes. */
void onLogChange();
}
private Set<ILogListener> listeners = new HashSet<ILogListener>();
/** Adds the given object as a Observer [GoF] of the VPG error/warning log */
public void addLogListener(ILogListener listener)
{
listeners.add(listener);
listener.onLogChange();
}
/** Removes the given object as a Observer [GoF] of the VPG error/warning log */
public void removeLogListener(ILogListener listener)
{
listeners.remove(listener);
}
protected void notifyListeners()
{
for (ILogListener listener : listeners)
listener.onLogChange();
}
////////////////////////////////////////////////////////////////////////////////
// Persistence Support
////////////////////////////////////////////////////////////////////////////////
private static final String EOL = System.getProperty("line.separator"); //$NON-NLS-1$
private static final String EOL_ESCAPE = "&EOL;"; //$NON-NLS-1$
/**
* Writes the log to a file.
* @since 2.0
*/
public void writeToFile() throws IOException
{
Writer output = new BufferedWriter(new FileWriter(logFile));
try
{
R tokenRef = null;
for (int i = 0; i < log.size(); i++)
{
Entry entry = log.get(i);
output.write(Boolean.toString(entry.isWarning())+
EOL);
tokenRef = entry.getTokenRef();
if (tokenRef == null)
output.write(EOL);
else
output.write(tokenRef.getFilename() + "," + //$NON-NLS-1$
Integer.toString(tokenRef.getOffset()) + "," + //$NON-NLS-1$
Integer.toString(tokenRef.getLength()) +
EOL);
output.write(entry.getMessage().replaceAll(EOL, EOL_ESCAPE) + EOL);
}
}
finally
{
output.close();
}
}
/**
* Reads the log which from a file back into memory.
* <p>
* Log entries have the format:
* <pre>
* isWarning
* TokenRef filename, offset, length
* message
* </pre>
* @since 2.0
*/
public void readLogFromFile()
{
try
{
FileInputStream fstream = new FileInputStream(logFile);
BufferedReader bRead = new BufferedReader(new InputStreamReader(fstream));
clear();
String line;
while ((line = bRead.readLine()) != null)
{
boolean isWarning = Boolean.parseBoolean(line);
//read tokenRef values
line = bRead.readLine();
R tokenRef;
if (line.trim().equals("")) //$NON-NLS-1$
{
tokenRef = null;
}
else
{
String[] tokenRefString = line.split("\\,"); //$NON-NLS-1$
tokenRef = locator.getVPGNode(
tokenRefString[0],
Integer.parseInt(tokenRefString[1]),
Integer.parseInt(tokenRefString[2]));
}
//read message
line = bRead.readLine();
log.add(new Entry(isWarning, line.replaceAll(EOL_ESCAPE, EOL), tokenRef));
}
bRead.close();
fstream.close();
}
catch (Exception e)
{
return;
}
finally
{
notifyListeners();
}
}
}