/* * Created on Nov 30, 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.reality.connector; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.commonreality.agents.IAgent; import org.commonreality.participant.IParticipant.State; import org.commonreality.reality.CommonReality; import org.commonreality.reality.IReality; import org.commonreality.reality.control.RealityShutdown; import org.commonreality.reality.control.RealityStartup; import org.commonreality.time.IClock; import org.commonreality.time.impl.BasicClock; import org.jactr.core.model.IModel; import org.jactr.core.reality.ACTRAgent; /** * @author developer */ public class CommonRealityConnector implements IConnector { // public static final String TRANSPORT_CLASS = "transportClass"; // public static final String PROTOCOL_CLASS = "protocolClass"; // public static final String ADDRESS = "address"; /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(CommonRealityConnector.class); protected Map<IModel, ACTRAgent> _agentInterfaces; // protected Map<IModel, IClock> _disconnectedModels; protected BasicClock _defaultClock; protected Map<IModel, IClock> _allClocks; protected IClockConfigurator _clockConfig; public CommonRealityConnector() { _defaultClock = new BasicClock(); _agentInterfaces = new ConcurrentHashMap<IModel, ACTRAgent>(); // _disconnectedModels = new ConcurrentHashMap<IModel, IClock>(); _allClocks = new ConcurrentHashMap<IModel, IClock>(); setClockConfigurator(new IClockConfigurator() { public IClock getClockFor(IModel model, IAgent agent) { return agent.getClock(); } /* * by default, we don't support nested clock (non-Javadoc) * @see * org.jactr.core.reality.connector.IClockConfigurator#getClockFor(org * .jactr.core.model.IModel, org.commonreality.time.IClock) */ public IClock getClockFor(IModel model, IClock defaultClock) { return null; } public void release(IModel model, IClock clock) { // noop } }); } /** * @see org.jactr.core.reality.connector.IConnector#isRunning() */ public boolean isRunning() { return CommonReality.getReality() != null && CommonReality.getReality().stateMatches(State.STARTED, State.SUSPENDED); } public void start() { IReality reality = CommonReality.getReality(); new RealityStartup(reality).run(); } public void stop() { IReality reality = CommonReality.getReality(); if (reality != null) new RealityShutdown(reality, true).run(); } /** * @see org.jactr.core.reality.connector.IConnector#connect(org.jactr.core.model.IModel) */ public void connect(IModel model) { String modelName = model.getName(); if (LOGGER.isDebugEnabled()) LOGGER.debug("connecting to reality inteface for " + modelName); try { ACTRAgent agentInterface = null; for (IAgent a : CommonReality.getAgents()) if (a instanceof ACTRAgent) { String idModelName = a.getIdentifier().getName(); String agentName = ((ACTRAgent) a).getModelName(); /* * short term test as we migrate from ACTRAgent explicitly. */ if (!idModelName.equals(agentName)) LOGGER.error(String.format( "Model name (%s) isn't same as agent name(%s)?", idModelName, agentName)); if (modelName.equals(agentName)) agentInterface = (ACTRAgent) a; } if (agentInterface != null) { _agentInterfaces.put(model, agentInterface); _allClocks.put(model, _clockConfig.getClockFor(model, agentInterface)); if (LOGGER.isDebugEnabled()) LOGGER.debug("connected, waiting for start"); // we dont need to do anything here since the modules will attach // to common reality during the modelStarted() call agentInterface.waitForState(State.STARTED); } else { IClock baseClock = _defaultClock; if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format( "Unexpected model %s, not common reality agent configured.", model.getName())); IClock assignedClock = _clockConfig.getClockFor(model, baseClock); if (assignedClock != null) { _allClocks.put(model, assignedClock); if (LOGGER.isDebugEnabled()) LOGGER.debug(String .format("Running the model using provided clock")); } else { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Unable to run this model. Exception")); throw new RuntimeException(String.format( "No clue how to hook up %s using current IConnector", model.getName())); } } if (LOGGER.isDebugEnabled()) LOGGER.debug("started!!"); } catch (Exception e) { _agentInterfaces.remove(model); _allClocks.remove(model); throw new RuntimeException("Could not connect " + model + " to reality", e); } } /** * @see org.jactr.core.reality.connector.IConnector#disconnect(org.jactr.core.model.IModel) */ public void disconnect(IModel model) { IClock clock = _allClocks.remove(model); if (clock != null) getClockConfigurator().release(model, clock); // now we can disconnect from reality IAgent agentInterface = getAgent(model); if (agentInterface != null) try { CommonReality.removeAgent(agentInterface); _agentInterfaces.remove(model); cleanDisconnect(agentInterface); } catch (Exception e) { LOGGER.error("Could not disconnect " + model + " from reality", e); throw new RuntimeException("Could not disconnect " + model + " from reality", e); } } protected void cleanDisconnect(IAgent agent) { boolean force = false; if (agent.stateMatches(State.STARTED)) try { agent.stop(); } catch (Exception e) { if (LOGGER.isWarnEnabled() && !(e instanceof InterruptedException)) LOGGER.warn(String.format("Could not stop agent cleanly, forcing "), e); force = true; } try { agent.shutdown(force); } catch (Exception e) { if (LOGGER.isWarnEnabled() && !(e instanceof InterruptedException)) LOGGER.warn(String.format("Forced shutdown failed ", e)); } } /** * @see org.jactr.core.reality.connector.IConnector#getAgentInterface(org.jactr.core.model.IModel) */ public IAgent getAgent(IModel model) { if (model == null) return null; /* * concurrent map will throw npe for a null key */ return _agentInterfaces.get(model); } public IClock getClock(IModel model) { if (model == null) return _defaultClock; IClock rtn = _allClocks.get(model); if (rtn == null) rtn = _defaultClock; return rtn; } public IClockConfigurator getClockConfigurator() { return _clockConfig; } public void setClockConfigurator(IClockConfigurator clockConfig) { _clockConfig = clockConfig; } }