/* * 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.ercmail; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOEnterpriseObject; import com.webobjects.eocontrol.EOObjectStoreCoordinator; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableDictionary; import er.extensions.eof.ERXEOControlUtilities; import er.extensions.eof.ERXEditingContextDelegate; import er.extensions.foundation.ERXThreadStorage; import er.extensions.logging.ERXMailAppender; /** * Basic log4j Mail Message Appender<br> * Used for logging log events to a database that will eventually be emailed * out. Logs events using {@link ERCMailDelivery ERCMailDelivery}. * @see er.extensions.logging.ERXMailAppender for more info. */ public class ERCMailMessageAppender extends ERXMailAppender { /** caches the no-op editing context delegate */ protected static final ERXEditingContextDelegate _delegate=new ERXEditingContextDelegate(); // START of static methods from ERCBusinessLogic class. /** * Sets the actor in the current thread storage. * @param actor current user for this thread */ public static void setActor(EOEnterpriseObject actor) { //if (log.isDebugEnabled()) // log.debug("Setting actor to : "+actor); if (actor != null) { ERXThreadStorage.takeValueForKey(actor, "actor"); } else { ERXThreadStorage.removeValueForKey("actor"); } } /** * Gets the actor as a local instance in the given context. * @param ec editing context to pull a local copy of the actor * into * @return actor instance in the given editing context */ public static EOEnterpriseObject actor(EOEditingContext ec) { EOEnterpriseObject actor = actor(); if (actor != null && actor.editingContext() != ec) { EOEditingContext actorEc = actor.editingContext(); actorEc.lock(); try { EOEnterpriseObject localActor = ERXEOControlUtilities.localInstanceOfObject(ec, actor); try { if(actor instanceof ERCoreUserInterface) { NSArray prefs = ((ERCoreUserInterface)actor).preferences(); prefs = ERXEOControlUtilities.localInstancesOfObjects(ec, prefs); ((ERCoreUserInterface)localActor).setPreferences(prefs); } } catch(RuntimeException ex) { //log.error("Error while setting getting actor's preferences: " + ex, ex); } actor = localActor; } finally { actorEc.unlock(); } } return actor; } /** * Gets the actor. * @return current actor for the thread */ public static EOEnterpriseObject actor() { return (EOEnterpriseObject)ERXThreadStorage.valueForKey("actor"); } // END of static methods from ERCBusinessLogic class. /** holds the editing context */ protected EOEditingContext editingContext; /** * Public constructor. */ public ERCMailMessageAppender() { super(); } /** * We want the ability to warn if we are going to be * creating the first cooperating object store. Not a bad * thing just a condition that might cause a strange EOF * issue if it occurs. * @return if the default object store coordinator has any * cooperating object stores. */ protected boolean hasCooperatingObjectStores() { return EOObjectStoreCoordinator.defaultCoordinator().cooperatingObjectStores().count() > 0; } /** * Gets the editing context to use for creating * mail messages in. * @return editing context with a no-op delegate * set. */ public EOEditingContext editingContext() { if (editingContext == null) { if (!hasCooperatingObjectStores()) { LogLog.warn("Creating editing context for the ERCMailMessageAppender before any cooperating object stores have been added."); } editingContext = new EOEditingContext(); editingContext.setDelegate(_delegate); } return editingContext; } /** Overridden because we want to use our own page */ @Override public String getExceptionPageName() { String name = super.getExceptionPageName(); if(name == null) { name = "ERCMailableExceptionPage"; } return name; } /** * Overridden to add the Actor into the dictionary. * @param event logging event */ @Override public NSMutableDictionary composeExceptionPageDictionary(LoggingEvent event) { NSMutableDictionary result = super.composeExceptionPageDictionary(event); result.setObjectForKey(actor(),"actor"); return result; } /** * Where the actual logging event is processed and a * mail message is generated. * @param event logging event */ @Override public void subAppend(LoggingEvent event) { if (editingContext().hasChanges()) { LogLog.error("ERProblemMailMessageAppender: editingContext has changes -- infinite loop detected"); } else { String title = composeTitle(event); String content = composeMessage(event); ERCMailMessage message = ERCMailDelivery.sharedInstance().composeEmail(computedFromAddress(), toAddressesAsArray(), toAddressesAsArray(), bccAddressesAsArray(), title, content, editingContext()); if (getReplyTo() != null) { message.setReplyToAddress(getReplyTo()); } try { editingContext().saveChanges(); } catch (RuntimeException e) { LogLog.error("Caught exception when saving changes to mail context. Exception: " + e.getMessage()); } finally { editingContext().revert(); } } } }