
java.fedora.server.journal.recoverylog.JournalRecoveryLog Maven / Gradle / Ivy
Show all versions of fcrepo-client Show documentation
/*
* -----------------------------------------------------------------------------
*
* License and Copyright: The contents of this file are subject to 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.fedora-commons.org/licenses.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The entire file consists of original code.
* Copyright © 2008 Fedora Commons, Inc.
*
Copyright © 2002-2007 The Rector and Visitors of the University of
* Virginia and Cornell University
* All rights reserved.
*
* -----------------------------------------------------------------------------
*/
package fedora.server.journal.recoverylog;
import java.io.IOException;
import java.io.Writer;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import org.apache.log4j.Logger;
import fedora.server.MultiValueMap;
import fedora.server.errors.ModuleInitializationException;
import fedora.server.journal.JournalConstants;
import fedora.server.journal.JournalException;
import fedora.server.journal.ServerInterface;
import fedora.server.journal.entry.ConsumerJournalEntry;
import fedora.server.journal.entry.JournalEntryContext;
import fedora.server.journal.helpers.JournalHelper;
/**
*
* Title: JournalRecoveryLog.java
*
*
* Description: The abstract base for all JournalRecoveryLog classes.
*
*
* @author [email protected]
* @version $Id: JournalRecoveryLog.java 5218 2006-11-20 05:10:11 +0000 (Mon, 20
* Nov 2006) cwilper $
*/
public abstract class JournalRecoveryLog
implements JournalConstants {
/** Logger for this class. */
private static final Logger LOG =
Logger.getLogger(JournalRecoveryLog.class.getName());
private static final int LEVEL_LOW = 0;
private static final int LEVEL_MEDIUM = 1;
private static final int LEVEL_HIGH = 2;
protected final ServerInterface server;
private final int logLevel;
/**
* Create an instance of the proper JournalRecoveryLog child class, as
* determined by the server parameters.
*/
public static JournalRecoveryLog getInstance(Map parameters,
String role,
ServerInterface server)
throws ModuleInitializationException {
try {
Object recoveryLog =
JournalHelper
.createInstanceAccordingToParameter(PARAMETER_JOURNAL_RECOVERY_LOG_CLASSNAME,
new Class[] {
Map.class,
String.class,
ServerInterface.class},
new Object[] {
parameters,
role,
server},
parameters);
LOG.info("JournalRecoveryLog is " + recoveryLog.toString());
return (JournalRecoveryLog) recoveryLog;
} catch (JournalException e) {
throw new ModuleInitializationException("Can't create JournalRecoveryLog",
role,
e);
}
}
/**
* Concrete sub-classes must implement this constructor. Checks the server
* parameters to find out what Logging Level to use - default is Low.
*/
protected JournalRecoveryLog(Map parameters,
String role,
ServerInterface server)
throws ModuleInitializationException {
this.server = server;
String level = parameters.get(PARAMETER_RECOVERY_LOG_LEVEL);
if (level == null) {
logLevel = LEVEL_LOW;
} else if (VALUE_RECOVERY_LOG_LEVEL_HIGH.equals(level)) {
logLevel = LEVEL_HIGH;
} else if (VALUE_RECOVERY_LOG_LEVEL_MEDIUM.equals(level)) {
logLevel = LEVEL_MEDIUM;
} else if (VALUE_RECOVERY_LOG_LEVEL_LOW.equals(level)) {
logLevel = LEVEL_LOW;
} else {
throw new ModuleInitializationException("'"
+ PARAMETER_RECOVERY_LOG_LEVEL + "' parameter must be '"
+ VALUE_RECOVERY_LOG_LEVEL_LOW + "'(default), '"
+ VALUE_RECOVERY_LOG_LEVEL_MEDIUM + "' or '"
+ VALUE_RECOVERY_LOG_LEVEL_HIGH + "'", role);
}
}
/**
* Concrete sub-classes should probably synchronize this method, since it
* can be called either from the JournalConsumerThread or from the Server.
*/
public abstract void log(String message);
/**
* Concrete sub-classes should probably synchronize this method, since it
* can be called either from the JournalConsumerThread or from the Server.
* For the same reason, they should also provide for the possibility that it
* will be called multiple times, or that a call to log() will happen after
* the call to shutdown().
*/
public abstract void shutdown();
public void shutdown(String message) {
log(message);
shutdown();
}
/**
* Concrete sub-classes should call this method from their constructor, or
* as soon as the log is ready for writing.
*/
public void logHeaderInfo(Map parameters) {
StringBuffer buffer = new StringBuffer("Recovery parameters:");
for (Iterator keys = parameters.keySet().iterator(); keys
.hasNext();) {
Object key = keys.next();
Object value = parameters.get(key);
buffer.append("\n ").append(key).append("=").append(value);
}
log(buffer.toString());
}
/**
* Format a journal entry for writing to the log. Take logging level into
* account.
*/
public void log(ConsumerJournalEntry journalEntry) {
StringBuffer buffer = new StringBuffer();
buffer.append("Event: method='").append(journalEntry.getMethodName())
.append("', ").append(journalEntry.getIdentifier())
.append("\n");
if (logLevel == LEVEL_HIGH) {
JournalEntryContext context = journalEntry.getContext();
buffer.append(" context=").append(context.getClass().getName())
.append("\n");
buffer.append(writeMapValues("environmentAttributes", context
.getEnvironmentAttributes()));
buffer.append(writeMapValues("subjectAttributes", context
.getSubjectAttributes()));
buffer.append(writeMapValues("actionAttributes", context
.getActionAttributes()));
buffer.append(writeMapValues("resourceAttributes", context
.getResourceAttributes()));
buffer.append(writeMapValues("recoveryAttributes", context
.getRecoveryAttributes()));
buffer.append(" password='*********'\n");
buffer.append(" noOp=").append(context.getNoOp())
.append("\n");
}
if (logLevel == LEVEL_HIGH || logLevel == LEVEL_MEDIUM) {
buffer.append(" now=" + journalEntry.getContext().getNoOp()
+ "\n");
buffer.append(" arguments\n");
Map argumentsMap = journalEntry.getArgumentsMap();
for (String name : argumentsMap.keySet()) {
Object value = argumentsMap.get(name);
if (value instanceof String[]) {
buffer.append(writeStringArray(name, (String[]) value));
} else {
buffer.append(" " + name + "='" + value + "'\n");
}
}
}
log(buffer.toString());
}
/**
* Helper for the {@link #log(ConsumerJournalEntry)} method. Writes the
* values of a string array
*/
private String writeStringArray(String name, String[] values) {
StringBuffer buffer = new StringBuffer();
buffer.append(" ").append(name).append("=[");
for (int i = 0; i < values.length; i++) {
buffer.append("'").append(values[i]).append("'");
if (i < values.length - 1) {
buffer.append(", ");
}
}
buffer.append("]\n");
return buffer.toString();
}
/**
* Helper for the {@link #log(ConsumerJournalEntry)} method. Writes the
* values of a context multi-map.
*/
private String writeMapValues(String mapName, MultiValueMap map) {
StringBuffer buffer = new StringBuffer();
buffer.append(" " + mapName + "\n");
for (Iterator names = map.names(); names.hasNext();) {
String name = (String) names.next();
buffer.append(" ").append(name).append("\n");
String[] values = map.getStringArray(name);
for (String element : values) {
buffer.append(" ").append(element).append("\n");
}
}
return buffer.toString();
}
/**
* Concrete sub-classes call this method to perform the final formatting if
* a log entry.
*/
protected void log(String message, Writer writer) {
try {
writer.write(JournalHelper.formatDate(new Date()) + ": " + message
+ "\n");
} catch (IOException e) {
LOG.error("Error writing journal log entry", e);
}
}
}