/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.engine.impl.log;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import org.apache.sling.engine.RequestLog;
/**
* The <code>FileRequestLog</code> class is an implementation of the
* {@link RequestLog} interface writing the log messages to an plain file. This
* class supports sharing the files for different log formatters, in that an
* internal map of log files is kept and access to the <code>PrintWriter</code>s
* to write to the file is synchronized.
* <p>
* This class has a defined lifecycle to ensure correct operation: To ensure no
* log files are kept open, the {@link RequestLoggerFilter} object calls
* {@link #dispose()} when it is being deactivated.
* <p>
* Note: Currently, each log file is kept open from the moment the log file is
* first moment until the {@link #dispose()} method is called. Future
* development should probably focus on the following issues: (1) Implement an
* open/write/close cycle when logging a message, (2) close log files when the
* last user has closed the log, (3) optimize the first strategy by keeping the
* files open for some time.
* <p>
* Note: Currently, the <code>PrintWriter</code> used to log the message is
* flushed after each log message written. Future development should probably
* implement better buffering in conjunction with the temporary open/close
* cycles of the files.
*/
class FileRequestLog implements RequestLog {
// The map of shared open files (actually PrintWriter instances)
private static Map<String, PrintWriter> logFiles = new HashMap<String, PrintWriter>();
// Dispose class by closing all open PrintWeiter instances
static void dispose() {
for (final Writer w : logFiles.values()) {
try {
w.close();
} catch (IOException ioe) {
// don't care
}
}
logFiles.clear();
}
// The PrintWriter used by this instance to write the messages
private PrintWriter output;
FileRequestLog(File logFile) throws IOException {
synchronized (logFiles) {
final String fileName = logFile.getAbsolutePath();
this.output = logFiles.get(fileName);
if (this.output == null) {
logFile.getParentFile().mkdirs();
FileWriter fw = new FileWriter(logFile, true);
this.output = new PrintWriter(fw);
logFiles.put(fileName, this.output);
}
}
}
/**
* @see org.apache.sling.engine.RequestLog#write(java.lang.String)
*/
public void write(String message) {
// use a local copy of the reference to not encounter NPE when this
// log happens to be closed asynchronously while at the same time not
// requiring synchronization
PrintWriter writer = this.output;
if (writer != null) {
synchronized (writer) {
writer.println(message);
writer.flush();
}
}
}
public void close() {
// just drop the reference to the output
this.output = null;
}
}