/* * Created on Jun 9, 2006 Copyright (C) 2001-5, 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.eclipse.runtime.debug; import java.net.URI; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.commonreality.net.handler.IMessageHandler; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IThread; import org.jactr.core.runtime.controller.debug.BreakpointType; import org.jactr.eclipse.core.comp.CompilationUnitManager; import org.jactr.eclipse.core.comp.ICompilationUnit; import org.jactr.eclipse.runtime.RuntimePlugin; import org.jactr.eclipse.runtime.debug.elements.ACTRDebugElement; import org.jactr.eclipse.runtime.debug.elements.ACTRThread; import org.jactr.eclipse.runtime.debug.handlers.BreakpointMessageHandler; import org.jactr.eclipse.runtime.debug.handlers.LoginMessageHandler; import org.jactr.eclipse.runtime.debug.handlers.ModelStateMessageHandler; import org.jactr.eclipse.runtime.debug.handlers.RuntimeStateMessageHandler; import org.jactr.eclipse.runtime.debug.listener.ProceduralTraceListener; import org.jactr.eclipse.runtime.debug.marker.ACTRBreakpoint; import org.jactr.eclipse.runtime.debug.marker.IDisableProductionMarker; import org.jactr.eclipse.runtime.launching.ACTRLaunchConfigurationUtils; import org.jactr.eclipse.runtime.launching.norm.ACTRSession; import org.jactr.eclipse.runtime.session.ISession; import org.jactr.eclipse.runtime.session.ISessionListener; import org.jactr.eclipse.runtime.session.data.ISessionData; import org.jactr.eclipse.runtime.session.stream.ISessionDataStream; import org.jactr.tools.async.message.event.data.BreakpointReachedEvent; import org.jactr.tools.async.message.event.login.LoginAcknowledgedMessage; import org.jactr.tools.async.message.event.state.ModelStateEvent; import org.jactr.tools.async.message.event.state.RuntimeStateEvent; import org.jactr.tools.async.shadow.ShadowController; public class ACTRDebugTarget extends ACTRDebugElement implements IDebugTarget { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ACTRDebugTarget.class); ILaunch _launch; ACTRSession _client; Map<String, ACTRThread> _threads; volatile boolean _inStartUp = true; ProceduralTraceListener _procTraceListener; public ACTRDebugTarget(ACTRSession client) { _client = client; _launch = _client.getLaunch(); _threads = new HashMap<String, ACTRThread>(); _procTraceListener = new ProceduralTraceListener(this); /* * we need to install various listeners.. */ installListeners(); setDebugTarget(this); DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this); client.getSession().addListener(new ISessionListener() { @Override public void sessionClosed(ISession session) { /* * disconnect our listeners */ DebugPlugin.getDefault().getBreakpointManager() .removeBreakpointListener(ACTRDebugTarget.this); RuntimePlugin.getDefault().getRuntimeTraceManager() .removeListener(_procTraceListener); } @Override public void sessionDestroyed(ISession session) { } @Override public void newSessionData(ISessionData sessionData) { } @Override public void newSessionDataStream(ISessionData sessionData, ISessionDataStream sessionDataStream) { } }, null); } public ACTRSession getACTRSession() { return _client; } public String getName() throws DebugException { return "Debug ACTRRuntime"; } public IProcess getProcess() { return null; } @Override public ILaunch getLaunch() { return _launch; } @Override public IDebugTarget getDebugTarget() { return this; } public IThread[] getThreads() throws DebugException { return _threads.values().toArray(new IThread[0]); } public boolean hasThreads() throws DebugException { return _threads.size() > 0; } public boolean supportsBreakpoint(IBreakpoint breakpoint) { if (breakpoint.getModelIdentifier().equals(getModelIdentifier())) try { // snag all the model files running in this launch ILaunchConfiguration launchConfig = getLaunch().getLaunchConfiguration(); Collection<IResource> modelFiles = ACTRLaunchConfigurationUtils .getModelFiles(launchConfig); // get the resource associated with this break point IMarker marker = breakpoint.getMarker(); if (marker != null) for (IResource modelFile : modelFiles) if (modelFile.equals(marker.getResource()) && marker.getResource().exists()) return true; } catch (CoreException ce) { } return false; } public boolean canTerminate() { if (!_inStartUp) { ShadowController shadow = _client.getShadowController(); return shadow.isConnected() && shadow.isRunning(); } else return false; } public boolean isTerminated() { if (_inStartUp) return false; ShadowController shadow = _client.getShadowController(); return !(shadow.isConnected() && shadow.isRunning()); } public void terminate() throws DebugException { // send the termination signal try { _client.stop(); } catch (CoreException e) { LOGGER.error(e); throw new DebugException(e.getStatus()); } } public boolean canResume() { ShadowController shadow = _client.getShadowController(); if (shadow.isRunning() && !_inStartUp) return shadow.getSuspendedModels().size() != 0; return false; } public boolean canSuspend() { ShadowController shadow = _client.getShadowController(); if (shadow.isRunning() && !_inStartUp) return !isSuspended(); else return false; } public boolean isSuspended() { ShadowController shadow = _client.getShadowController(); if (!_inStartUp) return shadow.isSuspended(); return false; } public void resume() throws DebugException { if (LOGGER.isDebugEnabled()) LOGGER.debug("Requesting resumption"); _client.getShadowController().resume(); } public void suspend() throws DebugException { if (LOGGER.isDebugEnabled()) LOGGER.debug("Requesting suspension"); _client.getShadowController().suspend(); } public ACTRThread addThread(String modelName) { ACTRThread thread = new ACTRThread(this, modelName); _threads.put(modelName, thread); thread.fireCreationEvent(); return thread; } public ACTRThread removeThread(String modelName) { ACTRThread thread = _threads.remove(modelName); if (thread != null) thread.setTerminated(true); return thread; } public ACTRThread getThread(String modelName) { return _threads.get(modelName); } public void breakpointAdded(IBreakpoint breakpoint) { if (supportsBreakpoint(breakpoint)) try { if (breakpoint.isEnabled()) { ACTRBreakpoint abp = (ACTRBreakpoint) breakpoint; String name = abp.getBreakpointName(); String type = abp.getBreakpointType(); if (name.length() == 0 || type.length() == 0) return; ShadowController service = _client.getShadowController(); /* * we have to add a breakpoint for all the models.. this is not * completely correct, but since models can be renamed, we can't be * sure we have the correct name.. */ if (ACTRBreakpoint.PRODUCTION.equals(type) && service.isConnected()) service.addBreakpoint(BreakpointType.PRODUCTION, "all", name); } } catch (CoreException ce) { } } public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { try { if (breakpoint.isEnabled()) breakpointAdded(breakpoint); else breakpointRemoved(breakpoint, delta); } catch (CoreException e) { LOGGER.error("ACTRDebugTarget.breakpointChanged threw CoreException : ", e); } } public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { if (supportsBreakpoint(breakpoint)) { ACTRBreakpoint abp = (ACTRBreakpoint) breakpoint; String name = abp.getBreakpointName(); String type = abp.getBreakpointType(); if (name.length() == 0 || type.length() == 0) return; ShadowController service = _client.getShadowController(); // we cant be sure of the model name, so we dont bother setting it // this will set the break point for all models that have this // named production if (ACTRBreakpoint.PRODUCTION.equals(type)) try { service.removeBreakpoint(BreakpointType.PRODUCTION, "all", name); } catch (Exception e) { // silently consume } } } public boolean canDisconnect() { return false; } public void disconnect() throws DebugException { terminate(); } public boolean isDisconnected() { return !_client.getShadowController().isConnected(); } public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } public boolean supportsStorageRetrieval() { return false; } public void installBreakpoints() { try { ShadowController service = _client.getShadowController(); Collection<IResource> modelFiles = ACTRLaunchConfigurationUtils .getModelFiles(_launch.getLaunchConfiguration()); IBreakpoint[] breakpoints = DebugPlugin.getDefault() .getBreakpointManager().getBreakpoints(ACTRSession.ACTR_DEBUG_MODEL); for (IBreakpoint breakpoint2 : breakpoints) if (breakpoint2.isEnabled()) { ACTRBreakpoint breakpoint = (ACTRBreakpoint) breakpoint2; String type = breakpoint.getBreakpointType(); String name = breakpoint.getBreakpointName(); IResource resource = breakpoint.getMarker().getResource(); for (IResource modelFile : modelFiles) if (resource.equals(modelFile)) { if (LOGGER.isDebugEnabled()) LOGGER.debug("installing " + type + " breakpoint " + name); // install the break point if (ACTRBreakpoint.PRODUCTION.equals(type)) service.addBreakpoint(BreakpointType.PRODUCTION, "all", name); } } IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); /* * now let's get all the disable annotations */ for (IResource modelFile : modelFiles) { ICompilationUnit compilationUnit = CompilationUnitManager .acquire(modelFile); if (compilationUnit == null) continue; Collection<String> aliases = ACTRLaunchConfigurationUtils .getModelAliases(modelFile, _launch.getLaunchConfiguration()); markDisabledProductions(modelFile, aliases); /* * now for the imports */ for (URI importSource : compilationUnit.getImportSources()) for (IFile file : root.findFilesForLocationURI(importSource)) markDisabledProductions(file, aliases); } } catch (CoreException ce) { LOGGER.error("Could not get model files", ce); } _inStartUp = false; } protected void markDisabledProductions(IResource modelFile, Collection<String> aliases) throws CoreException { IMarker[] disabled = modelFile.findMarkers( IDisableProductionMarker.MARKER_TYPE, true, IResource.DEPTH_INFINITE); for (String alias : aliases) for (IMarker marker : disabled) { String productionName = marker.getAttribute( IDisableProductionMarker.PRODUCTION_NAME_ATTR, ""); if (productionName.length() > 0) _client.getShadowController().setProductionEnabled(alias, productionName, false); } } protected void installListeners() { Map<Class<?>, IMessageHandler<?>> handlers = _client.getShadowController() .getDefaultHandlers(); /* * we need to add the handler for transformed production events which will * handle the conflict res info. remove on session close */ RuntimePlugin.getDefault().getRuntimeTraceManager() .addListener(_procTraceListener, null); handlers.put(BreakpointReachedEvent.class, new BreakpointMessageHandler( this)); handlers.put(ModelStateEvent.class, new ModelStateMessageHandler(this)); handlers.put(LoginAcknowledgedMessage.class, new LoginMessageHandler(this)); /* * use our own runtimestate handler to catch the suspend on stop w/ debug */ handlers.put(RuntimeStateEvent.class, new RuntimeStateMessageHandler()); } }