/*==========================================================================*\ | $Id: WCEC.java,v 1.2 2011/12/25 02:24:54 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2006-2011 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.woextensions; import org.apache.log4j.Logger; import org.webcat.core.Application; import org.webcat.core.EOManager; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOObjectStore; import com.webobjects.eocontrol.EOSharedEditingContext; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSMutableArray; import com.webobjects.foundation.NSMutableDictionary; import er.extensions.eof.ERXEC; // ------------------------------------------------------------------------- /** * This is a specialized editing context subclass with infrastructure * support for peer manager pools. * * @author Stephen Edwards * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.2 $, $Date: 2011/12/25 02:24:54 $ */ public class WCEC extends ERXEC { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Creates a new object. */ public WCEC() { this(defaultParentObjectStore()); } // ---------------------------------------------------------- /** * Creates a new object. * @param os the parent object store */ public WCEC(EOObjectStore os) { super(os); if (log.isDebugEnabled()) { String message = "creating " + getClass().getSimpleName() + " with parent object store " + os + "; " + this + "; by " + Thread.currentThread() + "; at " + System.currentTimeMillis(); log.debug(message, new Exception("from here")); } } // ---------------------------------------------------------- /** * Creates a new peer editing context, typically used to make * changes outside of a session's editing context. * @return the new editing context */ public static WCEC newEditingContext() { return (WCEC)factory()._newEditingContext(); } // ---------------------------------------------------------- /** * Creates a new peer editing context that performs * auto-locking/auto-unlocking on each method call. * @return the new editing context */ public static WCEC newAutoLockingEditingContext() { WCEC result = newEditingContext(); result.setCoalesceAutoLocks(false); result.setUseAutoLock(true); return result; } //~ Methods ............................................................... // ---------------------------------------------------------- @Override public void saveChanges() { EOSharedEditingContext defaultSharedEC = EOSharedEditingContext.defaultSharedEditingContext(); if (defaultSharedEC != null) { defaultSharedEC.lock(); } try { super.saveChanges(); } finally { if (defaultSharedEC != null) { defaultSharedEC.unlock(); } } } // ---------------------------------------------------------- @Override protected void _checkOpenLockTraces() { synchronized (this) { int lockCount = lockCount(); if (lockCount > 0) { log.error("Open lock count = " + lockCount); } super._checkOpenLockTraces(); } } // ---------------------------------------------------------- @Override public void dispose() { if (log.isDebugEnabled()) { log.debug("dispose(): " + this); } super.dispose(); } // ---------------------------------------------------------- public static class WCECFactory extends er.extensions.eof.ERXEC.DefaultFactory { protected EOEditingContext _createEditingContext(EOObjectStore parent) { return new WCEC(parent == null ? EOEditingContext.defaultParentObjectStore() : parent); } } // ---------------------------------------------------------- public static Factory factory() { if (factory == null) { factory = new WCECFactory(); } return factory; } // ---------------------------------------------------------- public static void installWOECFactory() { er.extensions.eof.ERXEC.setFactory(factory()); } // ---------------------------------------------------------- public static class PeerManager { // ---------------------------------------------------------- public PeerManager(PeerManagerPool pool) { owner = pool; if (log.isDebugEnabled()) { log.debug("creating manager: " + this); } } // ---------------------------------------------------------- public EOEditingContext editingContext() { if (ec == null) { ec = newEditingContext(); if (log.isDebugEnabled()) { log.debug("creating ec: " + ec.hashCode() + " for manager: " + this); } } return ec; } // ---------------------------------------------------------- public void dispose() { if (ec != null) { if (log.isDebugEnabled()) { log.debug("disposing ec: " + ec + " for manager: " + this); } ec.dispose(); ec = null; } else { log.debug("dispose() called with null ec for manager: " + this); } if (transientState != null) { for (Object value : transientState.allValues()) { if (value instanceof EOManager.ECManager) { ((EOManager.ECManager)value).dispose(); } else if (value instanceof EOEditingContext) { ((EOEditingContext)value).dispose(); } else if (value instanceof PeerManager) { ((PeerManager)value).dispose(); } else if (value instanceof PeerManagerPool) { ((PeerManagerPool)value).dispose(); } } transientState = null; } } // ---------------------------------------------------------- public void sleep() { if (ec != null) { if (log.isDebugEnabled()) { log.debug("sleep(): " + this); } if (cachePermanently) { owner.cachePermanently(this); } else { owner.cache(this); } } } // ---------------------------------------------------------- public boolean cachePermanently() { return cachePermanently; } // ---------------------------------------------------------- public void setCachePermanently(boolean value) { if (log.isDebugEnabled()) { log.debug("setCachePermanently(" + value + ") for manager: " + this); } cachePermanently = value; } // ---------------------------------------------------------- /** * Retrieve an NSMutableDictionary used to hold transient settings for * this editing context (data that is not database-backed). * @return A map of transient settings */ public NSMutableDictionary<String, Object> transientState() { if (transientState == null) { transientState = new NSMutableDictionary<String, Object>(); } return transientState; } //~ Instance/static variables ......................................... private EOEditingContext ec; private PeerManagerPool owner; private boolean cachePermanently; private NSMutableDictionary<String, Object> transientState; static Logger log = Logger.getLogger( PeerManager.class.getName().replace('$', '.')); } // ---------------------------------------------------------- public static class PeerManagerPool { // ---------------------------------------------------------- public PeerManagerPool() { managerCache = new NSMutableArray<PeerManager>(); permanentManagerCache = new NSMutableArray<PeerManager>(); if (log.isDebugEnabled()) { log.debug("creating manager pool: " + this); } } // ---------------------------------------------------------- public void cache(PeerManager manager) { if (log.isDebugEnabled()) { log.debug("cache(" + manager + ")"); } cache(manager, managerCache); } // ---------------------------------------------------------- public void cachePermanently(PeerManager manager) { if (log.isDebugEnabled()) { log.debug("cachePermanently(" + manager + ")"); } managerCache.removeObject(manager); cache(manager, permanentManagerCache); } // ---------------------------------------------------------- public void dispose() { log.debug("dispose()"); dispose(managerCache); dispose(permanentManagerCache); } // ---------------------------------------------------------- private void cache( PeerManager manager, NSMutableArray<PeerManager> cache) { int pos = cache.indexOfObject(manager); if (pos == NSArray.NotFound) { if (log.isDebugEnabled()) { log.debug("caching: manager " + manager + " not in cache"); } if (cache.count() > Application.application().pageCacheSize()) { log.debug("caching: pool full, flushing oldest"); cache.objectAtIndex(0).dispose(); cache.removeObjectAtIndex(0); } } else { if (log.isDebugEnabled()) { log.debug("caching: manager " + manager + " found at pos " + pos); } cache.remove(pos); } if (log.isDebugEnabled()) { log.debug("caching: manager " + manager + " placed at pos " + cache.count()); } cache.add(manager); } // ---------------------------------------------------------- private void dispose(NSMutableArray<PeerManager> cache) { for (PeerManager manager : cache) { manager.dispose(); } cache.clear(); } //~ Instance/static variables ......................................... private NSMutableArray<PeerManager> managerCache; private NSMutableArray<PeerManager> permanentManagerCache; static Logger log = Logger.getLogger( PeerManagerPool.class.getName().replace('$', '.')); } //~ Instance/static variables ............................................. private static Factory factory; static Logger log = Logger.getLogger(WCEC.class); }