blob: d22e13450ac4f8003c90ef2836fb2d4e09753423 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.defaultadaptor;
import java.io.*;
import java.util.Date;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.framework.util.SecureAction;
import org.osgi.framework.*;
public class DefaultLog implements FrameworkLog {
protected boolean newSession = true;
protected static final String SESSION = "!SESSION"; //$NON-NLS-1$
protected static final String ENTRY = "!ENTRY"; //$NON-NLS-1$
protected static final String SUBENTRY = "!SUBENTRY"; //$NON-NLS-1$
protected static final String MESSAGE = "!MESSAGE"; //$NON-NLS-1$
protected static final String STACK = "!STACK"; //$NON-NLS-1$
protected static final String LINE_SEPARATOR;
protected static final String TAB_STRING = "\t"; //$NON-NLS-1$
protected boolean consoleLog = false;
static {
String s = System.getProperty("line.separator"); //$NON-NLS-1$
LINE_SEPARATOR = s == null ? "\n" : s; //$NON-NLS-1$
}
/**
* The File object to store messages. This value may be null.
*/
protected File outFile;
/**
* The Writer to log messages to.
*/
protected Writer writer;
/**
* The default constructor for DefaultLog. Constructs a DefaultLog
* that uses System.err to log messages to.
*/
public DefaultLog() {
this((Writer) null);
}
/**
* Constructs a DefaultLog that uses the specified Writer to log messages
* to. If the Writer is null then System.err is used to log messages to.
* @param writer The Writer to log messages to or null if System.err is
* to be used.
*/
public DefaultLog(Writer writer) {
if (writer == null)
// log to System.err by default
this.writer = logForStream(System.err);
else
this.writer = writer;
}
/**
* Constructs a DefaultLog that uses the specified File to create
* a FileWriter to log messages to. Log messages will be appended to
* the specified File.
* @param outFile The File to log messages to.
*/
public DefaultLog(File outFile) {
this.outFile = outFile;
this.writer = null;
}
/**
* Closes the FrameworkLog.
*/
public void close() {
try {
if (writer != null) {
Writer tmpWriter = writer;
writer = null;
tmpWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
protected void openFile() {
if (writer == null) {
if (outFile != null) {
try {
writer = logForStream(SecureAction.getFileOutputStream(outFile, true));
} catch (IOException e) {
writer = logForStream(System.err);
}
} else {
writer = logForStream(System.err);
}
}
}
protected void closeFile() {
if (outFile != null) {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
writer = null;
}
}
}
public void log(FrameworkEvent frameworkEvent) {
Bundle b = frameworkEvent.getBundle();
Throwable t = frameworkEvent.getThrowable();
FrameworkLogEntry logEntry = new FrameworkLogEntry(b.getLocation() + " 0 0", "FrameworkEvent.ERROR", 0, t, null);
log(logEntry);
}
public synchronized void log(FrameworkLogEntry logEntry) {
if (logEntry == null)
return;
try {
openFile();
if (newSession) {
writeSession();
newSession = false;
}
writeLog(0, logEntry);
writer.flush();
} catch (Exception e) {
// any exceptions during logging should be caught
System.err.println("An exception occurred while writing to the platform log:");//$NON-NLS-1$
e.printStackTrace(System.err);
System.err.println("Logging to the console instead.");//$NON-NLS-1$
//we failed to write, so dump log entry to console instead
try {
writer = logForStream(System.err);
writeLog(0, logEntry);
writer.flush();
} catch (Exception e2) {
System.err.println("An exception occurred while logging to the console:");//$NON-NLS-1$
e2.printStackTrace(System.err);
}
} finally {
closeFile();
}
}
public synchronized void setWriter(Writer newWriter, boolean append) {
setOutput(null, newWriter, append);
}
public synchronized void setFile(File newFile, boolean append) throws IOException {
setOutput(newFile, null, append);
}
public synchronized File getFile() {
return outFile;
}
public void setConsoleLog(boolean consoleLog) {
this.consoleLog = consoleLog;
}
private void setOutput(File newOutFile, Writer newWriter, boolean append) {
if (newOutFile == null || !newOutFile.equals(this.outFile)) {
if (this.writer != null) {
try {
this.writer.close();
} catch (IOException e) {
e.printStackTrace();
}
this.writer = null;
}
// Append old outFile to newWriter. We only attempt to do this
// if the current Writer is backed by a File and this is not
// a new session.
File oldOutFile = this.outFile;
this.outFile = newOutFile;
this.writer = newWriter;
boolean copyFailed = false;
if (append && oldOutFile != null && oldOutFile.isFile()) {
Reader fileIn = null;
try {
openFile();
fileIn = new InputStreamReader(SecureAction.getFileInputStream(oldOutFile), "UTF-8");
copyReader(fileIn, this.writer);
} catch (IOException e) {
copyFailed = true;
e.printStackTrace();
} finally {
if (fileIn != null) {
try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
// delete the old file if copying didn't fail
if (!copyFailed)
oldOutFile.delete();
}
closeFile();
}
}
}
}
private void copyReader(Reader reader, Writer writer) throws IOException {
char buffer[] = new char[1024];
int count;
while ((count = reader.read(buffer, 0, buffer.length)) > 0) {
writer.write(buffer, 0, count);
}
}
protected String getDate() {
return new Date().toString();
}
protected String getStackTrace(Throwable t) {
if (t == null)
return null;
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
if (t instanceof BundleException) {
Throwable n = ((BundleException) t).getNestedException();
if (n != null) {
pw.println("Nested exception:");
n.printStackTrace(pw);
}
}
return sw.toString();
}
protected Writer logForStream(OutputStream output) {
try {
return new BufferedWriter(new OutputStreamWriter(output, "UTF-8")); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
return new BufferedWriter(new OutputStreamWriter(output));
}
}
protected void writeLog(int depth, FrameworkLogEntry entry) throws IOException {
writeEntry(depth, entry);
writeMessage(entry);
writeStack(entry);
FrameworkLogEntry[] children = entry.getChildren();
if (children != null) {
for (int i = 0; i < children.length; i++) {
writeLog(depth + 1, children[i]);
}
}
}
protected void writeSession() throws IOException {
write(SESSION);
writeSpace();
String date = getDate();
write(date);
writeSpace();
for (int i = SESSION.length() + date.length(); i < 78; i++) {
write("-"); //$NON-NLS-1$
}
writeln();
// Write out certain values found in System.getProperties()
try {
String key = "java.fullversion"; //$NON-NLS-1$
String value = System.getProperty(key);
if (value == null) {
key = "java.version"; //$NON-NLS-1$
value = System.getProperty(key);
writeln(key + "=" + value); //$NON-NLS-1$
key = "java.vendor"; //$NON-NLS-1$
value = System.getProperty(key);
writeln(key + "=" + value); //$NON-NLS-1$
} else {
writeln(key + "=" + value); //$NON-NLS-1$
}
} catch (Exception e) {
// If we're not allowed to get the values of these properties
// then just skip over them.
}
}
protected void writeEntry(int depth, FrameworkLogEntry entry) throws IOException {
if (depth == 0) {
write(ENTRY);
} else {
write(SUBENTRY);
writeSpace();
write(Integer.toString(depth));
}
writeSpace();
write(entry.getEntry());
writeSpace();
write(getDate());
writeln();
}
protected void writeMessage(FrameworkLogEntry entry) throws IOException {
write(MESSAGE);
writeSpace();
writeln(entry.getMessage());
}
protected void writeStack(FrameworkLogEntry entry) throws IOException {
Throwable t = entry.getThrowable();
if (t != null) {
String stack = getStackTrace(t);
write(STACK);
writeSpace();
write(Integer.toString(entry.getStackCode()));
writeln();
write(stack);
}
}
protected void write(String message) throws IOException {
if (message != null) {
writer.write(message);
if (consoleLog)
System.out.print(message);
}
}
protected void writeln(String s) throws IOException {
write(s);
writeln();
}
protected void writeln() throws IOException {
write(LINE_SEPARATOR);
}
protected void writeSpace() throws IOException {
write(" "); //$NON-NLS-1$
}
}