package org.dresdenocl.logging.appender;
import java.io.IOException;
import org.apache.log4j.Layout;
import org.apache.log4j.RollingFileAppender;
import org.eclipse.core.runtime.IPath;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* This class is a custom log4j appender that logs to a file in an Eclipse
* plugin's state location. It can be configured using the standard
* configuration options available for {@link RollingFileAppender}. The state
* location can either be provided using one of the overloaded constructors or
* by calling the {@link #setStateLocation(IPath)} method. The appender won't be
* {@link #activateOptions() activated} until the state location of the
* corresponding plugin has been {@link #setStateLocation(IPath) set}. Clients
* may extend this class to provide specialized behaviour.
*
* @author Matthias Braeuer (based on version by Manoel Marques)
*/
public class PluginLogFileAppender extends RollingFileAppender {
// the path to the plugin's state location
private IPath stateLocation;
// a flag indicating whether we still have to activate the appender
private boolean activateOptionsPending;
/**
* Creates a new PluginLogFileAppender.
*/
public PluginLogFileAppender() {
super();
}
/**
* Creates a new PluginLogFileAppender providing the plugin state location, a
* layout and the file name for the log file.
*
* @param layout the {@link Layout} instance to use
* @param stateLocation the path to the plug-in state location
* @param file the file name for the log file
*
* @throws IOException if an I/O error occurs
*/
public PluginLogFileAppender(Layout layout, IPath stateLocation,
String fileName) throws IOException {
this(layout, stateLocation, fileName, true);
}
/**
* Creates a new PluginLogFileAppender with a complete set of options.
*
* @param layout the {@link Layout} instance to use
* @param stateLocation the path to the plug-in state location
* @param file the file name for the log file
* @param append true if file is to be appended
*
* @throws IOException if an I/O error occurs
*/
public PluginLogFileAppender(Layout layout, IPath stateLocation,
String fileName, boolean append) throws IOException {
super(layout, fileName, append);
// set the state location and activate options
setStateLocation(stateLocation);
activateOptions();
}
/**
* Sets the state location. If {@link #activateOptions()} call is pending,
* translates the file name and calls {@link #activateOptions()}.
*
* @param stateLocation an <code>IPath</code> instance representing the
* plug-in state location
*/
public void setStateLocation(IPath stateLocation) {
// precondition check
if (stateLocation == null) {
throw new IllegalArgumentException("Parameter 'stateLocation' was null."); //$NON-NLS-1$
}
this.stateLocation = stateLocation;
// activate options if necessary
if (activateOptionsPending) {
activateOptionsPending = false;
setFile(getFile());
activateOptions();
}
}
/**
* Sets the file name for the log file. Overridden to resolve the file name in
* relation to the plugin's config directory once the state location has been
* set.
*
* @param file file name
*
* @see #setStateLocation(IPath)
*/
@Override
public void setFile(String file) {
// state location has not been set yet
if (stateLocation == null) {
super.setFile(file);
}
else {
super.setFile(getTranslatedFileName(file));
}
}
// helper method to resolve a file name relative to the plugin's state path
// any directory path names in the filename are discarded
protected String getTranslatedFileName(String fileName) {
// state check
if (stateLocation == null) {
throw new IllegalStateException(
"Plugin state location has not been set yet."); //$NON-NLS-1$
}
// precondition check
if (fileName == null) {
throw new IllegalArgumentException("The parameter 'fileName' was null."); //$NON-NLS-1$
}
// trim whitespace
fileName = fileName.trim();
// validity check
if (fileName.length() == 0) {
throw new IllegalArgumentException(
"The parameter 'fileName' consisted only of whitespace."); //$NON-NLS-1$
}
// find the last path segment of the file
int index = fileName.lastIndexOf('/');
if (index == -1) {
index = fileName.lastIndexOf('\\');
}
// get the file name
if (index != -1) {
fileName = fileName.substring(index + 1);
}
// append the file name to the state path
IPath filePath = stateLocation.append(fileName);
return filePath.toString();
}
/**
* Finishes instance initialization. If state location was not set, set
* activate as pending and does nothing.
*/
@Override
public void activateOptions() {
if (stateLocation == null) {
activateOptionsPending = true;
return;
}
super.activateOptions();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append(
"stateLocation", //$NON-NLS-1$
stateLocation)
.append("activateOptionsPending", activateOptionsPending).toString(); //$NON-NLS-1$
}
}