org.jactr.core.model.basic.BasicModel.java Source code

Java tutorial

Introduction

Here is the source code for org.jactr.core.model.basic.BasicModel.java

Source

/*
 * Created on Oct 21, 2006 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
 * (jactr.org) This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the License,
 * or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have
 * received a copy of the GNU Lesser General Public License along with this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.jactr.core.model.basic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.buffer.IActivationBuffer;
import org.jactr.core.event.ACTREventDispatcher;
import org.jactr.core.event.IParameterListener;
import org.jactr.core.event.ParameterEvent;
import org.jactr.core.extensions.IExtension;
import org.jactr.core.model.ICycleProcessor;
import org.jactr.core.model.IModel;
import org.jactr.core.model.IllegalModelStateException;
import org.jactr.core.model.event.IModelListener;
import org.jactr.core.model.event.ModelEvent;
import org.jactr.core.model.six.DefaultCycleProcessor6;
import org.jactr.core.module.IModule;
import org.jactr.core.module.declarative.IDeclarativeModule;
import org.jactr.core.module.procedural.IProceduralModule;
import org.jactr.core.queue.TimedEventQueue;
import org.jactr.core.runtime.ACTRRuntime;
import org.jactr.core.utils.collections.CachedCollection;
import org.jactr.core.utils.collections.CachedMap;
import org.jactr.core.utils.parameter.IParameterized;
import org.jactr.core.utils.parameter.ParameterHandler;
import org.jactr.instrument.IInstrument;

public class BasicModel implements IModel {
    /**
     * logger definition
     */
    static private final Log LOGGER = LogFactory.getLog(BasicModel.class);

    static public final String CYCLE_SKIPPING_PARAM = "EnableUnusedCycleSkipping";

    static public final String PERSISTENT_PARAM = "EnablePersistentExecution";

    static public final String AGE_PARAM = "Age";

    static private final Collection<String> READABLE_PARAMETERS = Collections
            .unmodifiableCollection(Arrays.asList(AGE_PARAM, CYCLE_SKIPPING_PARAM, PERSISTENT_PARAM));

    static private final Collection<String> WRITABLE_PARAMETERS = Collections
            .unmodifiableCollection(Arrays.asList(AGE_PARAM, CYCLE_SKIPPING_PARAM, PERSISTENT_PARAM));

    protected boolean _isInitialized = false;

    protected TimedEventQueue _timedEventQueue;

    protected IDeclarativeModule _declarativeModule;

    protected IProceduralModule _proceduralModule;

    protected CachedMap<String, IActivationBuffer> _buffers;

    protected CachedCollection<IModule> _modules;

    protected CachedCollection<IExtension> _extensions;

    protected CachedCollection<IInstrument> _installedInstruments;

    protected boolean _cycleSkippingEnabled = true;

    protected boolean _persistentExecution = false;

    protected ReentrantReadWriteLock _lock = new ReentrantReadWriteLock();

    protected ACTREventDispatcher<IModel, IModelListener> _eventDispatcher;

    protected ACTREventDispatcher<IParameterized, IParameterListener> _parameterEventDispatcher;

    protected Map<String, Object> _metaData;

    protected Map<String, Object> _parameterMap;

    protected String _name;

    protected boolean _modulesInitialized = false;

    protected long _cycle;

    protected double _age;

    protected ICycleProcessor _cycleProcessor;

    public BasicModel() {
        _timedEventQueue = new TimedEventQueue(this);
        _buffers = new CachedMap<String, IActivationBuffer>(new TreeMap<String, IActivationBuffer>());
        _modules = new CachedCollection<IModule>(new ArrayList<IModule>());
        _extensions = new CachedCollection<IExtension>(new ArrayList<IExtension>());
        _installedInstruments = new CachedCollection<IInstrument>(new ArrayList<IInstrument>());
        _eventDispatcher = new ACTREventDispatcher<IModel, IModelListener>();
        _parameterEventDispatcher = new ACTREventDispatcher<IParameterized, IParameterListener>();
        _metaData = new TreeMap<String, Object>();
        _parameterMap = new TreeMap<String, Object>();
        setCycleProcessor(createCycleProcessor());
    }

    public void setCycleProcessor(ICycleProcessor processor) {
        _cycleProcessor = processor;
    }

    public ICycleProcessor getCycleProcessor() {
        return _cycleProcessor;
    }

    protected ICycleProcessor createCycleProcessor() {
        return new DefaultCycleProcessor6();
    }

    public BasicModel(String name) {
        this();
        setName(name);
    }

    public void dispose() {
        /*
         * explicitly uninstall
         */
        for (IInstrument instrument : new ArrayList<IInstrument>(_installedInstruments))
            uninstall(instrument);

        /*
         * modules are responsible for buffer disposal
         */
        for (IModule module : _modules)
            module.dispose();

        try {
            // acquire lock
            _lock.writeLock().lock();

            /*
             * no more events
             */
            _eventDispatcher.clear();
            _eventDispatcher = null;

            _extensions.clear();
            _extensions = null;

            _modules.clear();
            _modules = null;

            _buffers.clear();
            _buffers = null;

            _metaData.clear();
            _metaData = null;

            _parameterMap.clear();
            _parameterMap = null;

            _timedEventQueue.dispose();
            _timedEventQueue = null;

            _declarativeModule = null;
            _proceduralModule = null;
        } finally {
            // release
            _lock.writeLock().unlock();
        }
    }

    public void addActivationBuffer(IActivationBuffer buffer) {
        boolean added = false;
        try {
            // acquire lock
            _lock.writeLock().lock();

            _buffers.put(buffer.getName().toLowerCase(), buffer);
            added = true;
        } finally {
            // release
            _lock.writeLock().unlock();

            if (added)
                dispatch(new ModelEvent(this, buffer));
        }
    }

    public IActivationBuffer getActivationBuffer(String name) {
        try {
            // lock
            _lock.readLock().lock();
            return _buffers.get(name.toLowerCase());
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public Collection<IActivationBuffer> getActivationBuffers() {
        ArrayList<IActivationBuffer> buffers = new ArrayList<IActivationBuffer>(_buffers.size());
        getActivationBuffers(buffers);
        return buffers;
    }

    public void getActivationBuffers(Collection<IActivationBuffer> container) {
        try {
            // lock
            _lock.readLock().lock();
            _buffers.getValues(container);
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public IDeclarativeModule getDeclarativeModule() {
        try {
            // lock
            _lock.readLock().lock();
            return _declarativeModule;
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public IExtension getExtension(Class<? extends IExtension> extensionClass) {
        try {
            // lock
            _lock.readLock().lock();
            for (IExtension extension : _extensions)
                if (extensionClass.isAssignableFrom(extension.getClass()))
                    return extension;

            return null;
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public Collection<IExtension> getExtensions() {
        try {
            // lock
            _lock.readLock().lock();
            return Collections.unmodifiableCollection(_extensions);
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public IInstrument getInstrument(Class<? extends IInstrument> instrumentClass) {
        try {
            // lock
            _lock.readLock().lock();
            for (IInstrument installable : _installedInstruments)
                if (instrumentClass.isAssignableFrom(installable.getClass()))
                    return installable;

            return null;
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public Collection<IInstrument> getInstruments() {
        try {
            // lock
            _lock.readLock().lock();
            return Collections.unmodifiableCollection(_installedInstruments);
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public IModule getModule(Class<? extends IModule> moduleClass) {
        try {
            // lock
            _lock.readLock().lock();
            for (IModule module : _modules)
                if (moduleClass.isAssignableFrom(module.getClass()))
                    return module;

            return null;
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public Collection<IModule> getModules() {
        try {
            // lock
            _lock.readLock().lock();
            return Collections.unmodifiableCollection(_modules);
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public IProceduralModule getProceduralModule() {
        try {
            // lock
            _lock.readLock().lock();
            return _proceduralModule;
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public void install(IModule module) {
        boolean added = false;
        try {
            // acquire lock
            _lock.writeLock().lock();

            if (module instanceof IDeclarativeModule) {
                if (_declarativeModule != null)
                    throw new IllegalModelStateException(
                            "Only one declarative module may exist in a model at a time");

                _declarativeModule = (IDeclarativeModule) module;
            }

            if (module instanceof IProceduralModule) {
                if (_proceduralModule != null)
                    throw new IllegalModelStateException(
                            "Only one procedural module may exist in a model at a time");

                _proceduralModule = (IProceduralModule) module;
            }

            _modules.add(module);

            added = true;
        } finally {
            // release
            _lock.writeLock().unlock();

            if (added) {
                /*
                 * install out of the lock in case this takes a sig amount of time
                 */

                module.install(this);
                if (hasBeenInitialized())
                    module.initialize();
                dispatch(new ModelEvent(this, module));
            }
        }
    }

    public void install(IExtension extension) {
        if (!modulesAreInitialized())
            initializeModules();

        boolean added = false;
        try {
            // acquire lock
            _lock.writeLock().lock();

            _extensions.add(extension);

            added = true;
        } finally {
            // release
            _lock.writeLock().unlock();

            if (added) {
                /*
                 * install out of the lock in case this takes a sig amount of time
                 */
                extension.install(this);
                if (hasBeenInitialized())
                    try {
                        extension.initialize();
                    } catch (Exception e) {
                        throw new IllegalModelStateException("Exception while initializing extension " + extension,
                                e);
                    }

                dispatch(new ModelEvent(this, extension));
            }
        }
    }

    public void install(IInstrument instrument) {
        if (!modulesAreInitialized())
            initializeModules();

        boolean added = false;
        try {
            // acquire lock
            _lock.writeLock().lock();

            _installedInstruments.add(instrument);
            added = true;
        } finally {
            // release
            _lock.writeLock().unlock();

            if (added) {
                /*
                 * perform the instll out of the lock
                 */
                instrument.install(this);
                if (hasBeenInitialized())
                    instrument.initialize();
                dispatch(new ModelEvent(this, instrument));
            }
        }

    }

    /**
     * @see org.jactr.core.model.IModel#uninstall(org.jactr.instrument.IInstrument)
     */
    public void uninstall(IInstrument installable) {
        try {
            _lock.writeLock().lock();
            _installedInstruments.remove(installable);
        } finally {
            _lock.writeLock().unlock();
        }
        /*
         * pull it out of the lock, since this may take some time
         */
        installable.uninstall(this);
    }

    public String getParameter(String key) {
        if (CYCLE_SKIPPING_PARAM.equalsIgnoreCase(key))
            return ParameterHandler.booleanInstance().toString(isCycleSkippingEnabled());
        else if (AGE_PARAM.equalsIgnoreCase(key))
            return "" + getAge();
        else if (PERSISTENT_PARAM.equalsIgnoreCase(key))
            return "" + isPersistentExecutionEnabled();

        if (_parameterMap.containsKey(key))
            return _parameterMap.get(key).toString();

        if (LOGGER.isWarnEnabled())
            LOGGER.warn("Unknown parameter " + key + " requested, returning null");
        return null;
    }

    public Collection<String> getPossibleParameters() {
        TreeSet<String> possible = new TreeSet<String>(READABLE_PARAMETERS);
        possible.addAll(WRITABLE_PARAMETERS);
        return possible;
    }

    public Collection<String> getSetableParameters() {
        return WRITABLE_PARAMETERS;
    }

    public void setParameter(String key, String value) {
        boolean handled = false;
        if (CYCLE_SKIPPING_PARAM.equalsIgnoreCase(key)) {
            setCycleSkippingEnabled(ParameterHandler.booleanInstance().coerce(value));
            handled = true;
        } else if (AGE_PARAM.equalsIgnoreCase(key)) {
            setAge(ParameterHandler.numberInstance().coerce(value).doubleValue());
            handled = true;
        } else if (PERSISTENT_PARAM.equalsIgnoreCase(key)) {
            setPersistentExecutionEnabled(ParameterHandler.booleanInstance().coerce(value));
            handled = true;
        } else
            // check the modules..
            for (IModule module : _modules)
                if (module instanceof IParameterized)
                    if (((IParameterized) module).getSetableParameters().contains(key)) {
                        // route it
                        if (LOGGER.isWarnEnabled())
                            LOGGER.warn(
                                    "You should not use the model as the parameter nexus, rather assigned it to the module directly");
                        ((IParameterized) module).setParameter(key, value);
                        handled = true;
                    }

        if (!handled) {
            if (LOGGER.isDebugEnabled())
                LOGGER.debug("No registered handler for " + key + " = " + value);
            _parameterMap.put(key, value);
        }

    }

    public Object getMetaData(String key) {
        try {
            // lock
            _lock.readLock().lock();
            return _metaData.get(key);
        } finally {
            // unlock
            _lock.readLock().unlock();
        }
    }

    public void setMetaData(String key, Object value) {
        try {
            // acquire lock
            _lock.writeLock().lock();

            _metaData.put(key, value);
        } finally {
            // release
            _lock.writeLock().unlock();
        }
    }

    public Collection<String> getMetaDataKeys() {
        return new ArrayList<String>(_metaData.keySet());
    }

    public void setAge(double age) {
        _age = age;
    }

    public double getAge() {
        return _age;
    }

    public void setCycleSkippingEnabled(boolean skipping) {
        if (skipping == _cycleSkippingEnabled)
            return;

        boolean old = _cycleSkippingEnabled;
        _cycleSkippingEnabled = skipping;

        fireParameterEvent(CYCLE_SKIPPING_PARAM, old, skipping);
    }

    public boolean isCycleSkippingEnabled() {
        return _cycleSkippingEnabled;
    }

    public void setPersistentExecutionEnabled(boolean persistent) {
        if (_persistentExecution == persistent)
            return;

        boolean old = _persistentExecution;
        _persistentExecution = persistent;
        fireParameterEvent(PERSISTENT_PARAM, old, persistent);
    }

    public boolean isPersistentExecutionEnabled() {
        return _persistentExecution;
    }

    public TimedEventQueue getTimedEventQueue() {
        return _timedEventQueue;
    }

    public boolean hasBeenInitialized() {
        return _isInitialized;
    }

    /**
     * initialize the model, calling initialize on buffers, and extensions in that
     * order. this is called before the model starts to run Modules will have
     * already been initialized, as they are initialized before extensions or
     * instruments are installed..
     * 
     * @see org.jactr.core.model.IModel#initialize()
     */
    public void initialize() throws Exception {
        if (!modulesAreInitialized())
            initializeModules();

        try {
            _lock.writeLock().lock();
            if (hasBeenInitialized())
                throw new IllegalModelStateException("Model has already been initialized");

            _isInitialized = true;

            for (IActivationBuffer buffer : _buffers.values())
                buffer.initialize();

            for (IExtension extension : _extensions)
                extension.initialize();

            for (IInstrument instruments : _installedInstruments)
                instruments.initialize();
        } finally {
            _lock.writeLock().unlock();

            dispatch(new ModelEvent(this, ModelEvent.Type.INITIALIZED));
        }
    }

    protected boolean modulesAreInitialized() {
        return _modulesInitialized;
    }

    protected void initializeModules() {
        if (modulesAreInitialized())
            return;
        for (IModule module : _modules)
            module.initialize();
        _modulesInitialized = true;
    }

    public void addListener(IModelListener listener, Executor executor) {
        _eventDispatcher.addListener(listener, executor);
    }

    public void removeListener(IModelListener listener) {
        _eventDispatcher.removeListener(listener);
    }

    public boolean hasListeners() {
        return _eventDispatcher.hasListeners();
    }

    public void dispatch(ModelEvent modelEvent) {
        if (_eventDispatcher.hasListeners())
            _eventDispatcher.fire(modelEvent);
    }

    public void addListener(IParameterListener listener, Executor executor) {
        _parameterEventDispatcher.addListener(listener, executor);
    }

    public void removeListener(IParameterListener listener) {
        _parameterEventDispatcher.removeListener(listener);
    }

    public boolean hasParameterListeners() {
        return _parameterEventDispatcher.hasListeners();
    }

    public void dispatch(ParameterEvent modelEvent) {
        if (_parameterEventDispatcher.hasListeners())
            _parameterEventDispatcher.fire(modelEvent);
    }

    protected void fireParameterEvent(String parameterName, Object oldValue, Object newValue) {
        if (hasParameterListeners())
            dispatch(new ParameterEvent(this, ACTRRuntime.getRuntime().getClock(this).getTime(), parameterName,
                    oldValue, newValue));
    }

    public String getName() {
        return _name;
    }

    public void setName(String modelName) {
        _name = modelName;
    }

    public long getCycle() {
        return _cycle;
    }

    public void setCycle(long cycle) {
        if (cycle <= _cycle)
            return;
        _cycle = cycle;
    }

    @Override
    public String toString() {
        return getName();
    }
}