Package er.extensions.eof

Source Code of er.extensions.eof.ERXObjectStoreCoordinatorPool$MultiOSCFactory

package er.extensions.eof;


import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.webobjects.appserver.WOSession;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOObjectStore;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import com.webobjects.eocontrol.EOSharedEditingContext;
import com.webobjects.foundation.NSNotification;
import com.webobjects.foundation.NSNotificationCenter;
import com.webobjects.foundation.NSSelector;

import er.extensions.appserver.ERXSession;
import er.extensions.foundation.ERXProperties;
import er.extensions.foundation.ERXThreadStorage;

/**
* This class implements EOF stack pooling including EOF stack synchronizing.
* It provides a special ERXEC.Factory in order to work without any changes in existing
* applications. The number of EOObjectStoreCoordinators can be set with the
* system Property <code>er.extensions.ERXObjectStoreCoordinatorPool.maxCoordinators</code>.
* Each Session will become one EOObjectStoreCoordinator and the method
* <code>newEditingContext</code> will always return an <code>EOEditingContext</code>
* with the same <code>EOObjectStoreCoordinator</code> for the same <code>WOSession</code>.
* This first release uses round-robin pooling, future versions might use better algorithms
* to decide which <code>EOObjectStoreCoordinator</code> will be used for the next new
* <code>WOSession</code>.<br>The code is tested in a heavy  multithreaded application
* and afawk no deadlock occures, neither in EOF nor directly in Java.
*
* @author David Teran, Frank Caputo @ cluster9
*/
public class ERXObjectStoreCoordinatorPool {
    private static final Logger log = Logger.getLogger(ERXObjectStoreCoordinatorPool.class);
   
    private static final String THREAD_OSC_KEY = "er.extensions.ERXObjectStoreCoordinatorPool.threadOSC";
    private Map<String, EOObjectStore> _oscForSession;
    private int _maxObjectStoreCoordinators;
    private int _currentObjectStoreIndex;
    private List<EOObjectStoreCoordinator> _objectStores;
    private List<EOSharedEditingContext> _sharedEditingContexts;
    private Object _lock = new Object();
    private static ERXObjectStoreCoordinatorPool _sharedObjectStoreCoordinatorPool;

    public static ERXObjectStoreCoordinatorPool _pool() {
      return _sharedObjectStoreCoordinatorPool;
    }
   
    /**
     * Calls initialize() if the required system properties exist.
     *
     */
    public static void initializeIfNecessary() {
      if (ERXProperties.stringForKey("er.extensions.ERXObjectStoreCoordinatorPool.maxCoordinators") != null) {
        ERXObjectStoreCoordinatorPool.initialize();
      }
    }
   
    /**
     * Creates the singleton and registers the multi factory.
     */
    public static void initialize() {
        if(_sharedObjectStoreCoordinatorPool == null) {
            ERXObjectStoreCoordinatorSynchronizer.initialize();
            _sharedObjectStoreCoordinatorPool = new ERXObjectStoreCoordinatorPool(ERXProperties.intForKey("er.extensions.ERXObjectStoreCoordinatorPool.maxCoordinators"));
            log.info("setting ERXEC.factory to MultiOSCFactory");
            ERXEC.setFactory(new MultiOSCFactory(_sharedObjectStoreCoordinatorPool, ERXEC._factory()));
        }
    }
   
    /**
     * Creates a new ERXObjectStoreCoordinatorPool. This object is a singleton.
     * This object is responsible to provide EOObjectStoreCoordinators
     * based on the current Threads' session.
     * It is used by MultiOSCFactory to get a rootObjectStore if the
     * MultiOSCFactory is asked for a new EOEditingContext.
     */
    public ERXObjectStoreCoordinatorPool(int maxObjectStoreCoordinators) {
      _maxObjectStoreCoordinators = maxObjectStoreCoordinators;
        if (_maxObjectStoreCoordinators == 0) {
            //this should work like the default implementation
            log.warn("Registering the pool with only one coordinator doesn't make a lot of sense.");
            _maxObjectStoreCoordinators = 1;
        }
        _oscForSession = new HashMap<String, EOObjectStore>();
       
        NSNotificationCenter.defaultCenter().addObserver(this, new NSSelector/*<Void>*/("sessionDidCreate", ERXConstant.NotificationClassArray), WOSession.SessionDidCreateNotification, null);
        NSNotificationCenter.defaultCenter().addObserver(this, new NSSelector/*<Void>*/("sessionDidTimeout", ERXConstant.NotificationClassArray), WOSession.SessionDidTimeOutNotification, null);
    }
   
