/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.extensions.logging;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import er.extensions.eof.ERXEC;
import er.extensions.eof.ERXEOControlUtilities;
/**
* Basic log4j EOF Appender<br>
* Very basic appender, useful for logging events to a database using EOF.
* Manditory Fields:<br>
* LoggingEntity - Entity for creating logging events. The class mapped to this entity must
* implement the interface: {@link ERXEOFLogEntryInterface}
* Optional Fields:<br>
* BufferSize - Number of Events to catch before calling ec.saveChanges()
*/
public class ERXEOFAppender extends AppenderSkeleton {
/** holds the logging entity name */
protected String loggingEntity;
/** holds a reference to the logging editing context */
protected EOEditingContext ec;
/** holds the buffer size, defaults to -1 */
protected int bufferSize = -1;
/** holds the flag if all the conditions for logging have been checked */
protected boolean conditionsChecked = false;
/** holds the current buffer size, defaults to 1 */
protected int currentBufferSize = 1;
/**
* The EOF Appender does not require a layout
* @return false
*/
public boolean requiresLayout() { return false; }
/**
* Called to close the appender.
*/
public synchronized void close() {
if (!closed)
closed = true;
}
/**
* Gets the logging entity name.
* @return logging entity name.
*/
public String getLoggingEntity() { return loggingEntity; }
/**
* Sets the logging entity name.
* @param name name of the logging entity
*/
public void setLoggingEntity(String name) { loggingEntity = name; }
/**
* Determines if enough of the EOF stack has been setup
* that it is safe to create an editing context and log
* events to the database.
* @return if any cooperating object stores have been created
*/
// ENHANCEME: Should also check if the application has fully started up
protected boolean safeToCreateEditingContext() {
return EOObjectStoreCoordinator.defaultCoordinator().cooperatingObjectStores().count() > 0;
}
/**
* Gets the editing context for logging events. Will
* create one if one hasn't been created yet.
* @return editing context to log events to the database
*/
protected EOEditingContext editingContext() {
if (ec == null) {
if (safeToCreateEditingContext()) {
ec = ERXEC.newEditingContext();
}
}
return ec;
}
/**
* Gets the buffer size.
* @return current buffer size
*/
public int getBufferSize() { return bufferSize; }
/**
* Sets the current buffer size. Must be set
* to a value greater than zero.
* @param bufferSize size of the buffer
*/
public void setBufferSize(int bufferSize) {
if (bufferSize <= 0)
LogLog.warn("BufferSize must be greater than 0! Attempted to set bufferSize to: " + bufferSize);
else
this.bufferSize = bufferSize;
}
/**
* Used to determine if the system is ready to log
* events to the database.
* @return if all of the conditions are satisfied
*/
protected boolean checkConditions() {
if (getLoggingEntity() == null) {
LogLog.warn("Attempting to log an event with a null LoggingEntity specified.");
} else if (!safeToCreateEditingContext()) {
LogLog.warn("Attempting to log an event to an EREOFAppender before an ObjectStoreCoordinator has been added.");
} else {
conditionsChecked = true;
}
return conditionsChecked;
}
/**
* Entry point for logging an event.
*
* Reminder: the nesting of calls is:
*
* doAppend()
* - check threshold
* - filter
* - append();
* - checkConditions();
* - subAppend();
*
* @param event current logging event
*/
@Override
public void append(LoggingEvent event) {
if (conditionsChecked || checkConditions()) {
subAppend(event);
} else {
LogLog.warn("Unable to log event: " + event.getMessage());
}
}
/**
* This is where the real logging happens.
* @param event current logging event
*/
protected void subAppend(LoggingEvent event) {
// Create Log Entry for event.
if (editingContext() != null) {
ERXEOFLogEntryInterface logEntry = (ERXEOFLogEntryInterface)ERXEOControlUtilities.createAndInsertObject(editingContext(), getLoggingEntity());
// Note that layout is not required and can be null.
logEntry.intializeWithLoggingEvent(event, layout);
if (getBufferSize() == -1 || currentBufferSize == getBufferSize()) {
editingContext().saveChanges();
// Clean out the ec.
editingContext().revert();
currentBufferSize = 1;
} else {
currentBufferSize++;
}
}
}
}