    /**
     * checks if the new Session has already  a EOObjectStoreCoordinator assigned,
     * if not it assigns a EOObjectStoreCoordinator to the session.
     * @param n {@link WOSession#SessionDidCreateNotification}
     */
    public void sessionDidCreate(NSNotification n) {
        WOSession s = (WOSession) n.object();
        if (_oscForSession.get(s.sessionID()) == null) {
            _oscForSession.put(s.sessionID(), currentThreadObjectStore());
        }
    }
   
    /** Removes the timed out session from the internal array.
     * session.
     * @param n {@link WOSession#SessionDidTimeOutNotification}
     */
    public void sessionDidTimeout(NSNotification n) {
        String sessionID = (String) n.object();
        _oscForSession.remove(sessionID);
    }
   
    /**
     * @return the sessionID from the session stored in ERXThreadStorage.
     */
    protected String sessionID() {
        return ERXSession.currentSessionID();
    }
   
    /**
     * returns the session related EOObjectStoreCoordinator.
     * If session is null then it returns the nextObjectStore.
     * This method is used to create new EOEditingContexts with the MultiOSCFactory
     * @return an EOEditingContext
     */
    public EOObjectStore currentRootObjectStore() {
        String sessionID = sessionID();
        EOObjectStore os = null;
        if (sessionID != null) {
            os = _oscForSession.get(sessionID);
            if (os == null) {
              os = currentThreadObjectStore();
                _oscForSession.put(sessionID, os);
            }
        } else {
          os = currentThreadObjectStore();
        }
        return os;
    }

    /**
     * Returns the object store for the current thread (or requests one and sets it if there isn't one).
     *
     * @return the object store for the current thread
     */
    protected EOObjectStore currentThreadObjectStore() {
      EOObjectStore os = (EOObjectStore) ERXThreadStorage.valueForKey(ERXObjectStoreCoordinatorPool.THREAD_OSC_KEY);
      if (os == null) {
        os = nextObjectStore();
        if (os != null) {
          ERXThreadStorage.takeValueForKey(os, ERXObjectStoreCoordinatorPool.THREAD_OSC_KEY);
        }
      }
      return os;
    }
   
    /**
     * Lazy initialises the objectStores and then returns the next one,
     * this is based on round robin.
     * @return the next EOObjectStore based on round robin
     */
    public EOObjectStore nextObjectStore() {
        synchronized (_lock) {
            if (_objectStores == null) {
                _initObjectStores();
            }
            if (_currentObjectStoreIndex == _maxObjectStoreCoordinators) {
                _currentObjectStoreIndex = 0;
            }
            EOObjectStore os = _objectStores.get(_currentObjectStoreIndex++);
          return os;
        }
    }
   
    public EOSharedEditingContext sharedEditingContextForObjectStore(EOObjectStore os) {
        int index = _objectStores.indexOf(os);
        EOSharedEditingContext ec = null;
        if (index >= 0) {
            ec = _sharedEditingContexts.get(index);
        }
        return ec;
    }
   
    /**
     * This class uses different EOF stack when creating new EOEditingContexts.
     */
    public static class MultiOSCFactory implements ERXEC.Factory {
        private ERXObjectStoreCoordinatorPool _pool;
        private boolean _useSharedEditingContext;
        private ERXEC.Factory _backingFactory;

        public MultiOSCFactory(ERXObjectStoreCoordinatorPool pool, ERXEC.Factory backingFactory) {
            _pool = pool;
            _backingFactory = backingFactory;
            _useSharedEditingContext = ERXProperties.booleanForKeyWithDefault("er.extensions.ERXEC.useSharedEditingContext", true);
        }

        public Object defaultEditingContextDelegate() {
            return _backingFactory.defaultEditingContextDelegate();
        }

        public void setDefaultEditingContextDelegate(Object delegate) {
            _backingFactory.setDefaultEditingContextDelegate(delegate);
        }

        public Object defaultNoValidationDelegate() {
            return _backingFactory.defaultNoValidationDelegate();
        }

        public void setDefaultNoValidationDelegate(Object delegate) {
            _backingFactory.setDefaultNoValidationDelegate(delegate);
        }

        public void setDefaultDelegateOnEditingContext(EOEditingContext ec) {
            _backingFactory.setDefaultDelegateOnEditingContext(ec);
        }

        public void setDefaultDelegateOnEditingContext(EOEditingContext ec, boolean validation) {
            _backingFactory.setDefaultDelegateOnEditingContext(ec, validation);
        }

        public EOEditingContext _newEditingContext(EOObjectStore objectStore) {
            return _backingFactory._newEditingContext(objectStore);
        }

        public EOEditingContext _newEditingContext(EOObjectStore objectStore, boolean validationEnabled) {
            return _backingFactory._newEditingContext(objectStore, validationEnabled);
        }

        public EOEditingContext _newEditingContext() {
            return _newEditingContext(true);
        }

        public EOEditingContext _newEditingContext(boolean validationEnabled) {
            EOObjectStore os = _pool.currentRootObjectStore();
            EOEditingContext ec = _newEditingContext(os, validationEnabled);
            ec.lock();
            try {
                EOSharedEditingContext sec = (useSharedEditingContext()) ? _pool.sharedEditingContextForObjectStore(os) : null;
                ec.setSharedEditingContext(sec);
            } finally {
                ec.unlock();
            }
            return ec;
        }

        public boolean useSharedEditingContext() {
            if (_backingFactory instanceof ERXEC.DefaultFactory) {
                return ((ERXEC.DefaultFactory)_backingFactory).useSharedEditingContext();
            }
            return _useSharedEditingContext;
        }

    public void setUseSharedEditingContext(boolean value) {
            if (_backingFactory instanceof ERXEC.DefaultFactory) {
                ((ERXEC.DefaultFactory)_backingFactory).setUseSharedEditingContext(value);
            }
      _useSharedEditingContext = value;
    }

    }

    private void _initObjectStores() {
        log.info("initializing Pool...");
        _objectStores = new ArrayList<EOObjectStoreCoordinator>(_maxObjectStoreCoordinators);
        _sharedEditingContexts = new ArrayList<EOSharedEditingContext>(_maxObjectStoreCoordinators);

        String className = ERXProperties.stringForKeyWithDefault("EOSharedEditingContext.defaultSharedEditingContextClassName", EOSharedEditingContext.class.getName()); //should really be "...defaultDefault..."
        try {
            Constructor<? extends EOSharedEditingContext> sharedEditingContextConstructor = Class.forName(className).asSubclass(EOSharedEditingContext.class).getConstructor(EOObjectStore.class);
            for (int i = 0; i < _maxObjectStoreCoordinators; i++) {
                EOObjectStoreCoordinator os = ERXObjectStoreCoordinator.create();
                _objectStores.add(os);
                _sharedEditingContexts.add(sharedEditingContextConstructor.newInstance(os));
            }
            if(_maxObjectStoreCoordinators > 0) {
                EOObjectStoreCoordinator.setDefaultCoordinator(_objectStores.get(0));
            }
        }
        catch (Exception e) {
            throw new IllegalStateException("Unable to create defaultSharedEditingContext with className = " + className, e);
        }

        log.info("initializing Pool finished");
     }
}
TOP

Related Classes of er.extensions.eof.ERXObjectStoreCoordinatorPool$MultiOSCFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.