The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+
If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at http://www.eclipse.org.
+
+
+
\ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.core/build.properties b/plugins/com.windriver.debug.tcf.core/build.properties
new file mode 100644
index 000000000..e9863e281
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/com.windriver.debug.tcf.core/plugin.properties b/plugins/com.windriver.debug.tcf.core/plugin.properties
new file mode 100644
index 000000000..d573d34eb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 Wind River Systems, Inc. and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Wind River Systems - initial implementation
+###############################################################################
+pluginName = TCF/Eclipse Debugger Integration Core
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.debug.tcf.core/plugin.xml b/plugins/com.windriver.debug.tcf.core/plugin.xml
new file mode 100644
index 000000000..1a9590a32
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/plugin.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/com.windriver.debug.tcf.core/schema/startup.exsd b/plugins/com.windriver.debug.tcf.core/schema/startup.exsd
new file mode 100644
index 000000000..0d41bb8d9
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/schema/startup.exsd
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+ This extension point is used to register plugins
+ that want to be activated on TCF startup.
+ Once the TCF is started, registered plugins will be activated.
+
+
+
+
+
+
+
+
+
+
+
+
+ a fully qualified identifier of the target extension point
+
+
+
+
+
+
+ an optional identifier of the extension instance
+
+
+
+
+
+
+ an optional name of the extension instance
+
+
+
+
+
+
+
+
+
+
+
+ Class will be loaded during statup
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java
new file mode 100644
index 000000000..e4ffe006d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.debug.tcf.core.model.TCFBreakpointsModel;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TCFCore extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.debug.tcf.core";
+
+ // The shared instance
+ private static TCFCore plugin;
+ private static TCFBreakpointsModel bp_model;
+
+ public TCFCore() {
+ plugin = this;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ bp_model = new TCFBreakpointsModel();
+ runTCFStartup();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ bp_model.dispose();
+ bp_model = null;
+ plugin = null;
+ super.stop(context);
+ }
+
+ private void runTCFStartup() {
+ try {
+ IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "startup");
+ IExtension[] extensions = point.getExtensions();
+ for (int i = 0; i < extensions.length; i++) {
+ try {
+ Platform.getBundle(extensions[i].getNamespaceIdentifier()).start();
+ IConfigurationElement[] e = extensions[i].getConfigurationElements();
+ for (int j = 0; j < e.length; j++) {
+ String nm = e[j].getName();
+ if (nm.equals("class")) { //$NON-NLS-1$
+ Class.forName(e[j].getAttribute("name")); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (Throwable x) {
+ log("TCF startup error", x);
+ }
+ }
+ }
+ catch (Exception x) {
+ log("TCF startup error", x);
+ }
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TCFCore getDefault() {
+ return plugin;
+ }
+
+ public static TCFBreakpointsModel getBreakpointsModel() {
+ return bp_model;
+ }
+
+ /**
+ * Send error message into Eclipse log.
+ * @param msg - error message test
+ * @param err - exception
+ */
+ public static void log(String msg, Throwable err) {
+ getDefault().getLog().log(new Status(IStatus.ERROR,
+ getDefault().getBundle().getSymbolicName(), IStatus.OK, msg, err));
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java
new file mode 100644
index 000000000..8a555cfc3
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.launch;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+
+import com.windriver.debug.tcf.core.model.ITCFConstants;
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFLaunchDelegate extends LaunchConfigurationDelegate {
+
+ public static final String
+ ATTR_PEER_ID = ITCFConstants.ID_TCF_DEBUG_MODEL + ".PeerID",
+ ATTR_PROGRAM_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramFile",
+ ATTR_PROGRAM_ARGUMENTS = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramArguments",
+ ATTR_WORKING_DIRECTORY = ITCFConstants.ID_TCF_DEBUG_MODEL + ".WorkingDirectory";
+
+ public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+ return new TCFLaunch(configuration, mode);
+ }
+
+ public void launch(final ILaunchConfiguration configuration, final String mode,
+ final ILaunch launch, IProgressMonitor monitor) throws CoreException {
+ if (monitor == null) monitor = new NullProgressMonitor();
+ monitor.beginTask("Launching debugger session", 1); //$NON-NLS-1$
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ String id = configuration.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "");
+ IPeer peer = Protocol.getLocator().getPeers().get(id);
+ if (peer == null) throw new IOException("Cannot locate peer " + id);
+ TCFLaunch.TerminateListener term = null;
+ if (peer instanceof TCFLaunch.TerminateListener) term = (TCFLaunch.TerminateListener)peer;
+ ((TCFLaunch)launch).launchTCF(mode, peer, term);
+ }
+ catch (Throwable e) {
+ ((TCFLaunch)launch).setError(e);
+ }
+ }
+ });
+ monitor.done();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java
new file mode 100644
index 000000000..57f07834f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * TCF source lookup director. For TCF source lookup there is one source lookup
+ * participant.
+ */
+public class TCFSourceLookupDirector extends AbstractSourceLookupDirector {
+
+ public void initializeParticipants() {
+ addParticipants(new ISourceLookupParticipant[] { new TCFSourceLookupParticipant() });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java
new file mode 100644
index 000000000..765476df1
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant;
+
+/**
+ * The TCF source lookup participant knows how to translate a TCF stack frame
+ * into a source file name
+ */
+public class TCFSourceLookupParticipant extends AbstractSourceLookupParticipant {
+
+ public String getSourceName(Object object) throws CoreException {
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java
new file mode 100644
index 000000000..f14abaae0
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate;
+import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer;
+
+/**
+ * Computes the default source lookup path for a TCF launch configuration. The
+ * default source lookup path is the folder or project containing the TCF
+ * program being launched. If the program is not specified, the workspace is
+ * searched by default.
+ */
+public class TCFSourcePathComputerDelegate implements
+ ISourcePathComputerDelegate {
+
+ public ISourceContainer[] computeSourceContainers(
+ ILaunchConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException {
+ ISourceContainer sourceContainer = null;
+ /*
+ * String path =
+ * configuration.getAttribute(IPDAConstants.ATTR_PDA_PROGRAM,
+ * (String)null); if (path != null) { IResource resource =
+ * ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(path));
+ * if (resource != null) { IContainer container = resource.getParent();
+ * if (container.getType() == IResource.PROJECT) { sourceContainer = new
+ * ProjectSourceContainer((IProject)container, false); } else if
+ * (container.getType() == IResource.FOLDER) { sourceContainer = new
+ * FolderSourceContainer(container, false); } } }
+ */
+ if (sourceContainer == null) {
+ sourceContainer = new WorkspaceSourceContainer();
+ }
+ return new ISourceContainer[] { sourceContainer };
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java
new file mode 100644
index 000000000..a78f8127f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+public interface ITCFBreakpointListener {
+
+ public void breakpointStatusChanged(String id);
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java
new file mode 100644
index 000000000..66cba6273
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+public interface ITCFConstants {
+
+ /**
+ * Unique identifier for the TCF debug model
+ */
+ public static final String ID_TCF_DEBUG_MODEL = "com.windriver.debug.tcf";
+
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java
new file mode 100644
index 000000000..3b4e912ab
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.Breakpoint;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpoint extends Breakpoint {
+
+ public static final String MARKER_TYPE = "com.windriver.debug.tcf.breakpoint.marker";
+
+ private static long last_id = 0;
+
+ private static String createNewID() {
+ assert Protocol.isDispatchThread();
+ long id = System.currentTimeMillis();
+ if (id <= last_id) id = last_id + 1;
+ last_id = id;
+ return Long.toHexString(id);
+ }
+
+ private String text;
+
+ public TCFBreakpoint() {
+ }
+
+ public TCFBreakpoint(final IResource resource, Map props) throws DebugException {
+ props.put(IBreakpoints.PROP_ID, createNewID());
+ final Map m = TCFCore.getBreakpointsModel().toMarkerAttributes(props);
+ final IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarker marker = resource.createMarker(MARKER_TYPE);
+ setMarker(marker);
+ marker.setAttributes(m);
+ DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(TCFBreakpoint.this);
+ }
+ };
+ final ISchedulingRule rule = getMarkerRule(resource);
+ Job job = new Job("Add Breakpoint") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ TCFBreakpoint.this.run(getMarkerRule(resource), runnable);
+ }
+ catch (CoreException e) {
+ return e.getStatus();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(rule);
+ job.schedule();
+ }
+
+ public String getModelIdentifier() {
+ return ITCFConstants.ID_TCF_DEBUG_MODEL;
+ }
+
+ public String getText() {
+ if (text == null) {
+ IMarker marker = getMarker();
+ if (marker == null) return null;
+ StringBuffer bf = new StringBuffer();
+ String address = marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ADDRESS, null);
+ if (address != null && address.length() > 0) {
+ bf.append("PC = ");
+ BigInteger n = new BigInteger(address, 10);
+ String s = n.toString(16);
+ int l = Math.min(s.length(), 8);
+ bf.append("0x00000000".substring(0, 10 - l));
+ bf.append(s);
+ }
+ else {
+ String id = marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null);
+ bf.append("BP");
+ bf.append(id);
+ }
+ text = bf.toString();
+ }
+ return text;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java
new file mode 100644
index 000000000..a1998a9e2
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointListener;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.IBreakpointManagerListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointManagerListener {
+
+ private static final String PROP_ID = "ID";
+ private final IBreakpointManager bp_manager = DebugPlugin.getDefault().getBreakpointManager();
+
+ private abstract class BreakpointUpdate implements Runnable {
+
+ private final ILaunch[] launches;
+ private final Map marker_attrs;
+ private final String marker_file;
+
+ IBreakpoints service;
+ IBreakpoints.DoneCommand done;
+ Map tcf_attrs;
+
+ @SuppressWarnings("unchecked")
+ BreakpointUpdate(IBreakpoint breakpoint) throws CoreException, IOException {
+ if (breakpoint == null) {
+ marker_attrs = null;
+ marker_file = null;
+ }
+ else {
+ marker_attrs = new HashMap(breakpoint.getMarker().getAttributes());
+ marker_file = getFilePath(breakpoint.getMarker().getResource());
+ }
+ launches = DebugPlugin.getDefault().getLaunchManager().getLaunches();
+ }
+
+ synchronized void exec() throws InterruptedException {
+ assert !Protocol.isDispatchThread();
+ Protocol.invokeLater(this);
+ wait();
+ }
+
+ public void run() {
+ if (marker_attrs != null) {
+ tcf_attrs = toBreakpointAttributes(marker_file, marker_attrs);
+ }
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFLaunch launch = (TCFLaunch)launches[i];
+ final IChannel channel = launch.getChannel();
+ if (channel == null) continue;
+ if (channel.getState() != IChannel.STATE_OPEN) continue;
+ service = channel.getRemoteService(IBreakpoints.class);
+ if (service == null) continue;
+ done = new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) channel.terminate(error);
+ }
+ };
+ update();
+ }
+ }
+ Protocol.sync(new Runnable() {
+ public void run() {
+ synchronized (BreakpointUpdate.this) {
+ BreakpointUpdate.this.notify();
+ }
+ }
+ });
+ };
+
+ abstract void update();
+ }
+
+ public TCFBreakpointsModel() {
+ bp_manager.addBreakpointListener(this);
+ bp_manager.addBreakpointManagerListener(this);
+ }
+
+ public void dispose() {
+ bp_manager.removeBreakpointListener(this);
+ bp_manager.removeBreakpointManagerListener(this);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void downloadBreakpoints(final IChannel channel, final Runnable done)
+ throws IOException, CoreException {
+ assert Protocol.isDispatchThread();
+ IBreakpoints service = channel.getRemoteService(IBreakpoints.class);
+ if (service != null) {
+ IBreakpoint[] arr = bp_manager.getBreakpoints(ITCFConstants.ID_TCF_DEBUG_MODEL);
+ if (arr != null && arr.length > 0) {
+ Map[] bps = new Map[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ IMarker marker = arr[i].getMarker();
+ String file = getFilePath(marker.getResource());
+ bps[i] = toBreakpointAttributes(file, marker.getAttributes());
+ }
+ service.set(bps, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error == null) done.run();
+ else channel.terminate(error);
+ }
+ });
+ return;
+ }
+ }
+ Protocol.invokeLater(done);
+ }
+
+ public void breakpointManagerEnablementChanged(final boolean enabled) {
+ try {
+ IBreakpoint[] arr = bp_manager.getBreakpoints(ITCFConstants.ID_TCF_DEBUG_MODEL);
+ if (arr == null || arr.length == 0) return;
+ final Set ids = new HashSet();
+ for (int i = 0; i < arr.length; i++) {
+ IMarker marker = arr[i].getMarker();
+ Boolean b = marker.getAttribute(IBreakpoint.ENABLED, Boolean.FALSE);
+ if (!b.booleanValue()) continue;
+ ids.add(marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, (String)null));
+ }
+ if (ids.isEmpty()) return;
+ new BreakpointUpdate(null) {
+ @Override
+ void update() {
+ if (enabled) {
+ service.enable(ids.toArray(new String[ids.size()]), done);
+ }
+ else {
+ service.disable(ids.toArray(new String[ids.size()]), done);
+ }
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ private String getFilePath(IResource resource) throws IOException {
+ if (resource == ResourcesPlugin.getWorkspace().getRoot()) return null;
+ IPath p = resource.getRawLocation();
+ if (p == null) return null;
+ return p.toFile().getCanonicalPath();
+ }
+
+ public void breakpointAdded(IBreakpoint breakpoint) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ service.add(tcf_attrs, done);
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set calcMarkerDeltaKeys(IMarker marker, IMarkerDelta delta) throws CoreException {
+ assert delta.getKind() == IResourceDelta.CHANGED;
+ Map m0 = delta.getAttributes();
+ Map m1 = marker.getAttributes();
+ Set keys = new HashSet();
+ if (m0 != null) keys.addAll(m0.keySet());
+ if (m1 != null) keys.addAll(m1.keySet());
+ for (Iterator i = keys.iterator(); i.hasNext();) {
+ String key = i.next();
+ Object v0 = m0 != null ? m0.get(key) : null;
+ Object v1 = m1 != null ? m1.get(key) : null;
+ if (v0 instanceof String && ((String)v0).length() == 0) v0 = null;
+ if (v1 instanceof String && ((String)v1).length() == 0) v1 = null;
+ if (v0 instanceof Boolean && !((Boolean)v0).booleanValue()) v0 = null;
+ if (v1 instanceof Boolean && !((Boolean)v1).booleanValue()) v1 = null;
+ if ((v0 == null) != (v1 == null)) continue;
+ if (v0 != null && !v0.equals(v1)) continue;
+ i.remove();
+ }
+ return keys;
+ }
+
+ public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ final Set s = calcMarkerDeltaKeys(breakpoint.getMarker(), delta);
+ if (s.isEmpty()) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ if (s.size() == 1 && s.contains(IBreakpoint.ENABLED)) {
+ Boolean enabled = (Boolean)tcf_attrs.get(IBreakpoints.PROP_ENABLED);
+ if (enabled == null || !enabled.booleanValue()) {
+ service.disable(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ else {
+ service.enable(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ }
+ else {
+ service.change(tcf_attrs, done);
+ }
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ service.remove(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ public Map toMarkerAttributes(Map p) {
+ assert Protocol.isDispatchThread();
+ Map m = new HashMap();
+ for (Iterator> i = p.entrySet().iterator(); i.hasNext();) {
+ Map.Entry e = i.next();
+ String key = e.getKey();
+ Object val = e.getValue();
+ if (key.equals(IBreakpoints.PROP_ENABLED)) continue;
+ if (key.equals(IBreakpoints.PROP_FILE)) continue;
+ if (key.equals(IBreakpoints.PROP_LINE)) continue;
+ if (key.equals(IBreakpoints.PROP_COLUMN)) continue;
+ m.put(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + key, val);
+ }
+ Boolean enabled = (Boolean)p.get(IBreakpoints.PROP_ENABLED);
+ if (enabled == null) m.put(IBreakpoint.ENABLED, Boolean.FALSE);
+ else m.put(IBreakpoint.ENABLED, enabled);
+ m.put(IBreakpoint.REGISTERED, Boolean.TRUE);
+ m.put(IBreakpoint.PERSISTED, Boolean.TRUE);
+ m.put(IBreakpoint.ID, ITCFConstants.ID_TCF_DEBUG_MODEL);
+ String msg = "";
+ if (p.get(IBreakpoints.PROP_ADDRESS) != null) msg += p.get(IBreakpoints.PROP_ADDRESS);
+ m.put(IMarker.MESSAGE, "Breakpoint: " + msg);
+ Number line = (Number)p.get(IBreakpoints.PROP_LINE);
+ if (line != null) {
+ m.put(IMarker.LINE_NUMBER, Integer.toString(line.intValue() + 1));
+ Number column = (Number)p.get(IBreakpoints.PROP_COLUMN);
+ if (column != null) {
+ m.put(IMarker.CHAR_START, column.toString());
+ m.put(IMarker.CHAR_END, Integer.toString(column.intValue() + 1));
+ }
+ }
+ return m;
+ }
+
+ public Map toBreakpointAttributes(String file, Map p) {
+ assert Protocol.isDispatchThread();
+ Map m = new HashMap();
+ for (Iterator> i = p.entrySet().iterator(); i.hasNext();) {
+ Map.Entry e = i.next();
+ String key = e.getKey();
+ Object val = e.getValue();
+ if (!key.startsWith(ITCFConstants.ID_TCF_DEBUG_MODEL)) continue;
+ m.put(key.substring(ITCFConstants.ID_TCF_DEBUG_MODEL.length() + 1), val);
+ }
+ Boolean enabled = (Boolean)p.get(IBreakpoint.ENABLED);
+ if (enabled != null && enabled.booleanValue() && bp_manager.isEnabled()) {
+ m.put(IBreakpoints.PROP_ENABLED, enabled);
+ }
+ if (file != null) {
+ m.put(IBreakpoints.PROP_FILE, file);
+ String line = (String)p.get(IMarker.LINE_NUMBER);
+ if (line != null) {
+ m.put(IBreakpoints.PROP_LINE, new Integer(Integer.parseInt(line) - 1));
+ String column = (String)p.get(IMarker.CHAR_START);
+ if (column != null) {
+ m.put(IBreakpoints.PROP_COLUMN, new Integer(column));
+ }
+ }
+ }
+ return m;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java
new file mode 100644
index 000000000..a9a6cb735
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpointsStatus {
+
+ private final IBreakpoints service;
+ private final Map> status = new HashMap>();
+ private final Set listeners = new HashSet();
+
+ private static final Map status_not_supported = new HashMap();
+
+ static {
+ status_not_supported.put(IBreakpoints.STATUS_ERROR, "Not supported");
+ }
+
+ TCFBreakpointsStatus(TCFLaunch launch) {
+ assert Protocol.isDispatchThread();
+ service = launch.getChannel().getRemoteService(IBreakpoints.class);
+ if (service != null) {
+ service.addListener(new IBreakpoints.BreakpointsListener() {
+
+ public void breakpointStatusChanged(String id, Map status) {
+ assert Protocol.isDispatchThread();
+ TCFBreakpointsStatus.this.status.put(id, status);
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ i.next().breakpointStatusChanged(id);
+ }
+ }
+ });
+ }
+ }
+
+ public Map getStatus(String id) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ if (service == null) return status_not_supported;
+ return status.get(id);
+ }
+
+ public Map getStatus(IBreakpoint bp) {
+ if (!bp.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return status_not_supported;
+ IMarker marker = bp.getMarker();
+ if (marker == null) return null;
+ return getStatus(marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null));
+ }
+
+ public void addListener(ITCFBreakpointListener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.add(listener);
+ }
+
+ public void removeListener(ITCFBreakpointListener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java
new file mode 100644
index 000000000..f754eb7c2
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.DebugException;
+
+import com.windriver.debug.tcf.core.TCFCore;
+
+public class TCFError extends DebugException {
+
+ private static final long serialVersionUID = -4261097789666829020L;
+
+ public TCFError(Throwable exception) {
+ super(new Status(exception));
+ }
+
+ private static class Status implements IStatus {
+
+ private final Throwable exception;
+
+ private Status(Throwable exception) {
+ this.exception = exception;
+ }
+
+ public IStatus[] getChildren() {
+ return null;
+ }
+
+ public int getCode() {
+ return 1;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public String getMessage() {
+ return exception.getMessage();
+ }
+
+ public String getPlugin() {
+ return TCFCore.PLUGIN_ID;
+ }
+
+ public int getSeverity() {
+ return ERROR;
+ }
+
+ public boolean isMultiStatus() {
+ return false;
+ }
+
+ public boolean isOK() {
+ return false;
+ }
+
+ public boolean matches(int severityMask) {
+ return false;
+ }
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java
new file mode 100644
index 000000000..a7a07eda7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.core.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.Launch;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IProcesses;
+import com.windriver.tcf.api.services.IProcesses.ProcessContext;
+
+public class TCFLaunch extends Launch {
+
+ public interface Listener {
+
+ public void onConnected(TCFLaunch launch);
+
+ public void onDisconnected(TCFLaunch launch);
+
+ }
+
+ public interface TerminateListener {
+
+ public boolean canTerminate();
+
+ public boolean isTerminated();
+
+ public void terminate(Runnable done);
+ }
+
+ private static final Collection listeners = new ArrayList();
+
+ private IChannel channel;
+ private Throwable error;
+ private TerminateListener terminate_listener;
+ private TCFBreakpointsStatus breakpoints_status;
+ private String mode;
+ private boolean connecting;
+ private ProcessContext process;
+
+ public TCFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
+ super(launchConfiguration, mode, null);
+ }
+
+ private void onConnected() {
+ try {
+ final Runnable done = new Runnable() {
+ public void run() {
+ connecting = false;
+ for (Listener l : listeners) l.onConnected(TCFLaunch.this);
+ fireChanged();
+ }
+ };
+ if (mode.equals(ILaunchManager.DEBUG_MODE)) {
+ TCFCore.getBreakpointsModel().downloadBreakpoints(channel, new Runnable() {
+ public void run() {
+ if (channel.getState() != IChannel.STATE_OPEN) return;
+ breakpoints_status = new TCFBreakpointsStatus(TCFLaunch.this);
+ downloadApplication(done);
+ }
+ });
+ }
+ else {
+ downloadApplication(done);
+ }
+ }
+ catch (Exception x) {
+ channel.terminate(x);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void downloadApplication(final Runnable done) {
+ try {
+ ILaunchConfiguration cfg = getLaunchConfiguration();
+ final String file = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, "");
+ if (file.length() == 0) {
+ Protocol.invokeLater(done);
+ return;
+ }
+ final String dir = cfg.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "");
+ final String args = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "");
+ final Map env = cfg.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map)null);
+ final boolean append = cfg.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
+ final boolean attach = mode.equals(ILaunchManager.DEBUG_MODE);
+ final IProcesses ps = channel.getRemoteService(IProcesses.class);
+ if (ps == null) throw new Exception("Target does not provide Processes service");
+ IProcesses.DoneGetEnvironment done_env = new IProcesses.DoneGetEnvironment() {
+ public void doneGetEnvironment(IToken token, Exception error, Map def) {
+ if (error != null) {
+ channel.terminate(error);
+ return;
+ }
+ Map vars = new HashMap();
+ if (append) vars.putAll(def);
+ if (env != null) vars.putAll(env);
+ ps.start(dir, file, toArgsArray(args), vars, attach, new IProcesses.DoneStart() {
+ public void doneStart(IToken token, Exception error, ProcessContext process) {
+ if (error != null) {
+ channel.terminate(error);
+ return;
+ }
+ TCFLaunch.this.process = process;
+ Protocol.invokeLater(done);
+ }
+ });
+ }
+ };
+ if (append) ps.getEnvironment(done_env);
+ else done_env.doneGetEnvironment(null, null, null);
+ }
+ catch (Exception x) {
+ channel.terminate(x);
+ }
+ }
+
+ private String[] toArgsArray(String cmd) {
+ int i = 0;
+ int l = cmd.length();
+ List arr = new ArrayList();
+ for (;;) {
+ while (i < l && cmd.charAt(i) == ' ') i++;
+ if (i >= l) break;
+ String s = null;
+ if (cmd.charAt(i) == '"') {
+ i++;
+ StringBuffer bf = new StringBuffer();
+ while (i < l) {
+ char ch = cmd.charAt(i++);
+ if (ch == '"') break;
+ if (ch == '\\' && i < l) ch = cmd.charAt(i++);
+ bf.append(ch);
+ }
+ s = bf.toString();
+ }
+ else {
+ int i0 = i;
+ while (i < l && cmd.charAt(i) != ' ') i++;
+ s = cmd.substring(i0, i);
+ }
+ arr.add(s);
+ }
+ return arr.toArray(new String[arr.size()]);
+ }
+
+ private void onDisconnected(Throwable error) {
+ this.error = error;
+ breakpoints_status = null;
+ connecting = false;
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ i.next().onDisconnected(this);
+ }
+ if (DebugPlugin.getDefault() != null) fireTerminate();
+ }
+
+ /*--------------------------------------------------------------------------------------------*/
+
+ public Throwable getError() {
+ return error;
+ }
+
+ public void setError(Throwable x) {
+ if (error != null) return;
+ error = x;
+ if (channel != null && channel.getState() == IChannel.STATE_OPEN) {
+ channel.terminate(x);
+ }
+ fireChanged();
+ }
+
+ public TCFBreakpointsStatus getBreakpointsStatus() {
+ return breakpoints_status;
+ }
+
+ public static void addListener(Listener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.add(listener);
+ }
+
+ public static void removeListener(Listener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.remove(listener);
+ }
+
+ public IChannel getChannel() {
+ assert Protocol.isDispatchThread();
+ if (channel == null || channel.getState() != IChannel.STATE_OPEN) return null;
+ return channel;
+ }
+
+ public IProcesses.ProcessContext getProcessContext() {
+ return process;
+ }
+
+ public boolean isConnecting() {
+ return connecting;
+ }
+
+ public IPeer getPeer() {
+ assert Protocol.isDispatchThread();
+ return channel.getRemotePeer();
+ }
+
+ public V getService(Class cls) {
+ assert Protocol.isDispatchThread();
+ return channel.getRemoteService(cls);
+ }
+
+ public boolean canTerminate() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (terminate_listener == null) res[0] = false;
+ else res[0] = terminate_listener.canTerminate();
+ }
+ });
+ return res[0];
+ }
+
+ public boolean isTerminated() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (channel == null || channel.getState() == IChannel.STATE_CLOSED) res[0] = true;
+ else if (terminate_listener == null) res[0] = false;
+ else res[0] = terminate_listener.isTerminated();
+ }
+ });
+ return res[0];
+ }
+
+ public void terminate() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (terminate_listener == null) return;
+ terminate_listener.terminate(new Runnable() {
+ public void run() {
+ fireTerminate();
+ }
+ });
+ }
+ });
+ }
+
+ public void terminate(Runnable done) {
+ if (terminate_listener == null) done.run();
+ else terminate_listener.terminate(done);
+ }
+
+ public boolean canDisconnect() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = channel != null && channel.getState() != IChannel.STATE_CLOSED;
+ }
+ });
+ return res[0];
+ }
+
+ public boolean isDisconnected() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = channel == null || channel.getState() == IChannel.STATE_CLOSED;
+ }
+ });
+ return res[0];
+ }
+
+ public void disconnect() throws DebugException {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ channel.close();
+ }
+ fireTerminate();
+ }
+ });
+ }
+
+ public void launchTCF(String mode, IPeer peer, TerminateListener terminate_listener) throws DebugException {
+ assert Protocol.isDispatchThread();
+ this.mode = mode;
+ this.terminate_listener = terminate_listener;
+ connecting = true;
+ channel = peer.openChannel();
+ channel.addChannelListener(new IChannel.IChannelListener() {
+
+ public void onChannelOpened() {
+ onConnected();
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable error) {
+ channel.removeChannelListener(this);
+ onDisconnected(error);
+ }
+
+ });
+ assert channel.getState() == IChannel.STATE_OPENNING;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/.classpath b/plugins/com.windriver.debug.tcf.ui/.classpath
new file mode 100644
index 000000000..03ba07a5f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/com.windriver.debug.tcf.ui/.cvsignore b/plugins/com.windriver.debug.tcf.ui/.cvsignore
new file mode 100644
index 000000000..ba077a403
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/com.windriver.debug.tcf.ui/.project b/plugins/com.windriver.debug.tcf.ui/.project
new file mode 100644
index 000000000..fb751e4e7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.project
@@ -0,0 +1,28 @@
+
+
+ com.windriver.debug.tcf.ui
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs b/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..78e20524b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#Mon Sep 10 12:26:30 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF b/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..4743cd6da
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.debug.tcf.ui;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.debug.tcf.ui.TCFUI
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.debug.ui,
+ com.windriver.debug.tcf.core,
+ com.windriver.tcf.api
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.debug.tcf.ui.adapters,
+ com.windriver.debug.tcf.ui.launch
diff --git a/plugins/com.windriver.debug.tcf.ui/about.html b/plugins/com.windriver.debug.tcf.ui/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/about.html
@@ -0,0 +1,28 @@
+
+
+
+
+About
+
+
+
About This Content
+
+
January 10, 2008
+
License
+
+
The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+
If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at http://www.eclipse.org.
+
+
+
\ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.ui/build.properties b/plugins/com.windriver.debug.tcf.ui/build.properties
new file mode 100644
index 000000000..bbc49de86
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ bin/
+
diff --git a/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif b/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif
new file mode 100644
index 000000000..44660b5f0
Binary files /dev/null and b/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif differ
diff --git a/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif b/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif
new file mode 100644
index 000000000..3198679ae
Binary files /dev/null and b/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif differ
diff --git a/plugins/com.windriver.debug.tcf.ui/plugin.properties b/plugins/com.windriver.debug.tcf.ui/plugin.properties
new file mode 100644
index 000000000..c791ca4f7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 Wind River Systems, Inc. and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Wind River Systems - initial implementation
+###############################################################################
+pluginName = TCF/Eclipse Debugger Integration UI
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.debug.tcf.ui/plugin.xml b/plugins/com.windriver.debug.tcf.ui/plugin.xml
new file mode 100644
index 000000000..cc3b88d16
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/plugin.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java
new file mode 100644
index 000000000..5ce3dbb2b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+import com.windriver.debug.tcf.ui.model.TCFModelManager;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TCFUI extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.debug.tcf.ui";
+
+ // The shared instance
+ private static TCFUI plugin;
+ private static TCFModelManager model_manager;
+
+ private static final BundleListener bundle_listener = new BundleListener() {
+ public void bundleChanged(BundleEvent event) {
+ if (plugin != null && event.getBundle() == plugin.getBundle() &&
+ plugin.getBundle().getState() != Bundle.ACTIVE && model_manager != null) {
+ model_manager.dispose();
+ model_manager = null;
+ }
+ }
+ };
+
+ /**
+ * The constructor
+ */
+ public TCFUI() {
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ context.addBundleListener(bundle_listener);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TCFUI getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the shared TCFModel instance
+ *
+ * @return the shared TCFModel instance
+ */
+ public static TCFModelManager getModelManager() {
+ if (plugin != null && model_manager == null && plugin.getBundle().getState() == Bundle.ACTIVE) {
+ model_manager = new TCFModelManager();
+ }
+ return model_manager;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java
new file mode 100644
index 000000000..c5f428dac
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
+
+import com.windriver.debug.tcf.ui.commands.BreakpointCommand;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+
+public class TCFBreakpointAdapterFactory implements IAdapterFactory {
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Object obj, Class adapterType) {
+ if (obj instanceof TCFNode) {
+ return new BreakpointCommand();
+ }
+ System.out.println(obj.getClass().getName() + " -> " + adapterType);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return new Class[]{ IToggleBreakpointsTarget.class, IToggleBreakpointsTargetExtension.class };
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java
new file mode 100644
index 000000000..4159fcea4
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFLaunchAdapterFactory implements IAdapterFactory {
+
+ @SuppressWarnings("unchecked")
+ private final Class[] adapter_list = {
+ IElementContentProvider.class,
+ IElementLabelProvider.class,
+ IModelProxyFactory.class,
+ ITerminateHandler.class
+ };
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(final Object from, final Class to) {
+ if (from instanceof TCFLaunch) {
+ final Object[] res = new Object[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch launch = (TCFLaunch)from;
+ TCFModel model = TCFUI.getModelManager().getModel(launch);
+ if (model != null) {
+ if (to.isInstance(model)) {
+ res[0] = model;
+ return;
+ }
+ Object cmd = model.getCommand(to);
+ if (cmd != null) {
+ res[0] = cmd;
+ return;
+ }
+ }
+ }
+ });
+ if (res[0] != null) return res[0];
+ }
+ System.err.println(from.getClass().getName() + " -> " + to);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return adapter_list;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java
new file mode 100644
index 000000000..d8ad27b10
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+public class TCFModelSelectionPolicyFactoryAdapter implements IModelSelectionPolicyFactory {
+
+ public IModelSelectionPolicy createModelSelectionPolicyAdapter(
+ Object element, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java
new file mode 100644
index 000000000..12ec02760
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+
+import com.windriver.debug.tcf.core.model.TCFBreakpoint;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class BreakpointCommand implements IToggleBreakpointsTargetExtension {
+
+ public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
+ Object obj = ((IStructuredSelection)selection).getFirstElement();
+ if (obj instanceof TCFNode) {
+ final TCFNode node = (TCFNode)obj;
+ if (node == null) return false;
+ final boolean[] res = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = node.getAddress() != null;
+ }
+ });
+ return res[0];
+ }
+ else {
+ return false;
+ }
+ }
+
+ public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ Object obj = ((IStructuredSelection)selection).getFirstElement();
+ if (obj instanceof TCFNode) {
+ final TCFNode node = (TCFNode)obj;
+ if (node == null) return;
+ final CoreException[] res = new CoreException[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ String addr = node.getAddress();
+ if (addr == null) return;
+ Map m = new HashMap();
+ m.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ m.put(IBreakpoints.PROP_ADDRESS, addr);
+ new TCFBreakpoint(ResourcesPlugin.getWorkspace().getRoot(), m);
+ }
+ catch (CoreException x) {
+ res[0] = x;
+ }
+ }
+ });
+ if (res[0] != null) throw res[0];
+ }
+ }
+
+ public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java
new file mode 100644
index 000000000..3ef011689
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IDisconnectHandler;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+
+public class DisconnectCommand implements IDisconnectHandler {
+
+ private final TCFModel model;
+
+ public DisconnectCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ monitor.setEnabled(model.getLaunch().canDisconnect());
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ try {
+ model.getLaunch().disconnect();
+ monitor.setStatus(Status.OK_STATUS);
+ }
+ catch (DebugException x) {
+ monitor.setStatus(x.getStatus());
+ }
+ done();
+ }
+ };
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java
new file mode 100644
index 000000000..f4ecd5049
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IResumeHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class ResumeCommand implements IResumeHandler {
+
+ private final TCFModel model;
+
+ public ResumeCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else if (ctx.isContainer()) {
+ if (ctx.canResume(IRunControl.RM_RESUME)) res = true;
+ node = null;
+ }
+ else {
+ if (node.isSuspended() && ctx.canResume(IRunControl.RM_RESUME)) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java
new file mode 100644
index 000000000..76e09d274
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepIntoCommand implements IStepIntoHandler {
+
+ private final TCFModel model;
+
+ public StepIntoCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java
new file mode 100644
index 000000000..3a8170fbb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepOverCommand implements IStepOverHandler {
+
+ private final TCFModel model;
+
+ public StepOverCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java
new file mode 100644
index 000000000..8975a8155
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepReturnCommand implements IStepReturnHandler {
+
+ private final TCFModel model;
+
+ public StepReturnCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java
new file mode 100644
index 000000000..45419650e
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class SuspendCommand implements ISuspendHandler {
+
+ private final TCFModel model;
+
+ public SuspendCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else if (ctx.isContainer()) {
+ if (ctx.canSuspend()) res = true;
+ node = null;
+ }
+ else {
+ if (node.isRunning() && ctx.canSuspend()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.suspend(new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot suspend", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java
new file mode 100644
index 000000000..81f16e12a
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TerminateCommand implements ITerminateHandler {
+
+ private final TCFModel model;
+
+ public TerminateCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx != null && ctx.canTerminate()) {
+ res = true;
+ node = null;
+ }
+ else {
+ node = node.getParent();
+ if (node == null && model.getLaunch().canTerminate()) res = true;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set set = new HashSet();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx != null && ctx.canTerminate()) {
+ set.add(ctx);
+ node = null;
+ }
+ else {
+ node = node.getParent();
+ if (node == null) set.add(null);
+ }
+ }
+ }
+ final Set cmds = new HashSet();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ if (ctx == null) {
+ cmds.add(null);
+ model.getLaunch().terminate(new Runnable() {
+ public void run() {
+ assert cmds.contains(null);
+ cmds.remove(null);
+ if (cmds.isEmpty()) done();
+ }
+ });
+ }
+ else {
+ cmds.add(ctx.terminate(new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ }
+ };
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java
new file mode 100644
index 000000000..082d741bc
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.launch;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.StringVariableSelectionDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Text;
+
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.debug.tcf.ui.TCFUI;
+
+public class TCFArgumentsTab extends AbstractLaunchConfigurationTab {
+
+ private Text text_arguments;
+ private Button button_variables;
+ private Text text_working_dir;
+ private Button button_default_dir;
+ private Image image;
+
+ public void createControl(Composite parent) {
+ Font font = parent.getFont();
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ comp.setLayout(layout);
+ comp.setFont(font);
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ comp.setLayoutData(gd);
+ setControl(comp);
+
+ createArgumentsGroup(comp);
+ createWorkingDirGroup(comp);
+
+ URL url = FileLocator.find(TCFUI.getDefault().getBundle(),
+ new Path("icons/arguments_tab.gif"), null);
+ ImageDescriptor descriptor = null;
+ if (url == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ else {
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image = descriptor.createImage(parent.getDisplay());
+ }
+
+ private void createArgumentsGroup(Composite comp) {
+ Font font = comp.getFont();
+
+ Group group = new Group(comp, SWT.NONE);
+ group.setFont(font);
+ group.setLayout(new GridLayout());
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+ group.setText("Program Arguments");
+
+ text_arguments = new Text(group, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.heightHint = 40;
+ gd.widthHint = 100;
+ text_arguments.setLayoutData(gd);
+ text_arguments.setFont(font);
+ text_arguments.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent evt) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+ button_variables= createPushButton(group, "Variables", null);
+ gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+ button_variables.setLayoutData(gd);
+ button_variables.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent arg0) {
+ handleVariablesButtonSelected(text_arguments);
+ }
+ });
+ }
+
+ private void createWorkingDirGroup(Composite comp) {
+ Font font = comp.getFont();
+
+ Group group = new Group(comp, SWT.NONE);
+ GridLayout workingDirLayout = new GridLayout();
+ workingDirLayout.makeColumnsEqualWidth = false;
+ group.setLayout(workingDirLayout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ group.setFont(font);
+ group.setText("Working directory");
+
+ text_working_dir = new Text(group, SWT.SINGLE | SWT.BORDER);
+ text_working_dir.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ text_working_dir.setFont(font);
+
+ button_default_dir = new Button(group, SWT.CHECK);
+ button_default_dir.setText("Use default");
+ button_default_dir.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ button_default_dir.setFont(font);
+ }
+
+ @Override
+ public void dispose() {
+ if (image != null) {
+ image.dispose();
+ image = null;
+ }
+ super.dispose();
+ }
+
+ /**
+ * A variable entry button has been pressed for the given text
+ * field. Prompt the user for a variable and enter the result
+ * in the given field.
+ */
+ private void handleVariablesButtonSelected(Text textField) {
+ String variable = getVariable();
+ if (variable != null) textField.append(variable);
+ }
+
+ /**
+ * Prompts the user to choose and configure a variable and returns
+ * the resulting string, suitable to be used as an attribute.
+ */
+ private String getVariable() {
+ StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
+ dialog.open();
+ return dialog.getVariableExpression();
+ }
+
+ public boolean isValid(ILaunchConfiguration config) {
+ return true;
+ }
+
+ public void setDefaults(ILaunchConfigurationWorkingCopy config) {
+ config.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, (String)null);
+ config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, (String)null);
+ }
+
+ public void initializeFrom(ILaunchConfiguration configuration) {
+ try {
+ text_arguments.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$
+ text_working_dir.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "")); //$NON-NLS-1$
+ }
+ catch (CoreException e) {
+ setErrorMessage("Cannot read launch configuration: " + e);
+ }
+ }
+
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ configuration.setAttribute(
+ TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS,
+ getAttributeValueFrom(text_arguments));
+ configuration.setAttribute(
+ TCFLaunchDelegate.ATTR_WORKING_DIRECTORY,
+ getAttributeValueFrom(text_working_dir));
+ }
+
+ protected String getAttributeValueFrom(Text text) {
+ String content = text.getText().trim();
+ content = content.replaceAll("\r\n", "\n"); // eliminate Windows \r line delimiter
+ if (content.length() > 0) return content;
+ return null;
+ }
+
+ public String getName() {
+ return "Arguments";
+ }
+
+ @Override
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java
new file mode 100644
index 000000000..3e9168d3c
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java
@@ -0,0 +1,718 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.launch;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ * Launch configuration dialog tab to specify the Target Communication Framework
+ * configuration.
+ */
+public class TCFMainTab extends AbstractLaunchConfigurationTab {
+
+ private Text peer_id_text;
+ private Text program_text;
+ private Tree peer_tree;
+ private PeerInfo[] peer_info;
+ private Display display;
+
+ private final Map listeners = new HashMap();
+ private final Map image_cache = new HashMap();
+
+ private static class PeerInfo {
+ PeerInfo parent;
+ int index;
+ PeerInfo[] children;
+ Map attrs;
+ }
+
+ private class LocatorListener implements ILocator.LocatorListener {
+
+ private final PeerInfo parent;
+
+ LocatorListener(PeerInfo parent) {
+ this.parent = parent;
+ }
+
+ public void peerAdded(IPeer peer) {
+ if (display == null) return;
+ final Map attrs = new HashMap(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ PeerInfo[] buf = new PeerInfo[arr.length + 1];
+ System.arraycopy(arr, 0, buf, 0, arr.length);
+ PeerInfo info = new PeerInfo();
+ info.parent = parent;
+ info.index = arr.length;
+ info.attrs = attrs;
+ buf[arr.length] = info;
+ if (parent == null) {
+ peer_info = buf;
+ }
+ else {
+ parent.children = buf;
+ }
+ updateItems();
+ }
+ });
+ }
+
+ public void peerChanged(IPeer peer) {
+ if (display == null) return;
+ final Map attrs = new HashMap(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ String id = attrs.get(IPeer.ATTR_ID);
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) {
+ arr[i].attrs = attrs;
+ updateItems();
+ }
+ }
+ assert false;
+ }
+ });
+ }
+
+ public void peerRemoved(final String id) {
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ PeerInfo[] buf = new PeerInfo[arr.length - 1];
+ int j = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (!arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) {
+ buf[j++] = arr[i];
+ }
+ }
+ if (parent == null) {
+ peer_info = buf;
+ }
+ else {
+ parent.children = buf;
+ }
+ updateItems();
+ }
+ });
+ }
+
+ private void updateItems() {
+ PeerInfo[] arr = null;
+ TreeItem[] items = null;
+ if (parent == null) {
+ arr = peer_info;
+ peer_tree.setItemCount(arr.length);
+ items = peer_tree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ arr = parent.children;
+ item.setItemCount(arr.length);
+ items = item.getItems();
+ }
+ assert items.length == arr.length;
+ for (int i = 0; i < items.length; i++) {
+ fillItem(items[i], arr[i]);
+ }
+ String id = peer_id_text.getText();
+ TreeItem item = findItem(findPeerInfo(id));
+ if (item != null) peer_tree.setSelection(item);
+ }
+ }
+
+ public void createControl(Composite parent) {
+ display = parent.getDisplay();
+
+ Font font = parent.getFont();
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ comp.setLayout(layout);
+ comp.setFont(font);
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ comp.setLayoutData(gd);
+ setControl(comp);
+
+ createTargetGroup(comp);
+ createProgramGroup(comp);
+ }
+
+ private void createTargetGroup(Composite parent) {
+ Font font = parent.getFont();
+
+ Group group = new Group(parent, SWT.NONE);
+ GridLayout top_layout = new GridLayout();
+ top_layout.verticalSpacing = 0;
+ top_layout.numColumns = 2;
+ group.setLayout(top_layout);
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+ group.setFont(font);
+ group.setText("Target");
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Label host_label = new Label(group, SWT.NONE);
+ host_label.setText("Target ID:");
+ host_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ host_label.setFont(font);
+
+ peer_id_text = new Text(group, SWT.SINGLE | SWT.BORDER);
+ peer_id_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ peer_id_text.setFont(font);
+ peer_id_text.setEditable(false);
+ peer_id_text.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Label peer_label = new Label(group, SWT.NONE);
+ peer_label.setText("Available targets:");
+ peer_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ peer_label.setFont(font);
+
+ if (peer_info == null) loadPeerInfo(null);
+
+ peer_tree = new Tree(group, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1);
+ gd.minimumHeight = 150;
+ peer_tree.setLayoutData(gd);
+
+ for (int i = 0; i < 5; i++) {
+ TreeColumn column = new TreeColumn(peer_tree, SWT.LEAD, i);
+ column.setMoveable(true);
+ switch (i) {
+ case 0:
+ column.setText("Name");
+ column.setWidth(120);
+ break;
+ case 1:
+ column.setText("OS");
+ column.setWidth(100);
+ break;
+ case 2:
+ column.setText("Transport");
+ column.setWidth(60);
+ break;
+ case 3:
+ column.setText("Host");
+ column.setWidth(100);
+ break;
+ case 4:
+ column.setText("Port");
+ column.setWidth(40);
+ break;
+ }
+ }
+
+ peer_tree.setHeaderVisible(true);
+ peer_tree.setFont(font);
+ peer_tree.setItemCount(peer_info.length);
+ peer_tree.addListener(SWT.SetData, new Listener() {
+ public void handleEvent(Event event) {
+ TreeItem item = (TreeItem)event.item;
+ PeerInfo info = findPeerInfo(item);
+ fillItem(item, info);
+ }
+ });
+ peer_tree.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selections = peer_tree.getSelection();
+ if (selections.length > 0) {
+ assert selections.length == 1;
+ PeerInfo info = findPeerInfo(selections[0]);
+ peer_id_text.setText(getPath(info));
+ }
+ }
+ });
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Button button_test = new Button(group, SWT.PUSH);
+ button_test.setText("Run &Diagnostics");
+ button_test.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ button_test.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selection = peer_tree.getSelection();
+ if (selection.length > 0) {
+ assert selection.length == 1;
+ runDiagnostics(selection[0], false);
+ }
+ }
+ });
+
+ Button button_loop = new Button(group, SWT.PUSH);
+ button_loop.setText("Diagnostics &Loop");
+ button_loop.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ button_loop.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selection = peer_tree.getSelection();
+ if (selection.length > 0) {
+ assert selection.length == 1;
+ runDiagnostics(selection[0], true);
+ }
+ }
+ });
+ }
+
+ private void createProgramGroup(Composite parent) {
+ display = parent.getDisplay();
+
+ Font font = parent.getFont();
+
+ Group group = new Group(parent, SWT.NONE);
+ GridLayout top_layout = new GridLayout();
+ group.setLayout(top_layout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ group.setFont(font);
+ group.setText("Program");
+
+ program_text = new Text(group, SWT.SINGLE | SWT.BORDER);
+ program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ program_text.setFont(font);
+ }
+
+ @Override
+ public void dispose() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (Iterator i = listeners.keySet().iterator(); i.hasNext();) {
+ LocatorListener listener = i.next();
+ listeners.get(listener).removeListener(listener);
+ }
+ listeners.clear();
+ peer_info = null;
+ display = null;
+ }
+ });
+ for (Image i : image_cache.values()) i.dispose();
+ image_cache.clear();
+ super.dispose();
+ }
+
+ public String getName() {
+ return "Main";
+ }
+
+ @Override
+ public Image getImage() {
+ return getImage("icons/tcf.gif");
+ }
+
+ public void initializeFrom(ILaunchConfiguration configuration) {
+ try {
+ String id = configuration.getAttribute(
+ TCFLaunchDelegate.ATTR_PEER_ID, (String)null);
+ if (id != null) {
+ peer_id_text.setText(id);
+ TreeItem item = findItem(findPeerInfo(id));
+ if (item != null) peer_tree.setSelection(item);
+ }
+ program_text.setText(configuration.getAttribute(
+ TCFLaunchDelegate.ATTR_PROGRAM_FILE, "")); //$NON-NLS-1$
+ }
+ catch (CoreException e) {
+ setErrorMessage(e.getMessage());
+ }
+ }
+
+ public boolean isValid(ILaunchConfiguration launchConfig) {
+ String id = peer_id_text.getText().trim();
+ if (id.length() == 0) {
+ setErrorMessage("Specify a target ID");
+ return false;
+ }
+ setErrorMessage(null);
+ return super.isValid(launchConfig);
+ }
+
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ String id = peer_id_text.getText().trim();
+ if (id.length() == 0) id = null;
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, id);
+ String nm = program_text.getText().trim();
+ if (nm.length() == 0) nm = null;
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, nm);
+ }
+
+ public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "TCFLocal");
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, (String)null);
+ }
+
+ private void loadPeerInfo(final PeerInfo parent) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (parent == null) {
+ ILocator locator = Protocol.getLocator();
+ Map map = locator.getPeers();
+ PeerInfo[] buf = new PeerInfo[map.size()];
+ int n = 0;
+ for (Iterator i = map.values().iterator(); i.hasNext();) {
+ IPeer p = i.next();
+ PeerInfo info = new PeerInfo();
+ info.parent = parent;
+ info.index = n;
+ info.attrs = new HashMap(p.getAttributes());
+ buf[n++] = info;
+ }
+ LocatorListener listener = new LocatorListener(parent);
+ listeners.put(listener, locator);
+ locator.addListener(listener);
+ assert peer_info == null;
+ peer_info = buf;
+ }
+ else {
+ PeerInfo[] buf = new PeerInfo[0];
+ assert parent.children == null;
+ parent.children = buf;
+ }
+ }
+ });
+ }
+
+ private PeerInfo findPeerInfo(TreeItem item) {
+ TreeItem parent = item.getParentItem();
+ if (parent == null) return peer_info[peer_tree.indexOf(item)];
+ PeerInfo info = findPeerInfo(parent);
+ if (info.children == null) loadPeerInfo(info);
+ return info.children[parent.indexOf(item)];
+ }
+
+ private PeerInfo findPeerInfo(String path) {
+ int i = path.lastIndexOf('/');
+ String id = null;
+ PeerInfo[] arr = null;
+ if (i < 0) {
+ if (peer_info == null) loadPeerInfo(null);
+ arr = peer_info;
+ id = path;
+ }
+ else {
+ PeerInfo p = findPeerInfo(path.substring(0, i));
+ if (p == null) return null;
+ if (p.children == null) loadPeerInfo(p);
+ arr = p.children;
+ id = path.substring(i + 1);
+ }
+ for (int n = 0; n < arr.length; n++) {
+ if (arr[n].attrs.get(IPeer.ATTR_ID).equals(id)) return arr[n];
+ }
+ return null;
+ }
+
+ private TreeItem findItem(PeerInfo info) {
+ if (info == null) return null;
+ if (info.parent == null) {
+ return peer_tree.getItem(info.index);
+ }
+ TreeItem i = findItem(info.parent);
+ if (i == null) return null;
+ peer_tree.showItem(i);
+ return i.getItem(info.index);
+ }
+
+ private interface DoneFindPeer {
+ void doneFindPeer(Collection errors, IPeer peer);
+ }
+
+ private void findPeer(TreeItem item, final DoneFindPeer done) {
+ assert display != null;
+ assert Thread.currentThread() == display.getThread();
+ final String path = getPath(findPeerInfo(item));
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ final Collection errors = new ArrayList();
+ try {
+ final int i = path.lastIndexOf('/');
+ if (i < 0) {
+ done.doneFindPeer(errors, Protocol.getLocator().getPeers().get(path));
+ }
+ else {
+ openChannel(path.substring(0, i), errors, new DoneOpenChannel() {
+ public void doneOpenChannel(IChannel channel) {
+ IPeer peer = null;
+ if (channel != null) {
+ ILocator locator = channel.getRemoteService(ILocator.class);
+ peer = locator.getPeers().get(path.substring(i + 1));
+ channel.close();
+ }
+ done.doneFindPeer(errors, peer);
+ }
+ });
+ }
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.doneFindPeer(errors, null);
+ }
+ }
+ });
+ }
+
+ private interface DoneOpenChannel {
+ void doneOpenChannel(IChannel channel);
+ }
+
+ private static class OpenChannelListener implements IChannel.IChannelListener {
+
+ private final Collection errors;
+ private final IChannel channel;
+ private final DoneOpenChannel done;
+
+ OpenChannelListener(Collection errors, IChannel channel, DoneOpenChannel done) {
+ this.errors = errors;
+ this.channel = channel;
+ this.done = done;
+ channel.addChannelListener(this);
+ }
+
+ public void onChannelOpened() {
+ channel.removeChannelListener(this);
+ done.doneOpenChannel(channel);
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable e) {
+ errors.add(e);
+ channel.removeChannelListener(this);
+ done.doneOpenChannel(null);
+ }
+ }
+
+ private void openChannel(String path, final Collection errors, final DoneOpenChannel done) {
+ assert Protocol.isDispatchThread();
+ try {
+ int i = path.lastIndexOf('/');
+ if (i < 0) {
+ IPeer peer = Protocol.getLocator().getPeers().get(path);
+ if (peer == null) {
+ errors.add(new Exception("Peer not found: " + path));
+ done.doneOpenChannel(null);
+ return;
+ }
+ new OpenChannelListener(errors, peer.openChannel(), done);
+ }
+ else {
+ final String id = path.substring(i + 1);
+ openChannel(path.substring(0, i), errors, new DoneOpenChannel() {
+ public void doneOpenChannel(IChannel channel) {
+ if (errors.size() > 0) {
+ if (channel != null) channel.close();
+ done.doneOpenChannel(null);
+ }
+ else {
+ channel.redirect(id);
+ new OpenChannelListener(errors, channel, done);
+ }
+ }
+ });
+ }
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.doneOpenChannel(null);
+ }
+ }
+
+ private void runDiagnostics(TreeItem item, boolean loop) {
+ final Shell shell = new Shell(getShell(), SWT.TITLE | SWT.PRIMARY_MODAL);
+ GridLayout layout = new GridLayout();
+ layout.verticalSpacing = 0;
+ layout.numColumns = 2;
+ shell.setLayout(layout);
+ shell.setText("Running Diagnostics...");
+ CLabel label = new CLabel(shell, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ label.setText("Running Diagnostics...");
+ final TCFSelfTest[] test = new TCFSelfTest[1];
+ Button button_cancel = new Button(shell, SWT.PUSH);
+ button_cancel.setText("&Cancel");
+ button_cancel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ button_cancel.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (test[0] != null) test[0].cancel();
+ }
+ });
+ }
+ });
+ createVerticalSpacer(shell, 0);
+ ProgressBar bar = new ProgressBar(shell, SWT.HORIZONTAL);
+ bar.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1));
+ shell.setDefaultButton(button_cancel);
+ shell.pack();
+ shell.setSize(483, shell.getSize().y);
+ Rectangle rc0 = getShell().getBounds();
+ Rectangle rc1 = shell.getBounds();
+ shell.setLocation(rc0.x + (rc0.width - rc1.width) / 2, rc0.y + (rc0.height - rc1.height) / 2);
+ shell.setVisible(true);
+ runDiagnostics(item, loop, test, shell, label, bar);
+ }
+
+ private void runDiagnostics(final TreeItem item, final boolean loop, final TCFSelfTest[] test,
+ final Shell shell, final CLabel label, final ProgressBar bar) {
+ final TCFSelfTest.TestListener done = new TCFSelfTest.TestListener() {
+ private String last_text = "";
+ private int last_count = 0;
+ private int last_total = 0;
+ public void progress(final String label_text, final int count_done, final int count_total) {
+ if ((label_text == null || last_text.equals(label_text)) &&
+ last_total == count_total &&
+ (count_done - last_count) / (float)count_total < 0.02f) return;
+ if (label_text != null) last_text = label_text;
+ last_total = count_total;
+ last_count = count_done;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ label.setText(last_text);
+ bar.setMinimum(0);
+ bar.setMaximum(last_total);
+ bar.setSelection(last_count);
+ }
+ });
+ }
+ public void done(final Collection errors) {
+ final boolean b = test[0] == null ? false : test[0].isCanceled();
+ test[0] = null;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (errors.size() > 0) {
+ shell.dispose();
+ new TestErrorsDialog(getControl().getShell(),
+ getImage("icons/tcf.gif"), errors).open();
+ }
+ else if (loop && !b) {
+ runDiagnostics(item, true, test, shell, label, bar);
+ }
+ else {
+ shell.dispose();
+ }
+ }
+ });
+ }
+ };
+ findPeer(item, new DoneFindPeer() {
+ public void doneFindPeer(Collection errors, IPeer peer) {
+ if (errors.size() > 0) {
+ done.done(errors);
+ }
+ else {
+ try {
+ test[0] = new TCFSelfTest(peer, done);
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.done(errors);
+ }
+ }
+ }
+ });
+ }
+
+ private void fillItem(TreeItem item, PeerInfo info) {
+ String text[] = new String[5];
+ text[0] = info.attrs.get(IPeer.ATTR_NAME);
+ text[1] = info.attrs.get(IPeer.ATTR_OS_NAME);
+ text[2] = info.attrs.get(IPeer.ATTR_TRANSPORT_NAME);
+ text[3] = info.attrs.get(IPeer.ATTR_IP_HOST);
+ text[4] = info.attrs.get(IPeer.ATTR_IP_PORT);
+ item.setText(text);
+ item.setImage(getImage(getImageName(info)));
+ if (info.children == null) loadPeerInfo(info);
+ item.setItemCount(info.children.length);
+ }
+
+ private String getPath(PeerInfo info) {
+ String id = info.attrs.get(IPeer.ATTR_ID);
+ if (info.parent == null) return id;
+ return getPath(info.parent) + "/" + id;
+ }
+
+ private Image getImage(String name) {
+ if (name == null) return null;
+ if (display == null) return null;
+ Image image = image_cache.get(name);
+ if (image == null) {
+ URL url = FileLocator.find(TCFUI.getDefault().getBundle(), new Path(name), null);
+ ImageDescriptor descriptor = null;
+ if (url == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ else {
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image = descriptor.createImage(display);
+ image_cache.put(name, image);
+ }
+ return image;
+ }
+
+ private String getImageName(PeerInfo info) {
+ return "icons/tcf.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java
new file mode 100644
index 000000000..84208836d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java
@@ -0,0 +1,1207 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.launch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+import com.windriver.tcf.api.services.IDiagnostics;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.ILineNumbers;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRegisters;
+import com.windriver.tcf.api.services.IRunControl;
+import com.windriver.tcf.api.services.IDiagnostics.ISymbol;
+import com.windriver.tcf.api.services.IFileSystem.DirEntry;
+import com.windriver.tcf.api.services.IFileSystem.FileAttrs;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+import com.windriver.tcf.api.services.ILineNumbers.CodeArea;
+import com.windriver.tcf.api.services.IMemory.MemoryContext;
+import com.windriver.tcf.api.services.IMemory.MemoryError;
+import com.windriver.tcf.api.services.IRegisters.RegistersContext;
+import com.windriver.tcf.api.services.IRunControl.RunControlContext;
+import com.windriver.tcf.api.util.TCFFileInputStream;
+import com.windriver.tcf.api.util.TCFFileOutputStream;
+
+class TCFSelfTest {
+
+ private final static int NUM_CHANNELS = 4;
+
+ private final TestListener listener;
+ private final IChannel[] channels;
+ private final LinkedList pending_tests = new LinkedList();
+ private final Map active_tests = new HashMap();
+ private final Collection errors = new ArrayList();
+
+ private int count_total;
+ private int count_done;
+ private boolean canceled;
+ private boolean memory_lock;
+
+ public interface TestListener {
+ public void progress(String label, int done, int total);
+ public void done(Collection errors);
+ }
+
+ @SuppressWarnings("serial")
+ private static class CancelException extends Exception {
+ CancelException() {
+ super("Canceled");
+ }
+ }
+
+ private interface Test {
+ }
+
+ TCFSelfTest(IPeer peer, TestListener listener) throws IOException {
+ this.listener = listener;
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (IChannel channel : channels) new TestEcho(channel);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ int i = 0;
+ for (IChannel channel : channels) new TestRCBP1(channel, i++);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (IChannel channel : channels) new TestFileSystem(channel);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (int i = 0; i < channels.length; i++) {
+ switch (i % 3) {
+ case 0: new TestEcho(channels[i]); break;
+ case 1: new TestRCBP1(channels[i], i); break;
+ case 2: new TestFileSystem(channels[i]); break;
+ }
+ }
+ }
+ });
+ count_total = NUM_CHANNELS * pending_tests.size() * 2;
+ channels = new IChannel[NUM_CHANNELS];
+ listener.progress("Openning communication channels...", count_done, count_total);
+ for (int i = 0; i < channels.length; i++) {
+ final IChannel channel = channels[i] = peer.openChannel();
+ channel.addChannelListener(new IChannel.IChannelListener() {
+
+ public void onChannelOpened() {
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] == null) return;
+ if (channels[i].getState() != IChannel.STATE_OPEN) return;
+ }
+ runNextTest();
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable error) {
+ channel.removeChannelListener(this);
+ if (error == null && (!active_tests.isEmpty() || !pending_tests.isEmpty())) {
+ error = new IOException("Remote peer closed connection before all tests finished");
+ }
+ int cnt = 0;
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] == channel) {
+ channels[i] = null;
+ if (error != null && !(error instanceof CancelException)) errors.add(error);
+ for (Iterator n = active_tests.keySet().iterator(); n.hasNext();) {
+ if (active_tests.get(n.next()) == channel) n.remove();
+ }
+ }
+ else if (channels[i] != null) {
+ cnt++;
+ }
+ }
+ if (cnt == 0) {
+ TCFSelfTest.this.listener.done(errors);
+ }
+ else if (active_tests.isEmpty()) {
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] != null && channels[i].getState() != IChannel.STATE_CLOSED) {
+ if (errors.isEmpty()) channels[i].close();
+ else channels[i].terminate(new CancelException());
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ void cancel() {
+ if (canceled) return;
+ for (final Test t : active_tests.keySet()) {
+ if (t instanceof TestRCBP1) {
+ ((TestRCBP1)t).cancel(new Runnable() {
+ public void run() {
+ assert active_tests.get(t) == null;
+ cancel();
+ }
+ });
+ return;
+ }
+ }
+ canceled = true;
+ for (IChannel c : channels) {
+ if (c != null && c.getState() != IChannel.STATE_CLOSED) {
+ c.terminate(new CancelException());
+ }
+ }
+ }
+
+ boolean isCanceled() {
+ return canceled;
+ }
+
+ private class TestEcho implements Test, IDiagnostics.DoneEcho {
+
+ private final IDiagnostics diag;
+ private final LinkedList msgs = new LinkedList();
+ private int count = 0;
+
+ TestEcho(IChannel channel) {
+ diag = channel.getRemoteService(IDiagnostics.class);
+ listener.progress("Running Echo Test...", ++count_done, count_total);
+ active_tests.put(this, channel);
+ if (diag == null) {
+ done(this);
+ }
+ else {
+ for (int i = 0; i < 32; i++) sendMessage();
+ }
+ }
+
+ private void sendMessage() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(Integer.toHexString(count));
+ for (int i = 0; i < 64; i++) {
+ buf.append('-');
+ buf.append((char)(0x400 * i + count));
+ }
+ String s = buf.toString();
+ msgs.add(s);
+ diag.echo(s, this);
+ count++;
+ }
+
+ public void doneEcho(IToken token, Throwable error, String b) {
+ String s = msgs.removeFirst();
+ if (active_tests.get(this) == null) return;
+ if (error != null) {
+ errors.add(error);
+ done(this);
+ }
+ else if (!s.equals(b)) {
+ errors.add(new Exception("Echo test failed: " + s + " != " + b));
+ done(this);
+ }
+ else if (count < 0x400) {
+ sendMessage();
+ }
+ else if (msgs.isEmpty()){
+ done(this);
+ }
+ }
+ }
+
+ private class TestRCBP1 implements Test,
+ IDiagnostics.DoneGetTestList, IDiagnostics.DoneRunTest,
+ IRunControl.DoneGetContext, IRunControl.DoneGetChildren,
+ IRunControl.DoneGetState, IRunControl.RunControlListener,
+ IDiagnostics.DoneGetSymbol {
+
+ private final int channel_id;
+ private final IDiagnostics diag;
+ private final IMemory mm;
+ private final IRunControl rc;
+ private final IRegisters rg;
+ private final IBreakpoints bp;
+ private final ILineNumbers ln;
+ private final Map threads = new HashMap();
+ private final Map suspended = new HashMap();
+ private final Map suspended_prev = new HashMap();
+ private final Set running = new HashSet();
+ private final Map get_state_cmds = new HashMap();
+ private final Map> regs =
+ new HashMap>();
+
+ private String context_id; // Test process context ID
+ private IRunControl.RunControlContext context;
+ private String main_thread_id;
+ private Runnable pending_cancel;
+ private ISymbol func0;
+ private ISymbol func1;
+ private ISymbol func2;
+ private ISymbol array;
+ private int bp_cnt = 0;
+
+ private class SuspendedContext {
+ final String id;
+ final String pc;
+ final String reason;
+ final Map params;
+ boolean resumed;
+
+ SuspendedContext(String id, String pc, String reason, Map params) {
+ this.id = id;
+ this.pc = pc;
+ this.reason = reason;
+ this.params = params;
+ }
+ }
+
+ TestRCBP1(IChannel channel, int channel_id) {
+ this.channel_id = channel_id;
+ diag = channel.getRemoteService(IDiagnostics.class);
+ mm = channel.getRemoteService(IMemory.class);
+ rc = channel.getRemoteService(IRunControl.class);
+ rg = channel.getRemoteService(IRegisters.class);
+ bp = channel.getRemoteService(IBreakpoints.class);
+ ln = channel.getRemoteService(ILineNumbers.class);
+ active_tests.put(this, channel);
+ listener.progress("Running Run Control Test...", ++count_done, count_total);
+ if (diag == null || rc == null) {
+ done(this);
+ }
+ else if (bp == null) {
+ exit(new Exception("Remote Breakpoints service not found"));
+ }
+ else {
+ diag.getTestList(this);
+ }
+ }
+
+ public void doneGetTestList(IToken token, Throwable error, String[] list) {
+ assert active_tests.get(this) != null;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ for (int i = 0; i < list.length; i++) {
+ if (list[i].equals("RCBP1")) {
+ diag.runTest("RCBP1", this);
+ return;
+ }
+ }
+ }
+ exit(null);
+ }
+
+ public void doneRunTest(IToken token, Throwable error, String context_id) {
+ assert active_tests.get(this) != null;
+ assert this.context_id == null;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ this.context_id = context_id;
+ if (pending_cancel != null) {
+ Protocol.invokeLater(pending_cancel);
+ pending_cancel = null;
+ }
+ else {
+ diag.getSymbol(context_id, "tcf_test_func0", this);
+ diag.getSymbol(context_id, "tcf_test_func1", this);
+ diag.getSymbol(context_id, "tcf_test_func2", this);
+ diag.getSymbol(context_id, "tcf_test_array", this);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void doneGetSymbol(IToken token, Throwable error, ISymbol symbol) {
+ assert active_tests.get(this) != null;
+ assert this.context_id != null;
+ if (error != null) {
+ exit(error);
+ }
+ else if (!symbol.isGlobal()) {
+ exit(new Exception("Symbols 'tcf_test_*' must be global"));
+ }
+ else if (!symbol.isAbs()) {
+ exit(new Exception("Symbols 'tcf_test_*' must be absolute"));
+ }
+ else if (func0 == null) {
+ func0 = symbol;
+ }
+ else if (func1 == null) {
+ func1 = symbol;
+ }
+ else if (func2 == null) {
+ func2 = symbol;
+ }
+ else {
+ array = symbol;
+ Map m[] = new Map[4];
+ for (int i = 0; i < m.length; i++) {
+ m[i] = new HashMap();
+ m[i].put(IBreakpoints.PROP_ID, "TcfTestBP" + i);
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ switch (i) {
+ case 0:
+ m[i].put(IBreakpoints.PROP_ADDRESS, func0.getValue().toString());
+ m[i].put(IBreakpoints.PROP_CONDITION, "$thread!=\"\"");
+ break;
+ case 1:
+ m[i].put(IBreakpoints.PROP_ADDRESS, "(31+1)/16+tcf_test_func1-2");
+ m[i].put(IBreakpoints.PROP_CONDITION, "tcf_test_func0!=tcf_test_func1");
+ break;
+ case 2:
+ m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ break;
+ case 3:
+ m[i].put(IBreakpoints.PROP_ID, "TcfTestBP3" + channel_id);
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ break;
+ }
+ }
+ bp.set(m, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ rc.getContext(context_id, TestRCBP1.this);
+ }
+ }
+ });
+ }
+ }
+
+ public void doneGetContext(IToken token, Exception error, RunControlContext context) {
+ if (canceled) return;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ if (this.context == null) {
+ this.context = context;
+ assert context_id.equals(context.getID());
+ assert threads.isEmpty();
+ assert running.isEmpty();
+ assert suspended.isEmpty();
+ rc.addListener(this);
+ }
+ rc.getChildren(context.getID(), this);
+ if (context.hasState()) {
+ threads.put(context.getID(), context);
+ get_state_cmds.put(context.getState(this), context.getID());
+ }
+ }
+ }
+
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (canceled) return;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ for (String id : contexts) rc.getContext(id, this);
+ }
+ }
+
+ public void doneGetState(IToken token, Exception error,
+ boolean suspended, String pc, String reason,
+ Map params) {
+ final String id = get_state_cmds.remove(token);
+ if (canceled) return;
+ if (id == null) {
+ exit(new Exception("Invalid getState responce"));
+ }
+ else if (!suspended) {
+ if (this.suspended.get(id) != null) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ running.add(id);
+ }
+ }
+ else {
+ assert threads.get(id) != null;
+ if (running.contains(id)) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ SuspendedContext sc = this.suspended.get(id);
+ if (sc != null) {
+ if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ resume(sc);
+ }
+ }
+ else {
+ if (main_thread_id != null) {
+ exit(new Exception("Missing contextSuspended event for " + id));
+ }
+ else if ("Breakpoint".equals(reason)) {
+ exit(new Exception("Invalid suspend reason of main thread after test start: " + reason + " " + pc));
+ }
+ else {
+ main_thread_id = id;
+ final SuspendedContext sx = new SuspendedContext(id, pc, reason, params);
+ this.suspended.put(id, sx);
+ final String bp_id = "TcfTestBP3" + channel_id;
+ Map m = new HashMap();
+ m.put(IBreakpoints.PROP_ID, bp_id);
+ m.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ m.put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ m.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + id + "\"");
+ bp.change(m, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ Protocol.sync(new Runnable() {
+ public void run() {
+ bp.enable(new String[]{ bp_id }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ resume(sx);
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ public void containerResumed(String[] context_ids) {
+ for (String id : context_ids) contextResumed(id);
+ }
+
+ public void containerSuspended(String context, String pc,
+ String reason, Map params,
+ String[] suspended_ids) {
+ for (String id : suspended_ids) {
+ if (id.equals(context)) continue;
+ contextSuspended(id, null, null, null);
+ }
+ contextSuspended(context, pc, reason, params);
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ if (threads.get(contexts[i].getID()) != null) {
+ exit(new Exception("Invalid contextAdded event"));
+ return;
+ }
+ if (context.getID().equals(contexts[i].getProperties().get("ParentID"))) {
+ threads.put(contexts[i].getID(), contexts[i]);
+ running.add(contexts[i].getID());
+ }
+ }
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ if (contexts[i].getID().equals(context.getID())) {
+ context = contexts[i];
+ }
+ if (context.getID().equals(contexts[i].getProperties().get("ProcessID"))) {
+ threads.put(contexts[i].getID(), contexts[i]);
+ }
+ }
+ }
+
+ public void contextException(String context, String msg) {
+ if (context.equals(this.context.getID()) || threads.get(context) != null) {
+ exit(new Exception(msg));
+ }
+ }
+
+ public void contextRemoved(String[] contexts) {
+ for (String id : contexts) {
+ if (suspended.get(id) != null) {
+ exit(new Exception("Invalid contextRemoved event"));
+ return;
+ }
+ threads.remove(id);
+ running.remove(id);
+ if (threads.isEmpty()) {
+ if (bp_cnt != 30) {
+ exit(new Exception("Test main thread breakpoint count = " + bp_cnt + ", expected 30"));
+ }
+ rc.removeListener(this);
+ // Flush communication channel of pending commands
+ Protocol.sync(new Runnable() {
+ public void run() {
+ exit(null);
+ }
+ });
+ }
+ }
+ }
+
+ public void contextResumed(String id) {
+ if (threads.get(id) == null) return;
+ SuspendedContext sc = suspended.remove(id);
+ if (!isAlienBreakpoint(sc)) suspended_prev.put(id, sc);
+ running.add(id);
+ }
+
+ private String toSymName(long addr) {
+ if (func0.getValue().longValue() == addr) return "tcf_test_func0";
+ if (func1.getValue().longValue() == addr) return "tcf_test_func1";
+ if (func2.getValue().longValue() == addr) return "tcf_test_func2";
+ return "*no name*";
+ }
+
+ private void checkSuspendedContext(SuspendedContext sp, ISymbol sym) {
+ long pc = Long.parseLong(sp.pc);
+ if (pc != sym.getValue().longValue() || !"Breakpoint".equals(sp.reason)) {
+ exit(new Exception("Invalid contextSuspended event: " + sp.id + " '" + toSymName(pc) + "' " + sp.pc + " " + sp.reason +
+ ", expected breakpoint at '" + toSymName(sym.getValue().longValue()) + "' " + sym.getValue()));
+ }
+ }
+
+ private boolean isAlienBreakpoint(SuspendedContext sc) {
+ // Check if context suspended by a breakpoint from another debug session
+ // Test should ignore such breakpoints.
+ if (!"Breakpoint".equals(sc.reason)) return false;
+ long pc = Long.parseLong(sc.pc);
+ if (pc == func0.getValue().longValue()) return false;
+ if (pc == func1.getValue().longValue()) return false;
+ if (pc == func2.getValue().longValue()) return false;
+ return true;
+ }
+
+ public void contextSuspended(String id, String pc, String reason, Map params) {
+ if (threads.get(id) == null) return;
+ assert main_thread_id != null;
+ running.remove(id);
+ SuspendedContext sc = suspended.get(id);
+ if (sc != null) {
+ if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) {
+ exit(new Exception("Invalid contextSuspended event"));
+ }
+ }
+ else {
+ sc = new SuspendedContext(id, pc, reason, params);
+ suspended.put(id, sc);
+ if (!isAlienBreakpoint(sc)) {
+ if ("Breakpoint".equals(reason) && id.equals(main_thread_id)) bp_cnt++;
+ SuspendedContext sp = suspended_prev.get(id);
+ if (sp != null) {
+ if (Long.parseLong(sc.pc) == func2.getValue().longValue()) {
+ checkSuspendedContext(sp, func1);
+ }
+ else if (Long.parseLong(sc.pc) == func1.getValue().longValue()) {
+ checkSuspendedContext(sp, func0);
+ }
+ else if (Long.parseLong(sc.pc) == func0.getValue().longValue()) {
+ if (id.equals(main_thread_id)) {
+ if ("Breakpoint".equals(sp.reason)) {
+ checkSuspendedContext(sp, func2);
+ }
+ }
+ else {
+ checkSuspendedContext(sp, func1);
+ }
+ }
+ }
+ }
+ }
+ final SuspendedContext sc0 = sc;
+ ILineNumbers.DoneMapToSource ln_done = new ILineNumbers.DoneMapToSource() {
+ public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ if (error != null) exit(error);
+ if (mm != null) runMemoryTest(sc0);
+ else if (rg != null) runRegistersTest(sc0);
+ else resume(sc0);
+ }
+ };
+ if (ln != null) {
+ BigInteger x = new BigInteger(pc);
+ BigInteger y = x.add(BigInteger.valueOf(1));
+ ln.mapToSource(id, x, y, ln_done);
+ }
+ else {
+ ln_done.doneMapToSource(null, null, null);
+ }
+ }
+
+ private void resume(final SuspendedContext sc) {
+ IRunControl.RunControlContext ctx = threads.get(sc.id);
+ if (ctx != null && !sc.resumed) {
+ sc.resumed = true;
+ ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (canceled) return;
+ if (active_tests.get(this) == null) return;
+ if (threads.get(sc.id) == null) return;
+ if (error != null) exit(error);
+ }
+ });
+ }
+ }
+
+ private void runMemoryTest(final SuspendedContext sc) {
+ if (memory_lock) {
+ resume(sc);
+ return;
+ }
+ memory_lock = true;
+ mm.getContext(context_id, new IMemory.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, final MemoryContext mem_ctx) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ if (!context_id.equals(mem_ctx.getID())) {
+ exit(new Exception("Bad memory context data: invalid ID"));
+ }
+ Object pid = context.getProperties().get("ProcessID");
+ if (pid != null && !pid.equals(mem_ctx.getProperties().get("ProcessID"))) {
+ exit(new Exception("Bad memory context data: invalid ProcessID"));
+ }
+ final boolean big_endian = mem_ctx.isBigEndian();
+ final int addr_size = mem_ctx.getAddressSize();
+ final byte[] buf = new byte[0x1000];
+ mem_ctx.get(array.getValue(), 1, buf, 0, addr_size, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ byte[] tmp = new byte[addr_size + 1];
+ tmp[0] = 0; // Extra byte to avoid sign extension by BigInteger
+ if (big_endian) {
+ System.arraycopy(buf, 0, tmp, 1, addr_size);
+ }
+ else {
+ for (int i = 0; i < addr_size; i++) {
+ tmp[i + 1] = buf[addr_size - i - 1];
+ }
+ }
+ Number mem_address = new BigInteger(tmp);
+ testSetMemoryCommand(sc, mem_ctx, mem_address, buf);
+ }
+ });
+ }
+ });
+ }
+
+ private void testSetMemoryCommand(final SuspendedContext sc,
+ final IMemory.MemoryContext mem_ctx,
+ final Number addr, final byte[] buf) {
+ final byte[] data = new byte[buf.length];
+ new Random().nextBytes(data);
+ mem_ctx.set(addr, 1, data, 0, data.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != buf[i]) {
+ exit(new Exception(
+ "Invalid Memory.get responce: wrong data at offset " + i +
+ ", expected " + data[i] + ", actual " + buf[i]));
+ return;
+ }
+ }
+ testFillMemoryCommand(sc, mem_ctx, addr, buf);
+ }
+ });
+ }
+ });
+ }
+
+ private void testFillMemoryCommand(final SuspendedContext sc,
+ final IMemory.MemoryContext mem_ctx,
+ final Number addr, final byte[] buf) {
+ final byte[] data = new byte[buf.length / 7];
+ new Random().nextBytes(data);
+ mem_ctx.fill(addr, 1, data, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (data[i % data.length] != buf[i]) {
+ exit(new Exception(
+ "Invalid Memory.get responce: wrong data at offset " + i +
+ ", expected " + data[i % data.length] + ", actual " + buf[i]));
+ return;
+ }
+ }
+ memory_lock = false;
+ if (rg != null) runRegistersTest(sc);
+ else resume(sc);
+ }
+ });
+ }
+ });
+ }
+
+ private void runRegistersTest(final SuspendedContext sc) {
+ if (regs.get(sc.id) == null) {
+ final Map reg_map =
+ new HashMap();
+ final Set cmds = new HashSet();
+ regs.put(sc.id, reg_map);
+ cmds.add(rg.getChildren(sc.id, new IRegisters.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ for (final String id : context_ids) {
+ cmds.add(rg.getChildren(id, this));
+ cmds.add(rg.getContext(id, new IRegisters.DoneGetContext() {
+ public void doneGetContext(IToken token,
+ Exception error,
+ RegistersContext context) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ reg_map.put(id, context);
+ if (cmds.isEmpty()) {
+ testGetSetRegisterCommands(sc);
+ }
+ }
+ }));
+ }
+ }
+ }));
+ }
+ else {
+ testGetSetRegisterCommands(sc);
+ }
+ }
+
+ private void testGetSetRegisterCommands(final SuspendedContext sc) {
+ final Set cmds = new HashSet();
+ Map reg_map = regs.get(sc.id);
+ for (final IRegisters.RegistersContext ctx : reg_map.values()) {
+ if (!ctx.isReadable()) continue;
+ if (ctx.isReadOnce()) continue;
+ String[] fmts = ctx.getAvailableFormats();
+ for (final String fmt : fmts) {
+ cmds.add(ctx.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ cmds.add(ctx.set(fmt, value, new IRegisters.DoneSet() {
+ public void doneSet(IToken token, Exception error) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ if (cmds.isEmpty()) {
+ resume(sc);
+ }
+ }
+ }));
+ }
+ }));
+ }
+ }
+ if (cmds.isEmpty()) {
+ resume(sc);
+ }
+ }
+
+ void cancel(final Runnable done) {
+ if (rc != null) rc.removeListener(this);
+ if (context_id == null) {
+ if (pending_cancel != null) {
+ exit(null);
+ }
+ else {
+ pending_cancel = done;
+ }
+ }
+ else {
+ diag.cancelTest(context_id, new IDiagnostics.DoneCancelTest() {
+ public void doneCancelTest(IToken token, Throwable error) {
+ exit(error);
+ done.run();
+ }
+ });
+ }
+ }
+
+ private void exit(Throwable x) {
+ if (active_tests.get(this) == null) return;
+ if (pending_cancel != null) {
+ pending_cancel.run();
+ pending_cancel = null;
+ }
+ else {
+ if (x != null) errors.add(x);
+ if (rc != null) rc.removeListener(this);
+ }
+ done(this);
+ }
+ }
+
+ private int file_count = 0;
+
+ private class TestFileSystem implements Test, IFileSystem.DoneStat,
+ IFileSystem.DoneOpen, IFileSystem.DoneClose,
+ IFileSystem.DoneWrite, IFileSystem.DoneRead,
+ IFileSystem.DoneRename, IFileSystem.DoneRealPath,
+ IFileSystem.DoneRemove, IFileSystem.DoneRoots,
+ IFileSystem.DoneReadDir {
+
+ private static final int
+ STATE_PRE = 0,
+ STATE_WRITE = 1,
+ STATE_READ = 2,
+ STATE_OUT = 3,
+ STATE_INP = 4,
+ STATE_EXIT = 5;
+
+ private final IFileSystem files;
+ private final byte[] data = new byte[0x1000];
+ private String root;
+ private String tmp_path;
+ private String file_name;
+ private IFileHandle handle;
+ private int state = STATE_PRE;
+
+ TestFileSystem(IChannel channel) {
+ files = channel.getRemoteService(IFileSystem.class);
+ active_tests.put(this, channel);
+ listener.progress("Running File System Test...", ++count_done, count_total);
+ if (files == null) {
+ done(this);
+ }
+ else {
+ files.roots(this);
+ }
+ }
+
+ public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) {
+ assert state == STATE_PRE;
+ if (error != null) {
+ error(error);
+ }
+ else if (entries == null || entries.length == 0) {
+ error(new Exception("Invalid FileSysrem.roots responce: empty roots array"));
+ }
+ else {
+ root = entries[0].filename;
+ files.opendir(root, this);
+ }
+ }
+
+ public void doneReadDir(IToken token, FileSystemException error,
+ DirEntry[] entries, boolean eof) {
+ assert state == STATE_PRE;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ if (entries != null && tmp_path == null) {
+ for (DirEntry e : entries) {
+ if (e.filename.equals("tmp") || e.filename.equalsIgnoreCase("temp")) {
+ tmp_path = root + "/" + e.filename;
+ break;
+ }
+ }
+ }
+ if (eof) {
+ if (tmp_path == null) {
+ error(new Exception("File system test filed: cannot find temporary directory"));
+ return;
+ }
+ files.close(handle, this);
+ }
+ else {
+ files.readdir(handle, this);
+ }
+ }
+ }
+
+ public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ error(error);
+ }
+ else if (state == STATE_READ) {
+ if (attrs.size != data.length) {
+ error(new Exception("Invalid FileSysrem.fstat responce: wrong file size"));
+ }
+ else {
+ files.close(handle, this);
+ }
+ }
+ else {
+ file_name = tmp_path + "/tcf-test-" + (file_count++) + ".tmp";
+ files.open(file_name, IFileSystem.O_CREAT | IFileSystem.O_TRUNC | IFileSystem.O_WRITE, null, this);
+ }
+ }
+
+ public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ this.handle = handle;
+ if (state == STATE_READ) {
+ files.read(handle, 0, data.length + 1, this);
+ }
+ else if (state == STATE_WRITE) {
+ new Random().nextBytes(data);
+ files.write(handle, 0, data, 0, data.length, this);
+ }
+ else if (state == STATE_INP) {
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ InputStream inp = new TCFFileInputStream(handle);
+ int i = 0;
+ for (;;) {
+ int ch = inp.read();
+ if (ch < 0) break;
+ int dt = data[i % data.length] & 0xff;
+ if (ch != dt) {
+ error(new Exception("Invalid TCFFileInputStream.read responce: wrong data at offset " + i +
+ ", expected " + dt + ", actual " + ch));
+ }
+ i++;
+ }
+ if (i != data.length * 16) {
+ error(new Exception("Invalid TCFFileInputStream.read responce: wrong file length: " +
+ "expected " + data.length + ", actual " + i));
+ }
+ inp.close();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ state = STATE_EXIT;
+ files.rename(file_name, file_name + ".rnm", TestFileSystem.this);
+ }
+ });
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ private void error(final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TestFileSystem.this.error(x);
+ }
+ });
+ }
+ };
+ thread.setName("TCF FileSystem Test");
+ thread.start();
+ }
+ else if (state == STATE_OUT) {
+ new Random().nextBytes(data);
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ OutputStream out = new TCFFileOutputStream(handle);
+ for (int i = 0; i < data.length * 16; i++) {
+ out.write(data[i % data.length] & 0xff);
+ }
+ out.close();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ state = STATE_INP;
+ files.open(file_name, IFileSystem.O_READ, null, TestFileSystem.this);
+ }
+ });
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ private void error(final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TestFileSystem.this.error(x);
+ }
+ });
+ }
+ };
+ thread.setName("TCF FileSystem Test");
+ thread.start();
+ }
+ else {
+ assert state == STATE_PRE;
+ files.readdir(handle, this);
+ }
+ }
+ }
+
+ public void doneWrite(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ files.close(handle, this);
+ }
+ }
+
+ public void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof) {
+ if (error != null) {
+ error(error);
+ }
+ else if (!eof) {
+ error(new Exception("Invalid FileSysrem.read responce: EOF expected"));
+ }
+ else if (data.length != this.data.length) {
+ error(new Exception("Invalid FileSysrem.read responce: wrong data array size"));
+ }
+ else {
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != this.data[i]) {
+ error(new Exception("Invalid FileSysrem.read responce: wrong data at offset " + i +
+ ", expected " + this.data[i] + ", actual " + data[i]));
+ return;
+ }
+ }
+ files.fstat(handle, this);
+ }
+ }
+
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ handle = null;
+ if (state == STATE_PRE) {
+ files.realpath(tmp_path, this);
+ }
+ else if (state == STATE_WRITE) {
+ state = STATE_READ;
+ files.open(file_name, IFileSystem.O_READ, null, this);
+ }
+ else if (state == STATE_READ) {
+ state = STATE_OUT;
+ files.open(file_name, IFileSystem.O_WRITE, null, this);
+ }
+ else {
+ assert false;
+ }
+ }
+ }
+
+ public void doneRename(IToken token, FileSystemException error) {
+ assert state == STATE_EXIT;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ files.realpath(file_name + ".rnm", this);
+ }
+ }
+
+ public void doneRealPath(IToken token, FileSystemException error, String path) {
+ if (error != null) {
+ error(error);
+ }
+ else if (state == STATE_PRE) {
+ state = STATE_WRITE;
+ tmp_path = path;
+ files.stat(tmp_path, this);
+ }
+ else if (!path.equals(file_name + ".rnm")) {
+ error(new Exception("Invalid FileSysrem.realpath responce: " + path));
+ }
+ else {
+ files.remove(file_name + ".rnm", this);
+ }
+ }
+
+ public void doneRemove(IToken token, FileSystemException error) {
+ assert state == STATE_EXIT;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ done(this);
+ }
+ }
+
+ private void error(Throwable x) {
+ if (active_tests.get(this) == null) return;
+ errors.add(x);
+ done(this);
+ }
+ }
+
+ private void done(Test test) {
+ assert active_tests.get(test) != null;
+ active_tests.remove(test);
+ listener.progress(null, ++count_done, count_total);
+ if (active_tests.isEmpty()) runNextTest();
+ }
+
+ private void runNextTest() {
+ while (active_tests.isEmpty()) {
+ if (canceled || errors.size() > 0 || pending_tests.size() == 0) {
+ for (IChannel channel : channels) {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ if (errors.isEmpty()) channel.close();
+ else channel.terminate(new CancelException());
+ }
+ }
+ return;
+ }
+ pending_tests.removeFirst().run();
+ }
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java
new file mode 100644
index 000000000..8d06cafd5
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.launch;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
+
+/**
+ * Launch configuration dialog tab group for Target Communication Framework
+ */
+public class TCFTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+ setTabs(new ILaunchConfigurationTab[] {
+ new TCFMainTab(),
+ new TCFArgumentsTab(),
+ new EnvironmentTab(),
+ new SourceLookupTab(),
+ new CommonTab()
+ });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java
new file mode 100644
index 000000000..312e85c9a
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.launch;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+class TestErrorsDialog extends Dialog {
+
+ private final int SIZING_TEXT_WIDTH = 600;
+ private final int SIZING_TEXT_HEIGHT = 400;
+
+ private Collection errors;
+ private Image image;
+ private Text text;
+
+ TestErrorsDialog(Shell parent, Image image, Collection errors) {
+ super(parent);
+ this.image = image;
+ this.errors = errors;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText("Connection Diagnostic errors");
+ shell.setImage(image);
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ createButton(parent, IDialogConstants.OK_ID, "&OK", true);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite)super.createDialogArea(parent);
+ composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ Label label = new Label(composite, SWT.WRAP);
+ label.setFont(JFaceResources.getFontRegistry().get(JFaceResources.BANNER_FONT));
+ label.setText("Connection diagnostics ended with errors:");
+
+ text = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+ text.setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
+ text.setEditable(false);
+ text.setText(createText());
+ GridData data = new GridData(GridData.FILL_BOTH);
+ data.widthHint = SIZING_TEXT_WIDTH;
+ data.heightHint = SIZING_TEXT_HEIGHT;
+ text.setLayoutData(data);
+
+ return composite;
+ }
+
+ private String createText() {
+ StringWriter buf = new StringWriter();
+ PrintWriter pwr = new PrintWriter(buf);
+ for (Iterator i = errors.iterator(); i.hasNext();) {
+ i.next().printStackTrace(pwr);
+ pwr.println();
+ }
+ pwr.flush();
+ return buf.toString();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java
new file mode 100644
index 000000000..fafd5e541
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TCFChildren {
+
+ final TCFNode node;
+ final Map children = new HashMap();
+ final Map children_next = new HashMap();
+
+ protected boolean valid;
+
+ TCFChildren(TCFNode node) {
+ this.node = node;
+ }
+
+ void dispose() {
+ TCFNode arr[] = children.values().toArray(new TCFNode[children.size()]);
+ for (int i = 0; i < arr.length; i++) arr[i].dispose();
+ assert children.isEmpty();
+ }
+
+ void dispose(String id) {
+ children.remove(id);
+ }
+
+ void doneValidate() {
+ valid = true;
+ TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
+ for (TCFNode n : a) {
+ if (children_next.get(n.id) != n) n.dispose();
+ }
+ for (TCFNode n : children_next.values()) {
+ if (children.get(n.id) == null) {
+ children.put(n.id, n);
+ n.model.addNode(n.id, n);
+ }
+ assert children.get(n.id) == n;
+ }
+ assert children.size() == children_next.size();
+ }
+
+ boolean validate(TCFRunnable done) {
+ doneValidate();
+ return true;
+ }
+
+ void invalidate() {
+ children_next.clear();
+ TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
+ for (int i = 0; i < a.length; i++) a[i].invalidateNode(TCFNode.CF_ALL);
+ valid = false;
+ }
+
+ int size() {
+ return children.size();
+ }
+
+ TCFNode[] toArray() {
+ return children.values().toArray(new TCFNode[children.size()]);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java
new file mode 100644
index 000000000..95229f778
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFChildrenExecContext extends TCFChildren {
+
+ private boolean mem_valid;
+ private boolean run_valid;
+
+ TCFChildrenExecContext(TCFNode node) {
+ super(node);
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ if (!mem_valid && !validateMemoryChildren(done)) return false;
+ if (!run_valid && !validateRunControlChildren(done)) return false;
+ doneValidate();
+ return true;
+ }
+
+ @Override
+ void invalidate() {
+ mem_valid = false;
+ run_valid = false;
+ super.invalidate();
+ }
+
+ private boolean validateMemoryChildren(TCFRunnable done) {
+ assert node.data_command == null;
+ IMemory mem = node.model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ mem_valid = true;
+ return true;
+ }
+ if (done != null) node.wait_list.add(done);
+ node.data_command = mem.getChildren(node.id, new IMemory.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (int i = 0; i < contexts.length; i++) {
+ String id = contexts[i];
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ children_next.put(id, n);
+ }
+ }
+ mem_valid = true;
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlChildren(TCFRunnable done) {
+ assert node.data_command == null;
+ IRunControl run = node.model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ run_valid = true;
+ return true;
+ }
+ if (done != null) node.wait_list.add(done);
+ node.data_command = run.getChildren(node.id, new IRunControl.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ children_next.put(id, n);
+ }
+ }
+ run_valid = true;
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java
new file mode 100644
index 000000000..ec76afab7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRegisters;
+
+public class TCFChildrenRegisters extends TCFChildren {
+
+ TCFChildrenRegisters(TCFNode node) {
+ super(node);
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ children_next.clear();
+ String addr = node.getAddress();
+ if (addr == null) {
+ doneValidate();
+ return true;
+ }
+ IRegisters regs = node.model.getLaunch().getService(IRegisters.class);
+ if (regs == null) {
+ doneValidate();
+ return true;
+ }
+ assert node.data_command == null;
+ if (done != null) node.wait_list.add(done);
+ node.data_command = regs.getChildren(node.id, new IRegisters.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeRegister(node, id);
+ children_next.put(id, n);
+ }
+ }
+ doneValidate();
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java
new file mode 100644
index 000000000..8bcf2e757
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IStackTrace;
+
+public class TCFChildrenStackTrace extends TCFChildren {
+
+ private final TCFChildren children_regs;
+
+ TCFChildrenStackTrace(TCFNode node, TCFChildren children_regs) {
+ super(node);
+ this.children_regs = children_regs;
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ children_next.clear();
+ String addr = node.getAddress();
+ if (addr == null) {
+ doneValidate();
+ return true;
+ }
+ String nm = node.id + "-TF";
+ TCFNode n = children.get(nm);
+ if (n == null) n = new TCFNodeStackFrame(node, nm, children_regs);
+ children_next.put(n.id, n);
+ IStackTrace st = node.model.getLaunch().getService(IStackTrace.class);
+ if (st == null) {
+ doneValidate();
+ return true;
+ }
+ assert node.data_command == null;
+ if (done != null) node.wait_list.add(done);
+ node.data_command = st.getChildren(node.id, new IStackTrace.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ int cnt = contexts.length;
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null || ((TCFNodeStackFrame)n).getFrameNo() != cnt) {
+ n = new TCFNodeStackFrame(node, id, cnt);
+ }
+ assert ((TCFNodeStackFrame)n).getFrameNo() == cnt;
+ assert n.id.equals(id);
+ children_next.put(id, n);
+ cnt--;
+ }
+ }
+ doneValidate();
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java
new file mode 100644
index 000000000..8881fcb20
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java
@@ -0,0 +1,81 @@
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+public class TCFColumnPresentationRegister implements IColumnPresentation {
+
+ public static final String PRESENTATION_ID = "Registers";
+
+ private static String[] cols_all = {
+ TCFNodeRegister.COL_NAME,
+ TCFNodeRegister.COL_HEX_VALUE,
+ TCFNodeRegister.COL_DEC_VALUE,
+ TCFNodeRegister.COL_DESCRIPTION,
+ TCFNodeRegister.COL_READBLE,
+ TCFNodeRegister.COL_READ_ONCE,
+ TCFNodeRegister.COL_WRITEABLE,
+ TCFNodeRegister.COL_WRITE_ONCE,
+ TCFNodeRegister.COL_SIDE_EFFECTS,
+ TCFNodeRegister.COL_VOLATILE,
+ TCFNodeRegister.COL_FLOAT,
+ TCFNodeRegister.COL_MNEMONIC
+ };
+
+ private static String[] headers = {
+ "Name",
+ "Hex",
+ "Decimal",
+ "Description",
+ "Readable",
+ "Read Once",
+ "Writable",
+ "Write Once",
+ "Side Effects",
+ "Volatile",
+ "Float",
+ "Mnemonic"
+ };
+
+ private static String[] cols_ini = {
+ TCFNodeRegister.COL_NAME,
+ TCFNodeRegister.COL_HEX_VALUE,
+ TCFNodeRegister.COL_DEC_VALUE,
+ TCFNodeRegister.COL_DESCRIPTION,
+ TCFNodeRegister.COL_MNEMONIC
+ };
+
+ public void dispose() {
+ }
+
+ public String[] getAvailableColumns() {
+ return cols_all;
+ }
+
+ public String getHeader(String id) {
+ for (int i = 0; i < cols_all.length; i++) {
+ if (id.equals(cols_all[i])) return headers[i];
+ }
+ return null;
+ }
+
+ public String getId() {
+ return PRESENTATION_ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ public String[] getInitialColumns() {
+ return cols_ini;
+ }
+
+ public void init(IPresentationContext context) {
+ }
+
+ public boolean isOptional() {
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java
new file mode 100644
index 000000000..f4826d2c3
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.debug.core.commands.IDisconnectHandler;
+import org.eclipse.debug.core.commands.IResumeHandler;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.debug.tcf.ui.commands.DisconnectCommand;
+import com.windriver.debug.tcf.ui.commands.ResumeCommand;
+import com.windriver.debug.tcf.ui.commands.StepIntoCommand;
+import com.windriver.debug.tcf.ui.commands.StepOverCommand;
+import com.windriver.debug.tcf.ui.commands.StepReturnCommand;
+import com.windriver.debug.tcf.ui.commands.SuspendCommand;
+import com.windriver.debug.tcf.ui.commands.TerminateCommand;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFModel implements IElementContentProvider, IElementLabelProvider,
+ IModelProxyFactory, IColumnPresentationFactory {
+
+ private final Display display;
+ private final TCFLaunch launch;
+ private final TCFNode launch_node;
+ private final Map model_proxies =
+ new HashMap();
+ private final Map id2node = new HashMap();
+ private final Map deltas = new HashMap();
+ @SuppressWarnings("unchecked")
+ private final Map commands = new HashMap();
+
+ private final IMemory.MemoryListener mem_listener = new IMemory.MemoryListener() {
+
+ public void contextAdded(IMemory.MemoryContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getParentID());
+ if (node != null) node.onContextAdded(contexts[i]);
+ }
+ fireModelChanged();
+ }
+
+ public void contextChanged(IMemory.MemoryContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getID());
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextChanged(contexts[i]);
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextRemoved();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void memoryChanged(String context_id, Number[] addr, long[] size) {
+ TCFNode node = getNode(context_id);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onMemoryChanged(addr, size);
+ }
+ fireModelChanged();
+ }
+ };
+
+ private final IRunControl.RunControlListener run_listener = new IRunControl.RunControlListener() {
+
+ public void containerResumed(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContainerResumed();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void containerSuspended(String context, String pc, String reason,
+ Map params, String[] suspended_ids) {
+ for (int i = 0; i < suspended_ids.length; i++) {
+ TCFNode node = getNode(suspended_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContainerSuspended();
+ }
+ }
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params);
+ }
+ fireModelChanged();
+ }
+
+ public void contextAdded(IRunControl.RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getParentID());
+ if (node != null) node.onContextAdded(contexts[i]);
+ }
+ fireModelChanged();
+ }
+
+ public void contextChanged(IRunControl.RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getID());
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextChanged(contexts[i]);
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextException(String context, String msg) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextException(msg);
+ }
+ fireModelChanged();
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextRemoved();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextResumed(String context) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextResumed();
+ }
+ fireModelChanged();
+ }
+
+ public void contextSuspended(String context, String pc, String reason, Map params) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params);
+ }
+ fireModelChanged();
+ }
+ };
+
+ TCFModel(Display display, TCFLaunch launch) {
+ this.display = display;
+ this.launch = launch;
+ launch_node = new TCFNodeLaunch(TCFModel.this);
+ commands.put(ISuspendHandler.class, new SuspendCommand(this));
+ commands.put(IResumeHandler.class, new ResumeCommand(this));
+ commands.put(ITerminateHandler.class, new TerminateCommand(this));
+ commands.put(IDisconnectHandler.class, new DisconnectCommand(this));
+ commands.put(IStepIntoHandler.class, new StepIntoCommand(this));
+ commands.put(IStepOverHandler.class, new StepOverCommand(this));
+ commands.put(IStepReturnHandler.class, new StepReturnCommand(this));
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getCommand(Class c) {
+ Object o = commands.get(c);
+ assert o == null || c.isInstance(o);
+ return o;
+ }
+
+ void onConnected() {
+ assert Protocol.isDispatchThread();
+ IMemory mem = launch.getService(IMemory.class);
+ if (mem != null) mem.addListener(mem_listener);
+ IRunControl run = launch.getService(IRunControl.class);
+ if (run != null) run.addListener(run_listener);
+ launch_node.invalidateNode();
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void onDisconnected() {
+ assert Protocol.isDispatchThread();
+ TCFNode[] a = id2node.values().toArray(new TCFNode[id2node.size()]);
+ for (int i = 0; i < a.length; i++) {
+ if (!a[i].isDisposed()) a[i].dispose();
+ }
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void onProxyInstalled(final TCFModelProxy p) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ model_proxies.put(p.getPresentationContext(), p);
+ }
+ });
+ }
+
+ void onProxyDisposed(final TCFModelProxy p) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ model_proxies.remove(p.getPresentationContext());
+ }
+ });
+ }
+
+ void launchChanged() {
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void dispose() {
+ }
+
+ void addNode(String id, TCFNode node) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ assert id2node.get(id) == null;
+ assert !node.isDisposed();
+ id2node.put(id, node);
+ }
+
+ void removeNode(String id) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ id2node.remove(id);
+ }
+
+ ModelDelta getDelta(TCFNode node) {
+ return deltas.get(node);
+ }
+
+ void addDelta(TCFNode node, ModelDelta delta) {
+ assert deltas.get(node) == null;
+ deltas.put(node, delta);
+ }
+
+ void fireModelChanged() {
+ assert Protocol.isDispatchThread();
+ ModelDelta delta = deltas.get(launch_node);
+ assert (delta == null) == deltas.isEmpty();
+ if (delta != null) {
+ deltas.clear();
+ IModelDelta top = delta.getParentDelta();
+ for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged(top);
+ }
+ }
+
+ public Display getDisplay() {
+ return display;
+ }
+
+ public TCFLaunch getLaunch() {
+ return launch;
+ }
+
+ public TCFNode getRootNode() {
+ return launch_node;
+ }
+
+ public TCFNode getNode(String id) {
+ if (id == null) return null;
+ if (id.equals("")) return launch_node;
+ assert Protocol.isDispatchThread();
+ return id2node.get(id);
+ }
+
+ public void update(IChildrenCountUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(IChildrenUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(IHasChildrenUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ assert o != launch_node;
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public IModelProxy createModelProxy(Object element, IPresentationContext context) {
+ return new TCFModelProxy(this);
+ }
+
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ String id = getColumnPresentationId(context, element);
+ if (id == null) return null;
+ if (id.equals(TCFColumnPresentationRegister.PRESENTATION_ID)) return new TCFColumnPresentationRegister();
+ return null;
+ }
+
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId())) {
+ return TCFColumnPresentationRegister.PRESENTATION_ID;
+ }
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java
new file mode 100644
index 000000000..cfb9c9688
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFModelManager {
+
+ private final Display display;
+ private final Map models = new HashMap();
+
+ private final TCFLaunch.Listener tcf_launch_listener = new TCFLaunch.Listener() {
+
+ public void onConnected(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onConnected();
+ }
+
+ public void onDisconnected(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onDisconnected();
+ }
+ };
+
+ private final ILaunchesListener debug_launch_listener = new ILaunchesListener() {
+
+ public void launchesAdded(final ILaunch[] launches) {
+ }
+
+ public void launchesChanged(final ILaunch[] launches) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFModel model = models.get(launches[i]);
+ if (model != null) model.launchChanged();
+ }
+ }
+ }
+ });
+ }
+
+ public void launchesRemoved(final ILaunch[] launches) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFModel model = models.remove(launches[i]);
+ if (model != null) model.dispose();
+ }
+ }
+ }
+ });
+ }
+ };
+
+ public TCFModelManager() {
+ display = Display.getDefault();
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(debug_launch_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.addListener(tcf_launch_listener);
+ }
+ });
+ }
+
+ public void dispose() {
+ DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(debug_launch_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.removeListener(tcf_launch_listener);
+ for (Iterator i = models.values().iterator(); i.hasNext();) {
+ TCFModel model = i.next();
+ model.dispose();
+ i.remove();
+ }
+ assert models.isEmpty();
+ }
+ });
+ }
+
+ public TCFModel getModel(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model == null) {
+ model = new TCFModel(display, launch);
+ models.put(launch, model);
+ if (launch.getChannel() != null) tcf_launch_listener.onConnected(launch);
+ }
+ return model;
+ }
+
+ public TCFNode getRootNode(TCFLaunch launch) {
+ return getModel(launch).getRootNode();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java
new file mode 100644
index 000000000..07e358631
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.debug.ui.IValueDetailListener;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.windriver.debug.tcf.core.model.ITCFBreakpointListener;
+import com.windriver.debug.tcf.core.model.TCFBreakpoint;
+import com.windriver.debug.tcf.core.model.TCFBreakpointsStatus;
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFModelPresentation implements IDebugModelPresentation {
+
+ private final Collection listeners = new HashSet();
+
+ private IWorkbenchWindow active_window;
+ private TCFLaunch launch_selection;
+
+ private final TCFLaunch.Listener launch_listener = new TCFLaunch.Listener() {
+
+ public void onConnected(TCFLaunch launch) {
+ updateLaunchSelection();
+ }
+
+ public void onDisconnected(TCFLaunch launch) {
+ updateLaunchSelection();
+ }
+ };
+
+ private final ISelectionListener selection_listener = new ISelectionListener() {
+
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ updateLaunchSelection();
+ }
+ };
+
+ private final IWindowListener window_listener = new IWindowListener() {
+
+ public void windowActivated(IWorkbenchWindow window) {
+ if (active_window != null) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ window.getSelectionService().addSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = window;
+ updateLaunchSelection();
+ }
+
+ public void windowClosed(IWorkbenchWindow window) {
+ if (window == active_window) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ }
+
+ public void windowDeactivated(IWorkbenchWindow window) {
+ }
+
+ public void windowOpened(IWorkbenchWindow window) {
+ }
+ };
+
+ private final ITCFBreakpointListener breakpoint_status_listener = new ITCFBreakpointListener() {
+
+ public void breakpointStatusChanged(String id) {
+ refreshBreakpointView();
+ }
+ };
+
+ public TCFModelPresentation() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.addListener(launch_listener);
+ }
+ });
+ PlatformUI.getWorkbench().addWindowListener(window_listener);
+ IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (w != null) window_listener.windowActivated(w);
+ }
+
+ private void updateLaunchSelection() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ TCFLaunch launch = null;
+ IAdaptable adaptable = DebugUITools.getDebugContext();
+ if (adaptable != null) {
+ ILaunch x = (ILaunch)adaptable.getAdapter(ILaunch.class);
+ if (x instanceof TCFLaunch) {
+ final TCFLaunch l = (TCFLaunch)x;
+ final boolean[] b = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ IChannel channel = l.getChannel();
+ b[0] = channel != null && channel.getState() == IChannel.STATE_OPEN;
+ }
+ });
+ if (b[0]) launch = l;
+ }
+ }
+ if (launch_selection != launch) {
+ setBreakpointStatusListener(launch_selection, launch);
+ launch_selection = launch;
+ refreshBreakpointView();
+ }
+ }
+ });
+ }
+
+ private void refreshBreakpointView() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if (active_window != null) {
+ final IDebugView view = (IDebugView)active_window.getActivePage().findView(
+ IDebugUIConstants.ID_BREAKPOINT_VIEW);
+ if (view != null) {
+ view.getViewer().refresh();
+ }
+ }
+ }
+ });
+ }
+
+ private void setBreakpointStatusListener(final TCFLaunch prev, final TCFLaunch next) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (prev != null && prev.getBreakpointsStatus() != null) {
+ prev.getBreakpointsStatus().removeListener(breakpoint_status_listener);
+ }
+ if (next != null && next.getBreakpointsStatus() != null) {
+ next.getBreakpointsStatus().addListener(breakpoint_status_listener);
+ }
+ }
+ });
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void dispose() {
+ if (launch_selection != null) {
+ setBreakpointStatusListener(launch_selection, null);
+ launch_selection = null;
+ }
+ if (active_window != null) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ PlatformUI.getWorkbench().removeWindowListener(window_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.removeListener(launch_listener);
+ }
+ });
+ }
+
+ public void computeDetail(IValue value, IValueDetailListener listener) {
+ }
+
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ public String getText(Object element) {
+ if (element instanceof TCFBreakpoint) {
+ final TCFBreakpoint breakpoint = (TCFBreakpoint)element;
+ final TCFLaunch launch = launch_selection;
+ final String[] text = new String[1];
+ text[0] = breakpoint.getText();
+ if (launch != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFBreakpointsStatus bs = launch.getBreakpointsStatus();
+ if (bs != null) {
+ Map map = bs.getStatus(breakpoint);
+ if (map != null) {
+ String status = null;
+ String error = (String)map.get(IBreakpoints.STATUS_ERROR);
+ Object planted = map.get(IBreakpoints.STATUS_PLANTED);
+ if (error != null) status = error;
+ else if (planted != null) status = "Planted";
+ if (status != null) text[0] += " (" + status + ")";
+ }
+ }
+ }
+ });
+ }
+ return text[0];
+ }
+ return null;
+ }
+
+ public void setAttribute(String attribute, Object value) {
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return true;
+ }
+
+ public String getEditorId(IEditorInput input, Object element) {
+ return null;
+ }
+
+ public IEditorInput getEditorInput(Object element) {
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java
new file mode 100644
index 000000000..dbdae8822
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.jface.viewers.Viewer;
+
+public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
+
+ private final TCFModel model;
+
+ TCFModelProxy(TCFModel model) {
+ this.model = model;
+ }
+
+ public void installed(Viewer viewer) {
+ super.installed(viewer);
+ model.onProxyInstalled(this);
+ }
+
+ public void dispose() {
+ model.onProxyDisposed(this);
+ super.dispose();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java
new file mode 100644
index 000000000..6c07354ea
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.viewers.ISelection;
+
+public class TCFModelSelectionPolicy implements IModelSelectionPolicy {
+
+ public boolean contains(ISelection selection, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isSticky(ISelection selection, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean overrides(ISelection existing, ISelection candidate,
+ IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public ISelection replaceInvalidSelection(ISelection invalidSelection,
+ ISelection newSelection) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java
new file mode 100644
index 000000000..c213e0c2d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.RGB;
+import org.osgi.framework.Bundle;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+/**
+ * TCFNode is base class for all TCF debug model elements.
+ */
+public class TCFNode extends PlatformObject
+implements IMemoryBlockRetrievalExtension, Comparable {
+
+ protected final String id;
+ protected final TCFNode parent;
+ protected final TCFModel model;
+
+ protected boolean disposed;
+
+ protected TCFNode(TCFNode parent, String id) {
+ assert Protocol.isDispatchThread();
+ this.parent = parent;
+ this.id = id;
+ model = parent.model;
+ }
+
+ protected TCFNode(TCFModel model) {
+ id = null;
+ parent = null;
+ this.model = model;
+ }
+
+ /**
+ * Dispose this node. The node is removed from the model.
+ */
+ void dispose() {
+ assert !disposed;
+ if (parent != null) parent.dispose(id);
+ model.removeNode(id);
+ disposed = true;
+ }
+
+ /**
+ * A child node is being disposed.
+ * The child should be removed from this node children lists.
+ */
+ void dispose(String id) {
+ }
+
+ /**
+ * Check if node is disposed.
+ * @return true if disposed.
+ */
+ public final boolean isDisposed() {
+ return disposed;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (adapter == ILaunch.class) return model.getLaunch();
+ if (adapter == IModelProxyFactory.class) return model;
+ if (adapter == IElementLabelProvider.class) return model;
+ if (adapter == IElementContentProvider.class) return model;
+ if (adapter == IColumnPresentationFactory.class) return model;
+ Object o = model.getCommand(adapter);
+ if (o != null) return o;
+ //System.err.println(adapter.getName());
+ return super.getAdapter(adapter);
+ }
+
+ public final TCFNode getParent() {
+ assert Protocol.isDispatchThread();
+ return parent;
+ }
+
+ public IRunControl.RunControlContext getRunContext() {
+ return null;
+ }
+
+ public IMemory.MemoryContext getMemoryContext() {
+ return null;
+ }
+
+ public boolean isRunning() {
+ return false;
+ }
+
+ public boolean isSuspended() {
+ return false;
+ }
+
+ /**
+ * Return address of this node.
+ * For executable contexts and stack frames address is current PC.
+ * @return
+ */
+ public String getAddress() {
+ return null;
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
+ * @param result - children count update request.
+ */
+ final void update(final IChildrenCountUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setChildCount(0);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * @param result - children update request.
+ */
+ final void update(final IChildrenUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Check if node has children in a presentation context.
+ * @param result - "has children" update request.
+ */
+ final void update(final IHasChildrenUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setHasChilren(false);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * @param result - label update request.
+ */
+ final void update(final ILabelUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed) {
+ if (!validateNode(this)) return;
+ if (node_error != null) {
+ result.setBackground(new RGB(255, 0, 0), 0);
+ result.setLabel(node_error.getClass().getName() +
+ ": " + node_error.getMessage(), 0);
+ }
+ else {
+ getData(result);
+ }
+ }
+ else {
+ result.setLabel("[Disposed]", 0);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - children count update request.
+ */
+ protected void getData(IChildrenCountUpdate result) {
+ result.setChildCount(0);
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - children update request.
+ */
+ protected void getData(IChildrenUpdate result) {
+ }
+
+ /**
+ * Check if the node has children in a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - "has children" update request.
+ */
+ protected void getData(IHasChildrenUpdate result) {
+ result.setHasChilren(false);
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - label update request.
+ */
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ result.setLabel(id, 0);
+ }
+
+ /**
+ * Create ModelDelta for changes in this node.
+ * @param flags - description of what has changed: CF_CONTEXT, CF_CHILDREN or CF_ALL.
+ * @return - ModelDelta that describes node changes.
+ */
+ ModelDelta makeModelDelta(int flags) {
+ int count = -1;
+ //if (node_valid == CF_ALL) count = children.size();
+ ModelDelta delta = model.getDelta(this);
+ int index = -1;
+ /*
+ if (parent.node_valid == CF_ALL) {
+ index = 0;
+ for (Iterator i = parent.children.values().iterator(); i.hasNext();) {
+ if (i.next() == this) break;
+ index++;
+ }
+ }
+ */
+ if (delta == null || delta.getChildCount() != count || delta.getIndex() != index) {
+ ModelDelta parent_delta = parent.makeModelDelta(IModelDelta.NO_CHANGE);
+ delta = parent_delta.addNode(this, index, flags, count);
+ model.addDelta(this, delta);
+ }
+ else {
+ delta.setFlags(delta.getFlags() | flags);
+ }
+ return delta;
+ }
+
+ void onContextAdded(IRunControl.RunControlContext context) {
+ assert !disposed;
+ // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+
+ void onContextAdded(IMemory.MemoryContext context) {
+ assert !disposed;
+ // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Node data retrieval state machine */
+
+ protected static final int
+ CF_CHILDREN = 0x0001,
+ CF_CONTEXT = 0x0002,
+ CF_ALL = CF_CHILDREN | CF_CONTEXT;
+
+ protected int node_valid;
+ protected Throwable node_error;
+ protected IToken data_command;
+ protected final Collection wait_list = new ArrayList();
+
+ /**
+ * Invalidate the node - flush all cached data.
+ */
+ public void invalidateNode() {
+ invalidateNode(CF_ALL);
+ }
+
+ protected void invalidateNode(int flags) {
+ // flags - set of CF_*
+
+ // cancel current data retrieval command
+ if (data_command != null) {
+ data_command.cancel();
+ data_command = null;
+ }
+
+ // cancel waiting monitors
+ if (!wait_list.isEmpty()) {
+ TCFRunnable[] arr = wait_list.toArray(new TCFRunnable[wait_list.size()]);
+ for (TCFRunnable r : arr) r.cancel();
+ wait_list.clear();
+ }
+
+ if (flags == CF_ALL) {
+ node_error = null;
+ }
+
+ node_valid &= ~flags;
+ }
+
+ /**
+ * Validate node - retrieve and put into a cache missing data from remote peer.
+ * Validation is done asynchronously.
+ * @param done - call back, it is called when validation is done.
+ * @return true if the node is valid, false if validation is started.
+ */
+ public boolean validateNode(TCFRunnable done) {
+ assert Protocol.isDispatchThread();
+ assert (node_valid & ~CF_ALL) == 0;
+ if (data_command != null) {
+ if (done != null) wait_list.add(done);
+ return false;
+ }
+ else if (model.getLaunch().getChannel() == null) {
+ node_error = null;
+ node_valid = CF_ALL;
+ }
+ else {
+ if ((node_valid & CF_CONTEXT) == 0 && !validateContext(done)) return false;
+ if ((node_valid & CF_CHILDREN) == 0 && !validateChildren(done)) return false;
+ }
+ assert node_valid == CF_ALL;
+ if (!wait_list.isEmpty()) {
+ Runnable[] arr = wait_list.toArray(new Runnable[wait_list.size()]);
+ wait_list.clear();
+ for (int i = 0; i < arr.length; i++) arr[i].run();
+ }
+ return true;
+ }
+
+ protected boolean validateContext(TCFRunnable done) {
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ protected boolean validateChildren(TCFRunnable done) {
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Memory Block Retrieval */
+
+ public IMemoryBlockExtension getExtendedMemoryBlock(String addr, Object ctx) throws DebugException {
+ assert ctx == this;
+ return getMemoryBlock(addr, 0);
+ }
+
+ public IMemoryBlock getMemoryBlock(long addr, long length) throws DebugException {
+ return getMemoryBlock(Long.toString(addr), length);
+ }
+
+ public boolean supportsStorageRetrieval() {
+ return getMemoryContext() != null;
+ }
+
+ private IMemoryBlockExtension getMemoryBlock(String addr, long length) throws DebugException {
+ assert !Protocol.isDispatchThread();
+ // TODO: MemoryBlock
+ return null;
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Misc */
+
+ private static final Map image_cache = new HashMap();
+
+ static ImageDescriptor getImageDescriptor(String name) {
+ if (name == null) return null;
+ ImageDescriptor descriptor = image_cache.get(name);
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ Bundle bundle = Platform.getBundle("org.eclipse.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image_cache.put(name, descriptor);
+ }
+ return descriptor;
+ }
+
+ protected String getImageName() {
+ return null;
+ }
+
+ public int compareTo(TCFNode n) {
+ return id.compareTo(n.id);
+ }
+
+ public String toString() {
+ String s = "[" + Integer.toHexString(hashCode()) + "] " + id;
+ if (disposed) s += ", disposed";
+ return s;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java
new file mode 100644
index 000000000..996391ce0
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java
@@ -0,0 +1,487 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFNodeExecContext extends TCFNode {
+
+ private final TCFChildren children_exec;
+ private final TCFChildren children_stack;
+ private final TCFChildren children_regs;
+
+ private IMemory.MemoryContext mem_context;
+ private IRunControl.RunControlContext run_context;
+
+ private boolean suspended;
+ private String suspended_pc;
+ private String suspended_reason;
+ @SuppressWarnings("unused")
+ private Map suspended_params;
+ private boolean running;
+ private boolean terminated;
+ @SuppressWarnings("unused")
+ private String exception_msg;
+
+ private boolean valid_mem_ctx;
+ private boolean valid_run_ctx;
+ private boolean valid_state;
+
+ TCFNodeExecContext(TCFNode parent, String id) {
+ super(parent, id);
+ children_exec = new TCFChildrenExecContext(this);
+ children_regs = new TCFChildrenRegisters(this);
+ children_stack = new TCFChildrenStackTrace(this, children_regs);
+ }
+
+ @Override
+ void dispose() {
+ children_exec.dispose();
+ children_stack.dispose();
+ children_regs.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children_exec.dispose(id);
+ children_stack.dispose(id);
+ children_regs.dispose(id);
+ }
+
+ @Override
+ public IRunControl.RunControlContext getRunContext() {
+ assert Protocol.isDispatchThread();
+ return run_context;
+ }
+
+ @Override
+ public IMemory.MemoryContext getMemoryContext() {
+ assert Protocol.isDispatchThread();
+ return mem_context;
+ }
+
+ @Override
+ public boolean isRunning() {
+ assert Protocol.isDispatchThread();
+ return running;
+ }
+
+ @Override
+ public boolean isSuspended() {
+ assert Protocol.isDispatchThread();
+ return suspended;
+ }
+
+ @Override
+ public String getAddress() {
+ assert Protocol.isDispatchThread();
+ return suspended_pc;
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setChildCount(children_regs.size());
+ }
+ else {
+ result.setChildCount(children_stack.size());
+ }
+ }
+ else {
+ result.setChildCount(children_exec.size());
+ }
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = null;
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ arr = children_regs.toArray();
+ }
+ else {
+ arr = children_stack.toArray();
+ }
+ }
+ else {
+ arr = children_exec.toArray();
+ }
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setHasChilren(children_regs.size() > 0);
+ }
+ else {
+ result.setHasChilren(children_stack.size() > 0);
+ }
+ }
+ else {
+ result.setHasChilren(children_exec.size() > 0);
+ }
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ if (run_context != null) {
+ if (run_context.hasState()) {
+ if (running) {
+ label += " (Running)";
+ }
+ else if (suspended) {
+ if (suspended_reason != null) {
+ label += " (" + suspended_reason + ")";
+ }
+ else {
+ label += " (Suspended)";
+ }
+ }
+ }
+ String file = (String)run_context.getProperties().get("File");
+ if (file != null) label += " " + file;
+ }
+ result.setLabel(label, 0);
+ }
+
+ @Override
+ ModelDelta makeModelDelta(int flags) {
+ if (run_context != null && run_context.isContainer()) flags |= IModelDelta.STATE;
+ return super.makeModelDelta(flags);
+ }
+
+ @Override
+ void onContextAdded(IRunControl.RunControlContext context) {
+ assert !disposed;
+ if (node_valid == CF_ALL) {
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(this, id);
+ n.run_context = context;
+ n.valid_run_ctx = true;
+ children_exec.children.put(id, n);
+ model.addNode(id, n);
+ n.makeModelDelta(IModelDelta.INSERTED);
+ }
+ else {
+ n.run_context = context;
+ n.makeModelDelta(IModelDelta.STATE);
+ }
+ }
+ else {
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContextChanged(IRunControl.RunControlContext context) {
+ assert !disposed;
+ run_context = context;
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ @Override
+ void onContextAdded(IMemory.MemoryContext context) {
+ assert !disposed;
+ if (node_valid == CF_ALL) {
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(this, id);
+ n.mem_context = context;
+ n.valid_mem_ctx = true;
+ children_exec.children.put(id, n);
+ model.addNode(id, n);
+ n.makeModelDelta(IModelDelta.INSERTED);
+ }
+ else {
+ n.mem_context = context;
+ n.makeModelDelta(IModelDelta.STATE);
+ }
+ }
+ else {
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContextChanged(IMemory.MemoryContext context) {
+ assert !disposed;
+ mem_context = context;
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextRemoved() {
+ assert !disposed;
+ dispose();
+ if (parent.node_valid == CF_ALL) {
+ makeModelDelta(IModelDelta.REMOVED);
+ }
+ else {
+ parent.invalidateNode(CF_CHILDREN);
+ parent.makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContainerSuspended() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ suspended = false;
+ running = false;
+ valid_state = false;
+ invalidateNode(CF_CHILDREN);
+ suspended = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContainerResumed() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ suspended = false;
+ running = false;
+ valid_state = false;
+ invalidateNode(CF_CHILDREN);
+ suspended = false;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextSuspended(String pc, String reason, Map params) {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ invalidateNode(CF_CHILDREN);
+ suspended = true;
+ suspended_pc = pc;
+ suspended_reason = reason;
+ suspended_params = params;
+ running = false;
+ valid_state = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextResumed() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ invalidateNode(CF_CHILDREN);
+ exception_msg = null;
+ terminated = false;
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ running = true;
+ valid_state = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextException(String msg) {
+ assert !disposed;
+ exception_msg = msg;
+ makeModelDelta(IModelDelta.STATE);
+ }
+
+ void onMemoryChanged(Number[] addr, long[] size) {
+ assert !disposed;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CONTEXT) != 0) {
+ valid_mem_ctx = false;
+ valid_run_ctx = false;
+ valid_state = false;
+ running = false;
+ suspended = false;
+ }
+ if ((flags & CF_CHILDREN) != 0) {
+ children_exec.invalidate();
+ children_stack.invalidate();
+ children_regs.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ if (!valid_mem_ctx && !validateMemoryContext(done)) return false;
+ if (!valid_run_ctx && !validateRunControlContext(done)) return false;
+ if (!valid_state && !validateRunControlState(done)) return false;
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children_stack.valid && !children_stack.validate(done)) return false;
+ if (!children_regs.valid && !children_regs.validate(done)) return false;
+ if (!children_exec.valid && !children_exec.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ private boolean validateMemoryContext(TCFRunnable done) {
+ assert data_command == null;
+ IMemory mem = model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ valid_mem_ctx = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = mem.getContext(id, new IMemory.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ mem_context = context;
+ }
+ valid_mem_ctx = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlContext(TCFRunnable done) {
+ assert data_command == null;
+ IRunControl run = model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ valid_run_ctx = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = run.getContext(id, new IRunControl.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ run_context = context;
+ }
+ valid_run_ctx = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlState(TCFRunnable done) {
+ assert data_command == null;
+ if (node_error != null || run_context == null || !run_context.hasState()) {
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ running = false;
+ valid_state = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = run_context.getState(new IRunControl.DoneGetState() {
+ public void doneGetState(IToken token, Exception error, boolean suspend, String pc, String reason, Map params) {
+ if (token != data_command) return;
+ data_command = null;
+ if (error != null) {
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ node_error = error;
+ running = false;
+ }
+ else {
+ suspended = suspend;
+ if (suspend) {
+ suspended_pc = pc;
+ suspended_reason = reason;
+ suspended_params = params;
+ }
+ else {
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ }
+ running = !suspend;
+ }
+ valid_state = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean hasSuspendedChildren() {
+ for (TCFNode n : children_exec.children.values()) {
+ if (n instanceof TCFNodeExecContext) {
+ TCFNodeExecContext e = (TCFNodeExecContext)n;
+ if (e.run_context != null) {
+ if (e.run_context.hasState() && e.suspended) return true;
+ if (e.run_context.isContainer() && e.hasSuspendedChildren()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected String getImageName() {
+ if (run_context != null && run_context.hasState()) {
+ // Thread
+ if (terminated) return "icons/full/obj16/threadt_obj.gif";
+ if (suspended) return "icons/full/obj16/threads_obj.gif";
+ return "icons/full/obj16/thread_obj.gif";
+ }
+ else if (run_context != null) {
+ // Thread container (process)
+ if (terminated) return "icons/full/obj16/debugtt_obj.gif";
+ if (hasSuspendedChildren()) return "icons/full/obj16/debugts_obj.gif";
+ return "icons/full/obj16/debugt_obj.gif";
+ }
+ return super.getImageName();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java
new file mode 100644
index 000000000..b800e2cbe
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.util.Arrays;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.swt.graphics.RGB;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+
+public class TCFNodeLaunch extends TCFNode {
+
+ private final TCFChildren children;
+
+ TCFNodeLaunch(TCFModel model) {
+ super(model);
+ children = new TCFChildrenExecContext(this);
+ }
+
+ @Override
+ void dispose() {
+ children.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children.dispose(id);
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ result.setChildCount(children.size());
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = children.toArray();
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ result.setHasChilren(children.size() > 0);
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ TCFLaunch launch = model.getLaunch();
+ String status = "";
+ if (launch.isConnecting()) status = "Connecting";
+ else if (launch.isDisconnected()) status = "Disconnected";
+ else if (launch.isTerminated()) status = "Terminated";
+ Throwable error = launch.getError();
+ if (error != null) {
+ status += " - " + error;
+ result.setForeground(new RGB(255, 0, 0), 0);
+ }
+ if (status.length() > 0) status = " (" + status + ")";
+ label = launch.getLaunchConfiguration().getName() + status;
+ result.setLabel(label, 0);
+ }
+
+ @Override
+ ModelDelta makeModelDelta(int flags) {
+ int count = -1;
+ //if (node_valid == CF_ALL) count = children.size();
+ ModelDelta delta = model.getDelta(this);
+ if (delta == null) {
+ delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
+ delta = delta.addNode(model.getLaunch(), -1, flags, count);
+ model.addDelta(this, delta);
+ }
+ else {
+ assert delta.getChildCount() == count;
+ delta.setFlags(delta.getFlags() | flags);
+ }
+ return delta;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CHILDREN) != 0) {
+ children.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children.valid && !children.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ @Override
+ protected String getImageName() {
+ return "icons/full/obj16/ldebug_obj.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java
new file mode 100644
index 000000000..9309c1bd9
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRegisters;
+
+// TODO: hierarchical registers
+public class TCFNodeRegister extends TCFNode {
+
+ /**
+ * Presentation column IDs.
+ */
+ public static final String
+ COL_NAME = "Name",
+ COL_HEX_VALUE = "HexValue",
+ COL_DEC_VALUE = "DecValue",
+ COL_DESCRIPTION = "Description",
+ COL_READBLE = "Readable",
+ COL_READ_ONCE = "ReadOnce",
+ COL_WRITEABLE = "Writeable",
+ COL_WRITE_ONCE = "WriteOnce",
+ COL_SIDE_EFFECTS = "SideEffects",
+ COL_VOLATILE = "Volatile",
+ COL_FLOAT = "Float",
+ COL_MNEMONIC = "Menimonic";
+
+
+ private IRegisters.RegistersContext context;
+ private String hex_value;
+ private String dec_value;
+ private Number num_value;
+ private boolean valid_context;
+ private boolean valid_hex_value;
+ private boolean valid_dec_value;
+
+ TCFNodeRegister(TCFNode parent, String id) {
+ super(parent, id);
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ if (context != null) {
+ String[] cols = result.getColumnIds();
+ if (cols == null) {
+ result.setLabel(context.getName() + " = " + hex_value, 0);
+ }
+ else {
+ for (int i = 0; i < cols.length; i++) {
+ String c = cols[i];
+ if (c.equals(COL_NAME)) result.setLabel(context.getName(), i);
+ else if (c.equals(COL_HEX_VALUE)) result.setLabel(hex_value, i);
+ else if (c.equals(COL_DEC_VALUE)) result.setLabel(dec_value, i);
+ else if (c.equals(COL_DESCRIPTION)) result.setLabel(context.getDescription(), i);
+ else if (c.equals(COL_READBLE)) result.setLabel(bool(context.isReadable()), i);
+ else if (c.equals(COL_READ_ONCE)) result.setLabel(bool(context.isReadOnce()), i);
+ else if (c.equals(COL_WRITEABLE)) result.setLabel(bool(context.isWriteable()), i);
+ else if (c.equals(COL_WRITE_ONCE)) result.setLabel(bool(context.isWriteOnce()), i);
+ else if (c.equals(COL_SIDE_EFFECTS)) result.setLabel(bool(context.hasSideEffects()), i);
+ else if (c.equals(COL_VOLATILE)) result.setLabel(bool(context.isVolatile()), i);
+ else if (c.equals(COL_FLOAT)) result.setLabel(bool(context.isFloat()), i);
+ else if (c.equals(COL_MNEMONIC)) result.setLabel(getMnemonic(), i);
+ }
+ }
+ }
+ else {
+ result.setLabel(id, 0);
+ }
+ }
+
+ private String bool(boolean b) {
+ return b ? "yes" : "no";
+ }
+
+ private String getMnemonic() {
+ if (num_value != null) {
+ IRegisters.NamedValue[] arr = context.getNamedValues();
+ if (arr != null) {
+ if (context.isFloat()) {
+ for (IRegisters.NamedValue n : arr) {
+ if (n.getValue().doubleValue() == num_value.doubleValue()) return n.getName();
+ }
+ }
+ else {
+ for (IRegisters.NamedValue n : arr) {
+ if (n.getValue().longValue() == num_value.longValue()) return n.getName();
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CONTEXT) != 0) {
+ valid_context = false;
+ valid_hex_value = false;
+ valid_dec_value = false;
+ hex_value = null;
+ dec_value = null;
+ num_value = null;
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ if (!valid_context && !validateRegisterContext(done)) return false;
+ if (!valid_hex_value && !validateRegisterHexValue(done)) return false;
+ if (!valid_dec_value && !validateRegisterDecValue(done)) return false;
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ private boolean validateRegisterContext(TCFRunnable done) {
+ assert data_command == null;
+ IRegisters regs = model.getLaunch().getService(IRegisters.class);
+ if (done != null) wait_list.add(done);
+ data_command = regs.getContext(id, new IRegisters.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ TCFNodeRegister.this.context = context;
+ }
+ valid_context = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRegisterHexValue(TCFRunnable done) {
+ assert data_command == null;
+ if (done != null) wait_list.add(done);
+ String[] fmts = context.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_HEX)) fmt = s;
+ }
+ if (fmt == null) {
+ valid_hex_value = true;
+ return true;
+ }
+ data_command = context.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ hex_value = value;
+ }
+ valid_hex_value = true;
+ if (!context.isFloat()) num_value = Long.valueOf(value, 16);
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRegisterDecValue(TCFRunnable done) {
+ assert data_command == null;
+ if (done != null) wait_list.add(done);
+ String[] fmts = context.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_DECIMAL)) fmt = s;
+ }
+ if (fmt == null) {
+ valid_dec_value = true;
+ return true;
+ }
+ data_command = context.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ dec_value = value;
+ }
+ valid_dec_value = true;
+ if (!context.isFloat()) num_value = Long.valueOf(value, 10);
+ else num_value = Double.valueOf(value);
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ @Override
+ protected String getImageName() {
+ return "icons/full/obj16/genericregister_obj.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java
new file mode 100644
index 000000000..91683da5e
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILineNumbers;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+import com.windriver.tcf.api.services.IStackTrace;
+import com.windriver.tcf.api.services.ILineNumbers.CodeArea;
+
+public class TCFNodeStackFrame extends TCFNode {
+
+ private IStackTrace.StackTraceContext stack_trace_context;
+ private ILineNumbers.CodeArea code_area;
+
+ private final int frame_no;
+ private final TCFChildren children_regs;
+
+ TCFNodeStackFrame(TCFNode parent, String id, TCFChildren children_regs) {
+ super(parent, id);
+ this.frame_no = 0;
+ this.children_regs = children_regs;
+ }
+
+ TCFNodeStackFrame(TCFNode parent, String id, int frame_no) {
+ super(parent, id);
+ this.frame_no = frame_no;
+ children_regs = new TCFChildrenRegisters(this);
+ }
+
+ int getFrameNo() {
+ return frame_no;
+ }
+
+ @Override
+ void dispose() {
+ children_regs.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children_regs.dispose(id);
+ }
+
+ @Override
+ public IRunControl.RunControlContext getRunContext() {
+ return parent.getRunContext();
+ }
+
+ @Override
+ public IMemory.MemoryContext getMemoryContext() {
+ return parent.getMemoryContext();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return parent.isRunning();
+ }
+
+ @Override
+ public boolean isSuspended() {
+ return parent.isSuspended();
+ }
+
+ @Override
+ public String getAddress() {
+ assert Protocol.isDispatchThread();
+ if (frame_no == 0) return parent.getAddress();
+ if (stack_trace_context != null) {
+ return stack_trace_context.getReturnAddress().toString();
+ }
+ return null;
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setChildCount(children_regs.size());
+ }
+ else {
+ result.setChildCount(0);
+ }
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = null;
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ arr = children_regs.toArray();
+ }
+ else {
+ arr = null;
+ }
+ if (arr != null) {
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setHasChilren(children_regs.size() > 0);
+ }
+ else {
+ result.setHasChilren(false);
+ }
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ Number n = null;
+ if (frame_no == 0 && parent.getAddress() != null) {
+ n = new BigInteger(parent.getAddress());
+ }
+ else if (stack_trace_context != null) {
+ n = stack_trace_context.getReturnAddress();
+ }
+ if (n == null) {
+ label = "...";
+ }
+ else {
+ label = makeHexAddrString(n);
+ if (code_area != null && code_area.file != null) {
+ label += ": " + code_area.file + ", line " + (code_area.start_line + 1);
+ }
+ }
+ result.setLabel(label, 0);
+ }
+
+ private String makeHexAddrString(Number n) {
+ BigInteger i = null;
+ if (n instanceof BigInteger) i = (BigInteger)n;
+ else i = new BigInteger(n.toString());
+ String s = i.toString(16);
+ IMemory.MemoryContext m = getMemoryContext();
+ int sz = (m != null ? m.getAddressSize() : 4) * 2;
+ int l = sz - s.length();
+ if (l < 0) l = 0;
+ if (l > 16) l = 16;
+ return "0x0000000000000000".substring(0, 2 + l) + s;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CHILDREN) != 0) {
+ children_regs.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ assert data_command == null;
+ if (frame_no == 0) {
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+ IStackTrace st = model.getLaunch().getService(IStackTrace.class);
+ if (done != null) wait_list.add(done);
+ data_command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ stack_trace_context = context[0];
+ }
+ BigInteger n = null;
+ ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class);
+ if (node_error == null && ln != null) {
+ String s = getAddress();
+ if (s != null) n = new BigInteger(s);
+ }
+ code_area = null;
+ if (n == null) {
+ node_valid |= CF_CONTEXT;
+ validateNode(null);
+ }
+ else {
+ BigInteger m = n.add(BigInteger.valueOf(1));
+ data_command = ln.mapToSource(parent.id, n, m, new ILineNumbers.DoneMapToSource() {
+ public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else if (areas != null && areas.length > 0) {
+ for (ILineNumbers.CodeArea area : areas) {
+ if (code_area == null || area.start_line < code_area.start_line) {
+ code_area = area;
+ }
+ }
+ }
+ node_valid |= CF_CONTEXT;
+ validateNode(null);
+ }
+ });
+ }
+ }
+ });
+ return false;
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children_regs.valid && !children_regs.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ @Override
+ protected String getImageName() {
+ if (isRunning()) return "icons/full/obj16/stckframe_running_obj.gif";
+ return "icons/full/obj16/stckframe_obj.gif";
+ }
+
+ @Override
+ public int compareTo(TCFNode n) {
+ if (n instanceof TCFNodeStackFrame) {
+ TCFNodeStackFrame f = (TCFNodeStackFrame)n;
+ if (frame_no < f.frame_no) return -1;
+ if (frame_no > f.frame_no) return +1;
+ }
+ return id.compareTo(n.id);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java
new file mode 100644
index 000000000..f55cb8afb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class TCFRunnable implements Runnable {
+
+ private final IRequest monitor;
+ private final Display display;
+
+ public TCFRunnable(Display display, IRequest monitor) {
+ this.monitor = monitor;
+ this.display = display;
+ Protocol.invokeLater(this);
+ }
+
+ public void cancel() {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ monitor.cancel();
+ monitor.done();
+ }
+ });
+ }
+
+ public void done() {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ monitor.done();
+ }
+ });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java
new file mode 100644
index 000000000..824346801
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.debug.tcf.ui.trace;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.core.AbstractChannel;
+
+public class TraceView extends ViewPart implements Protocol.ChannelOpenListener {
+
+ private Composite parent;
+ private TabFolder tabs;
+ private Label no_data;
+ private final Map tab2page = new HashMap();
+
+ private class Page implements AbstractChannel.TraceListener {
+
+ final AbstractChannel channel;
+
+ private TabItem tab;
+ private Text text;
+
+ private final StringBuffer bf = new StringBuffer();
+ private int bf_line_cnt = 0;
+ private boolean closed;
+
+ private final Thread update_thread = new Thread() {
+ public void run() {
+ synchronized (Page.this) {
+ while (!closed) {
+ if (bf_line_cnt > 0) {
+ Runnable r = new Runnable() {
+ public void run() {
+ String str = null;
+ int cnt = 0;
+ synchronized (Page.this) {
+ str = bf.toString();
+ cnt = bf_line_cnt;
+ bf.setLength(0);
+ bf_line_cnt = 0;
+ }
+ if (text == null) return;
+ if (text.getLineCount() > 1000 - cnt) {
+ String s = text.getText();
+ int n = 0;
+ int i = -1;
+ while (n < cnt) {
+ int j = s.indexOf('\n', i + 1);
+ if (j < 0) break;
+ i = j;
+ n++;
+ }
+ if (i >= 0) {
+ text.setText(s.substring(i + 1));
+ }
+ }
+ text.append(str);
+ }
+ };
+ getSite().getShell().getDisplay().asyncExec(r);
+ }
+ try {
+ Page.this.wait(1000);
+ }
+ catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ Page(AbstractChannel channel) {
+ this.channel = channel;
+ update_thread.start();
+ }
+
+ public void dispose() {
+ synchronized (this) {
+ closed = true;
+ update_thread.interrupt();
+ }
+ try {
+ update_thread.join();
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ tab2page.remove(tab);
+ tab.dispose();
+ tab = null;
+ text = null;
+ if (tab2page.isEmpty()) hideTabs();
+ }
+
+ public synchronized void onChannelClosed(Throwable error) {
+ if (error == null) {
+ channel.removeTraceListener(this);
+ getSite().getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ dispose();
+ }
+ });
+ }
+ else {
+ bf.append("Channel terminated: " + error);
+ bf_line_cnt++;
+ }
+ }
+
+ public synchronized void onMessageReceived(char type, String token,
+ String service, String name, byte[] data) {
+ try {
+ bf.append("Inp: ");
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token);
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append('\n');
+ bf_line_cnt++;
+ }
+ catch (UnsupportedEncodingException x) {
+ x.printStackTrace();
+ }
+ }
+
+ public synchronized void onMessageSent(char type, String token,
+ String service, String name, byte[] data) {
+ try {
+ bf.append("Out: ");
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token);
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append('\n');
+ bf_line_cnt++;
+ }
+ catch (UnsupportedEncodingException x) {
+ x.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ this.parent = parent;
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ IChannel[] arr = Protocol.getOpenChannels();
+ for (IChannel c : arr) onChannelOpen(c);
+ Protocol.addChannelOpenListener(TraceView.this);
+ }
+ });
+ if (tab2page.size() == 0) hideTabs();
+ }
+
+ @Override
+ public void setFocus() {
+ if (tabs != null) tabs.setFocus();
+ }
+
+ @Override
+ public void dispose() {
+ final Page[] pages = tab2page.values().toArray(new Page[tab2page.size()]);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ Protocol.removeChannelOpenListener(TraceView.this);
+ for (Page p : pages) p.channel.removeTraceListener(p);
+ }
+ });
+ for (Page p : pages) p.dispose();
+ assert tab2page.isEmpty();
+ if (tabs != null) {
+ tabs.dispose();
+ tabs = null;
+ }
+ if (no_data != null) {
+ no_data.dispose();
+ no_data = null;
+ }
+ super.dispose();
+ }
+
+ public void onChannelOpen(final IChannel channel) {
+ if (!(channel instanceof AbstractChannel)) return;
+ AbstractChannel c = (AbstractChannel)channel;
+ IPeer rp = c.getRemotePeer();
+ final String name = rp.getName();
+ final String host = rp.getAttributes().get(IPeer.ATTR_IP_HOST);
+ final String port = rp.getAttributes().get(IPeer.ATTR_IP_PORT);
+ final Page p = new Page(c);
+ c.addTraceListener(p);
+ getSite().getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ showTabs();
+ p.tab = new TabItem(tabs, SWT.NONE);
+ tab2page.put(p.tab, p);
+ String title = name;
+ if (host != null) {
+ title += ", " + host;
+ if (port != null) {
+ title += ":" + port;
+ }
+ }
+ p.tab.setText(title);
+ p.text = new Text(tabs, SWT.H_SCROLL | SWT.V_SCROLL |
+ SWT.BORDER | SWT.READ_ONLY | SWT.MULTI);
+ p.tab.setControl(p.text);
+ p.text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ }
+ });
+ }
+
+ private void showTabs() {
+ boolean b = false;
+ if (no_data != null) {
+ no_data.dispose();
+ no_data = null;
+ b = true;
+ }
+ if (tabs == null) {
+ tabs = new TabFolder(parent, SWT.NONE);
+ b = true;
+ }
+ if (b) parent.layout();
+ }
+
+ private void hideTabs() {
+ boolean b = false;
+ if (tabs != null) {
+ tabs.dispose();
+ tabs = null;
+ b = true;
+ }
+ if (!parent.isDisposed()) {
+ if (no_data == null) {
+ no_data = new Label(parent, SWT.NONE);
+ no_data.setText("No open communication channels at this time.");
+ b = true;
+ }
+ if (b) parent.layout();
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/.classpath b/plugins/com.windriver.tcf.api/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/plugins/com.windriver.tcf.api/.cvsignore b/plugins/com.windriver.tcf.api/.cvsignore
new file mode 100644
index 000000000..c5e82d745
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.cvsignore
@@ -0,0 +1 @@
+bin
\ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/.project b/plugins/com.windriver.tcf.api/.project
new file mode 100644
index 000000000..48171f9bd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.project
@@ -0,0 +1,28 @@
+
+
+ com.windriver.tcf.api
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs b/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..d598b3c83
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#Mon Sep 10 12:26:22 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF b/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..87bb955c3
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.tcf.api
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.tcf.api.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.core.runtime
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.tcf.api.core,
+ com.windriver.tcf.api.protocol,
+ com.windriver.tcf.api.services,
+ com.windriver.tcf.api.util
diff --git a/plugins/com.windriver.tcf.api/about.html b/plugins/com.windriver.tcf.api/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/about.html
@@ -0,0 +1,28 @@
+
+
+
+
+About
+
+
+
About This Content
+
+
January 10, 2008
+
License
+
+
The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+
If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at http://www.eclipse.org.
+
+
+
\ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/build.properties b/plugins/com.windriver.tcf.api/build.properties
new file mode 100644
index 000000000..34d2e4d2d
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/com.windriver.tcf.api/plugin.properties b/plugins/com.windriver.tcf.api/plugin.properties
new file mode 100644
index 000000000..8c23febbe
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 Wind River Systems, Inc. and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Wind River Systems - initial implementation
+###############################################################################
+pluginName = Target Communication Framework (TCF)
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java
new file mode 100644
index 000000000..97ead437f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.tcf.api";
+
+ // The shared instance
+ private static Activator plugin;
+
+ public Activator() {
+ plugin = this;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ Protocol.setEventQueue(new EventQueue());
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Send error message into Eclipse log.
+ * @param msg - error message test
+ * @param err - exception
+ */
+ public static void log(String msg, Throwable err) {
+ if (plugin == null || plugin.getLog() == null) {
+ err.printStackTrace();
+ }
+ else {
+ plugin.getLog().log(new Status(IStatus.ERROR,
+ getDefault().getBundle().getSymbolicName(), IStatus.OK, msg, err));
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java
new file mode 100644
index 000000000..e26cfa100
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api;
+
+public class ErrorCodes {
+
+ public static final int
+ ERR_TERMINATE = 1;
+
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java
new file mode 100644
index 000000000..fec45e8dd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api;
+
+import java.util.LinkedList;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.Job;
+
+import com.windriver.tcf.api.protocol.IEventQueue;
+
+/**
+ * Implementation of Target Communication Framework event queue.
+ * This implementation is intended for Eclipse environment.
+ */
+class EventQueue implements IEventQueue, Runnable {
+
+ private final boolean debug = Platform.inDebugMode();
+ private final LinkedList queue = new LinkedList();
+ private final Thread thread;
+ private boolean waiting;
+ private int job_cnt;
+
+ EventQueue() {
+ thread = new Thread(this);
+ thread.setDaemon(true);
+ thread.setName("TCF Event Dispatch");
+ thread.start();
+ // Need to monitor jobs to detect congestion
+ Job.getJobManager().addJobChangeListener(new IJobChangeListener() {
+
+ public void aboutToRun(IJobChangeEvent event) {
+ job_cnt++;
+ }
+
+ public void awake(IJobChangeEvent event) {
+ //job_cnt++;
+ }
+
+ public void done(IJobChangeEvent event) {
+ job_cnt--;
+ if (Job.getJobManager().isIdle()) job_cnt = 0;
+ }
+
+ public void running(IJobChangeEvent event) {
+ }
+
+ public void scheduled(IJobChangeEvent event) {
+ }
+
+ public void sleeping(IJobChangeEvent event) {
+ //job_cnt--;
+ }
+ });
+ }
+
+ private void error(Throwable x) {
+ if (debug) x.printStackTrace();
+ Activator.log("Unhandled excetion in TCF event dispatch", x);
+ }
+
+ public void run() {
+ for (;;) {
+ try {
+ Runnable r = null;
+ synchronized (this) {
+ while (queue.isEmpty()) {
+ waiting = true;
+ wait();
+ }
+ r = queue.removeFirst();
+ }
+ r.run();
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ }
+
+ public synchronized void invokeLater(final Runnable r) {
+ queue.add(r);
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+
+ public boolean isDispatchThread() {
+ return Thread.currentThread() == thread;
+ }
+
+ public synchronized int getCongestion() {
+ int l0 = job_cnt / 100 - 100;
+ int l1 = queue.size() / 100 - 100;
+ if (l1 > l0) l0 = l1;
+ if (l0 > 100) l0 = 100;
+ return l0;
+ }
+}
\ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java
new file mode 100644
index 000000000..767f8b153
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java
@@ -0,0 +1,796 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api.core;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.DiagnosticsService;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.internal.services.remote.GenericProxy;
+import com.windriver.tcf.api.internal.services.remote.LocatorProxy;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+public abstract class AbstractChannel implements IChannel {
+
+ public interface TraceListener {
+
+ public void onMessageReceived(char type, String token,
+ String service, String name, byte[] data);
+
+ public void onMessageSent(char type, String token,
+ String service, String name, byte[] data);
+
+ public void onChannelClosed(Throwable error);
+ }
+
+ private static class Message {
+ final char type;
+ Token token;
+ String service;
+ String name;
+ byte[] data;
+
+ boolean is_sent;
+ boolean is_canceled;
+
+ Collection trace;
+
+ Message(char type) {
+ this.type = type;
+ }
+
+ public String toString() {
+ try {
+ StringBuffer bf = new StringBuffer();
+ bf.append('[');;
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token.getID());
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append(']');
+ return bf.toString();
+ }
+ catch (Exception x) {
+ return x.toString();
+ }
+ }
+ }
+
+ private static IChannelListener[] listeners_array = new IChannelListener[64];
+
+ private final LinkedList redirect_queue = new LinkedList();
+ private final Map,IService> local_service_by_class = new HashMap,IService>();
+ private final Map,IService> remote_service_by_class = new HashMap,IService>();
+ private final Map local_service_by_name = new HashMap();
+ private final Map remote_service_by_name = new HashMap();
+ private final LinkedList out_queue = new LinkedList();
+ private final Collection channel_listeners = new ArrayList();
+ private final Map event_listeners = new HashMap();
+ private final Map command_servers = new HashMap();
+ private final Map inp_tokens = new HashMap();
+ private final Map out_tokens = new HashMap();
+ private final Thread inp_thread;
+ private final Thread out_thread;
+ private boolean shutdown;
+ private int state = STATE_OPENNING;
+ private IToken redirect_command;
+ private IPeer peer;
+
+ private static final int pending_command_limit = 10;
+ private int local_congestion_level = -100;
+ private int remote_congestion_level = -100;
+ private long local_congestion_time;
+ private int inp_queue_size = 0;
+ private Collection trace_listeners;
+
+ public static final int
+ EOS = -1,
+ EOM = -2;
+
+ protected AbstractChannel(IPeer peer) {
+ assert Protocol.isDispatchThread();
+ assert Protocol.getLocator().getPeers().get(peer.getID()) == peer;
+ this.peer = peer;
+
+ addLocalService(Protocol.getLocator());
+ addLocalService(new DiagnosticsService(this));
+
+ inp_thread = new Thread() {
+
+ byte[] buf = new byte[1024];
+ byte[] eos;
+
+ private void error() throws IOException {
+ throw new IOException("Protocol syntax error");
+ }
+
+ private byte[] readBytes(int end) throws IOException {
+ int len = 0;
+ for (;;) {
+ int n = read();
+ if (n == end) break;
+ if (n < 0) error();
+ if (len >= buf.length) {
+ byte[] tmp = new byte[buf.length * 2];
+ System.arraycopy(buf, 0, tmp, 0, len);
+ buf = tmp;
+ }
+ buf[len++] = (byte)n;
+ }
+ byte[] res = new byte[len];
+ System.arraycopy(buf, 0, res, 0, len);
+ return res;
+ }
+
+ private String readString() throws IOException {
+ return new String(readBytes(0), "UTF8");
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ int n = read();
+ if (n == EOM) continue;
+ if (n == EOS) {
+ eos = readBytes(EOM);
+ break;
+ }
+ final Message msg = new Message((char)n);
+ if (read() != 0) error();
+ switch (msg.type) {
+ case 'C':
+ msg.token = new Token(readBytes(0));
+ msg.service = readString();
+ msg.name = readString();
+ msg.data = readBytes(EOM);
+ break;
+ case 'R':
+ msg.token = new Token(readBytes(0));
+ msg.data = readBytes(EOM);
+ break;
+ case 'E':
+ msg.service = readString();
+ msg.name = readString();
+ msg.data = readBytes(EOM);
+ break;
+ case 'F':
+ msg.data = readBytes(EOM);
+ break;
+ default:
+ error();
+ }
+ long delay = 0;
+ synchronized (out_queue) {
+ inp_queue_size++;
+ if (inp_queue_size > 32) delay = inp_queue_size;
+ }
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ handleInput(msg);
+ }
+ });
+ if (delay > 0) sleep(delay);
+ }
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (out_tokens.isEmpty()) {
+ close();
+ }
+ else {
+ IOException x = new IOException("Connection reset by peer");
+ try {
+ Object[] args = JSON.parseSequence(eos);
+ int error_code = ((Number)args[0]).intValue();
+ if (error_code != 0) {
+ x = new IOException(Command.toErrorString(args[1]));
+ }
+ }
+ catch (IOException e) {
+ x = e;
+ }
+ terminate(x);
+ }
+ }
+ });
+ }
+ catch (final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ terminate(x);
+ }
+ });
+ }
+ }
+ };
+
+ out_thread = new Thread() {
+
+ public void run() {
+ try {
+ while (true) {
+ Message msg = null;
+ boolean last = false;
+ synchronized (out_queue) {
+ while (out_queue.isEmpty()) out_queue.wait();
+ msg = out_queue.removeFirst();
+ if (msg == null) break;
+ last = out_queue.isEmpty();
+ if (msg.is_canceled) {
+ if (last) flush();
+ continue;
+ }
+ msg.is_sent = true;
+ }
+ if (msg.trace != null) {
+ final Message m = msg;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ for (TraceListener l : m.trace) {
+ try {
+ l.onMessageSent(m.type, m.token == null ? null : m.token.getID(),
+ m.service, m.name, m.data);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+ });
+ }
+ write(msg.type);
+ write(0);
+ if (msg.token != null) {
+ write(msg.token.getBytes());
+ write(0);
+ }
+ if (msg.service != null) {
+ write(msg.service.getBytes("UTF8"));
+ write(0);
+ }
+ if (msg.name != null) {
+ write(msg.name.getBytes("UTF8"));
+ write(0);
+ }
+ if (msg.data != null) {
+ write(msg.data);
+ }
+ write(EOM);
+ int delay = 0;
+ int level = remote_congestion_level;
+ if (level > 0) delay = level * 10;
+ if (last || delay > 0) flush();
+ if (delay > 0) sleep(delay);
+ else yield();
+ }
+ write(EOS);
+ flush();
+ }
+ catch (final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ terminate(x);
+ }
+ });
+ }
+ }
+ };
+ inp_thread.setName("TCF Channel Receiver");
+ out_thread.setName("TCF Channel Transmitter");
+
+ try {
+ Object[] args = new Object[]{ local_service_by_name.keySet() };
+ sendEvent(Protocol.getLocator(), "Hello", JSON.toJSONSequence(args));
+ }
+ catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ protected void start() {
+ assert Protocol.isDispatchThread();
+ inp_thread.start();
+ out_thread.start();
+ LocatorService.channelStarted(this);
+ }
+
+ public void redirect(String peer_id) {
+ assert Protocol.isDispatchThread();
+ if (state == STATE_OPENNING) {
+ assert redirect_command == null;
+ redirect_queue.add(peer_id);
+ }
+ else {
+ assert state == STATE_OPEN;
+ state = STATE_OPENNING;
+ try {
+ onLocatorHello(new ArrayList());
+ }
+ catch (Throwable x) {
+ terminate(x);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void onLocatorHello(Collection c) throws IOException {
+ if (state != STATE_OPENNING) throw new IOException("Invalid event: Locator.Hello");
+ remote_service_by_class.clear();
+ String pkg_name = LocatorProxy.class.getPackage().getName();
+ for (Iterator i = c.iterator(); i.hasNext();) {
+ String service_name = i.next();
+ try {
+ Class> cls = Class.forName(pkg_name + "." + service_name + "Proxy");
+ IService service = (IService)cls.getConstructor(IChannel.class).newInstance(this);
+ for (Class> fs : cls.getInterfaces()) {
+ if (fs.equals(IService.class)) continue;
+ if (!IService.class.isAssignableFrom(fs)) continue;
+ remote_service_by_class.put(fs, service);
+ }
+ assert service_name.equals(service.getName());
+ remote_service_by_name.put(service_name, service);
+ }
+ catch (Exception x) {
+ IService service = new GenericProxy(this, service_name);
+ remote_service_by_name.put(service_name, service);
+ }
+ }
+ assert redirect_command == null;
+ if (redirect_queue.size() > 0) {
+ String id = redirect_queue.removeFirst();
+ ILocator l = (ILocator)remote_service_by_class.get(ILocator.NAME);
+ if (l == null) throw new IOException("Peer " + peer.getID() + " has no locator service");
+ peer = l.getPeers().get(id);
+ if (peer == null) throw new IOException("Unknown peer ID: " + id);
+ redirect_command = l.redirect(id, new ILocator.DoneRedirect() {
+ public void doneRedirect(IToken token, Exception x) {
+ assert redirect_command == token;
+ assert state == STATE_OPENNING;
+ redirect_command = null;
+ remote_congestion_level = 0;
+ if (x != null) terminate(x);
+ // Wait for next "Hello"
+ }
+ });
+ }
+ else {
+ state = STATE_OPEN;
+ Transport.channelOpened(this);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ listeners_array = channel_listeners.toArray(listeners_array);
+ for (int i = 0; i < listeners_array.length && listeners_array[i] != null; i++) {
+ listeners_array[i].onChannelOpened();
+ }
+ }
+ });
+ }
+ }
+
+ public final int getState() {
+ return state;
+ }
+
+ public void addChannelListener(IChannelListener listener) {
+ assert Protocol.isDispatchThread();
+ channel_listeners.add(listener);
+ }
+
+ public void removeChannelListener(IChannelListener listener) {
+ assert Protocol.isDispatchThread();
+ channel_listeners.remove(listener);
+ }
+
+ public void addTraceListener(TraceListener listener) {
+ if (trace_listeners == null) {
+ trace_listeners = new ArrayList();
+ }
+ else {
+ trace_listeners = new ArrayList(trace_listeners);
+ }
+ trace_listeners.add(listener);
+ }
+
+ public void removeTraceListener(TraceListener listener) {
+ trace_listeners = new ArrayList(trace_listeners);
+ trace_listeners.remove(listener);
+ if (trace_listeners.isEmpty()) trace_listeners = null;
+ }
+
+ public void addEventListener(IService service, IChannel.IEventListener listener) {
+ assert Protocol.isDispatchThread();
+ IChannel.IEventListener[] list = event_listeners.get(service.getName());
+ IChannel.IEventListener[] next = new IChannel.IEventListener[list == null ? 1 : list.length + 1];
+ if (list != null) System.arraycopy(list, 0, next, 0, list.length);
+ next[next.length - 1] = listener;
+ event_listeners.put(service.getName(), next);
+ }
+
+ public void removeEventListener(IService service, IChannel.IEventListener listener) {
+ assert Protocol.isDispatchThread();
+ IChannel.IEventListener[] list = event_listeners.get(service.getName());
+ for (int i = 0; i < list.length; i++) {
+ if (list[i] == listener) {
+ if (list.length == 1) {
+ event_listeners.remove(service.getName());
+ }
+ else {
+ IChannel.IEventListener[] next = new IChannel.IEventListener[list.length - 1];
+ System.arraycopy(list, 0, next, 0, i - 1);
+ System.arraycopy(list, i + 1, next, i, next.length - i);
+ event_listeners.put(service.getName(), next);
+ }
+ return;
+ }
+ }
+ }
+
+ public void addCommandServer(IService service, IChannel.ICommandServer listener) {
+ assert Protocol.isDispatchThread();
+ if (command_servers.put(service.getName(), listener) != null) {
+ throw new Error("Only one command server per service is allowed");
+ }
+ }
+
+ public void removeCommandServer(IService service, IChannel.ICommandServer listener) {
+ assert Protocol.isDispatchThread();
+ if (command_servers.remove(service.getName()) != listener) {
+ throw new Error("Invalid command server");
+ }
+ }
+
+ private void sendEndOfStream() {
+ if (shutdown) return;
+ shutdown = true;
+ synchronized (out_queue) {
+ out_queue.clear();
+ out_queue.add(0, null);
+ out_queue.notify();
+ }
+ }
+
+ public void close() {
+ assert Protocol.isDispatchThread();
+ try {
+ sendEndOfStream();
+ out_thread.join(10000);
+ stop();
+ inp_thread.join(10000);
+ terminate(null);
+ }
+ catch (Exception x) {
+ terminate(x);
+ }
+ }
+
+ public void terminate(final Throwable error) {
+ assert Protocol.isDispatchThread();
+ sendEndOfStream();
+ if (state == STATE_CLOSED) return;
+ if (error != null) Activator.log("TCF channel terminated", error);
+ state = STATE_CLOSED;
+ Transport.channelClosed(this, error);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (!out_tokens.isEmpty()) {
+ Exception x = null;
+ if (error instanceof Exception) x = (Exception)error;
+ else if (error != null) x = new Exception(error);
+ else x = new IOException("Channel is closed");
+ for (Message msg : out_tokens.values()) {
+ String s = msg.toString();
+ if (s.length() > 72) s = s.substring(0, 72) + "...]";
+ IOException y = new IOException("Command " + s + " aborted");
+ y.initCause(x);
+ msg.token.getListener().terminated(msg.token, y);
+ }
+ out_tokens.clear();
+ }
+ listeners_array = channel_listeners.toArray(listeners_array);
+ for (int i = 0; i < listeners_array.length && listeners_array[i] != null; i++) {
+ listeners_array[i].onChannelClosed(error);
+ }
+ if (trace_listeners != null) {
+ for (TraceListener l : trace_listeners) {
+ try {
+ l.onChannelClosed(error);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public int getCongestion() {
+ assert Protocol.isDispatchThread();
+ int level = out_tokens.size() * 100 / pending_command_limit - 100;
+ if (remote_congestion_level > level) level = remote_congestion_level;
+ if (level > 100) level = 100;
+ return level;
+ }
+
+ public IPeer getLocalPeer() {
+ assert Protocol.isDispatchThread();
+ return LocatorService.getLocalPeer();
+ }
+
+ public IPeer getRemotePeer() {
+ assert Protocol.isDispatchThread();
+ return peer;
+ }
+
+ private void addLocalService(IService service) {
+ for (Class> fs : service.getClass().getInterfaces()) {
+ if (fs.equals(IService.class)) continue;
+ if (!IService.class.isAssignableFrom(fs)) continue;
+ local_service_by_class.put(fs, service);
+ }
+ local_service_by_name.put(service.getName(), service);
+ }
+
+ public Collection getLocalServices() {
+ assert Protocol.isDispatchThread();
+ return local_service_by_name.keySet();
+ }
+
+ public Collection getRemoteServices() {
+ return remote_service_by_name.keySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ public V getLocalService(Class cls) {
+ return (V)local_service_by_class.get(cls);
+ }
+
+ @SuppressWarnings("unchecked")
+ public V getRemoteService(Class cls) {
+ return (V)remote_service_by_class.get(cls);
+ }
+
+ public IService getLocalService(String service_name) {
+ return local_service_by_name.get(service_name);
+ }
+
+ public IService getRemoteService(String service_name) {
+ return remote_service_by_name.get(service_name);
+ }
+
+ private void addToOutQueue(Message msg) {
+ msg.trace = trace_listeners;
+ synchronized (out_queue) {
+ out_queue.add(msg);
+ out_queue.notify();
+ }
+ }
+
+ public IToken sendCommand(IService service, String name, byte[] args, ICommandListener listener) {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) throw new Error("Channel is closed");
+ final Message msg = new Message('C');
+ msg.service = service.getName();
+ msg.name = name;
+ msg.data = args;
+ Token token = new Token(listener) {
+ public boolean cancel() {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) return false;
+ synchronized (out_queue) {
+ if (msg.is_sent) return false;
+ msg.is_canceled = true;
+ }
+ out_tokens.remove(msg.token.getID());
+ return true;
+ }
+ };
+ msg.token = token;
+ out_tokens.put(token.getID(), msg);
+ addToOutQueue(msg);
+ return token;
+ }
+
+ public void sendResult(IToken token, byte[] results) {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) {
+ throw new Error("Channel is closed");
+ }
+ Message msg = new Message('R');
+ msg.data = results;
+ msg.token = (Token)token;
+ inp_tokens.remove(((Token)token).getID());
+ addToOutQueue(msg);
+ }
+
+ public void sendEvent(IService service, String name, byte[] args) {
+ assert Protocol.isDispatchThread();
+ if (!(state == STATE_OPEN || state == STATE_OPENNING && service instanceof ILocator)) {
+ throw new Error("Channel is closed");
+ }
+ Message msg = new Message('E');
+ msg.service = service.getName();
+ msg.name = name;
+ msg.data = args;
+ addToOutQueue(msg);
+ }
+
+ private void handleInput(Message msg) {
+ assert Protocol.isDispatchThread();
+ synchronized (out_queue) {
+ inp_queue_size--;
+ }
+ if (state == STATE_CLOSED) return;
+ if (trace_listeners != null) {
+ for (TraceListener l : trace_listeners) {
+ try {
+ l.onMessageReceived(msg.type,
+ msg.token != null ? msg.token.getID() : null,
+ msg.service, msg.name, msg.data);
+ }
+ catch (Throwable x) {
+ x.printStackTrace();
+ }
+ }
+ }
+ try {
+ Token token = null;
+ IChannel.IEventListener[] list = null;
+ IChannel.ICommandServer cmds = null;
+ switch (msg.type) {
+ case 'C':
+ token = msg.token;
+ inp_tokens.put(token.getID(), msg);
+ cmds = command_servers.get(msg.service);
+ if (cmds != null) {
+ cmds.command(token, msg.name, msg.data);
+ }
+ else {
+ throw new IOException("Unknown command " + msg.service + "." + msg.name);
+ }
+ sendCongestionLevel();
+ break;
+ case 'P':
+ token = out_tokens.get(msg.token.getID()).token;
+ token.getListener().progress(token, msg.data);
+ break;
+ case 'R':
+ token = out_tokens.remove(msg.token.getID()).token;
+ token.getListener().result(token, msg.data);
+ break;
+ case 'E':
+ list = event_listeners.get(msg.service);
+ if (list != null) {
+ for (int i = 0; i < list.length; i++) {
+ list[i].event(msg.name, msg.data);
+ }
+ }
+ sendCongestionLevel();
+ break;
+ case 'F':
+ remote_congestion_level = Integer.parseInt(new String(msg.data, "UTF8"));
+ break;
+ default:
+ assert false;
+ break;
+ }
+ }
+ catch (Throwable x) {
+ terminate(x);
+ }
+ }
+
+ private void sendCongestionLevel() throws IOException {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) return;
+ int level = Protocol.getEventQueue().getCongestion();
+ int n = inp_tokens.size() * 100 / pending_command_limit - 100;
+ if (n > level) level = n;
+ if (level > 100) level = 100;
+ if (level == local_congestion_level) return;
+ long time = System.currentTimeMillis();
+ if (level < local_congestion_level) {
+ if (time - local_congestion_time < 500) return;
+ int i = (local_congestion_level - level) / 4;
+ if (i <= 0) i = 1;
+ local_congestion_level -= i;
+ }
+ else {
+ local_congestion_level = level;
+ }
+ local_congestion_time = time;
+ synchronized (out_queue) {
+ Message msg = out_queue.isEmpty() ? null : out_queue.get(0);
+ if (msg == null || msg.type != 'F') {
+ msg = new Message('F');
+ out_queue.add(0, msg);
+ out_queue.notify();
+ }
+ msg.data = Integer.toString(local_congestion_level).getBytes("UTF8");
+ msg.trace = trace_listeners;
+ }
+ }
+
+ /**
+ * Read one byte from the channel input stream.
+ * @return next data byte or -1 if end of stream is reached.
+ * @throws IOException
+ */
+ protected abstract int read() throws IOException;
+
+ /**
+ * Write one byte into the channel output stream.
+ * The stream can put the byte into a buffer instead of transmitting it right away.
+ * @param n - the data byte.
+ * @throws IOException
+ */
+ protected abstract void write(int n) throws IOException;
+
+ /**
+ * Flush the channel output stream.
+ * All buffered data should be transmitted immediately.
+ * @throws IOException
+ */
+ protected abstract void flush() throws IOException;
+
+ /**
+ * Stop (close) channel underlying streams.
+ * If a thread is blocked by read() or write(), it should be
+ * resumed (or interrupted).
+ * @throws IOException
+ */
+ protected abstract void stop() throws IOException;
+
+ /**
+ * Write array of bytes into the channel output stream.
+ * The stream can put bytes into a buffer instead of transmitting it right away.
+ * @param buf
+ * @throws IOException
+ */
+ protected void write(byte[] buf) throws IOException {
+ assert Thread.currentThread() == out_thread;
+ for (int i = 0; i < buf.length; i++) write(buf[i]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java
new file mode 100644
index 000000000..314d9b03a
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class AbstractPeer implements IPeer {
+
+ private final Map ro_attrs;
+ private final Map rw_attrs;
+
+ public AbstractPeer(Map attrs) {
+ if (attrs != null) {
+ rw_attrs = new HashMap(attrs);
+ }
+ else {
+ rw_attrs = new HashMap();
+ }
+ ro_attrs = new ReadOnlyMap(rw_attrs);
+ assert getID() != null;
+ LocatorService.addPeer(this);
+ }
+
+ protected Map getAttributesStorage() {
+ assert Protocol.isDispatchThread();
+ return rw_attrs;
+ }
+
+ public void dispose() {
+ assert Protocol.isDispatchThread();
+ Transport.peerDisposed(this);
+ LocatorService.removePeer(this);
+ }
+
+ public Map getAttributes() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs;
+ }
+
+ public String getID() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_ID);
+ }
+
+ public String getName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_NAME);
+ }
+
+ public String getOSName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_OS_NAME);
+ }
+
+ public String getTransportName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_TRANSPORT_NAME);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java
new file mode 100644
index 000000000..498104fac
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api.core;
+
+/**
+ * Methods for translating Base64 encoded strings to byte arrays and back.
+ */
+public class Base64 {
+
+ public static char[] toBase64(byte[] buf, int pos, int len) {
+ char[] out_buf = new char[4 * ((len + 2) / 3)];
+ int end = pos + len;
+ int out_pos = 0;
+ while (pos < end) {
+ int byte0 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[byte0 >> 2];
+ if (pos == end) {
+ out_buf[out_pos++] = int2char[(byte0 << 4) & 0x3f];
+ out_buf[out_pos++] = '=';
+ out_buf[out_pos++] = '=';
+ }
+ else {
+ int byte1 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[(byte0 << 4) & 0x3f | (byte1 >> 4)];
+ if (pos == end) {
+ out_buf[out_pos++] = int2char[(byte1 << 2) & 0x3f];
+ out_buf[out_pos++] = '=';
+ }
+ else {
+ int byte2 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[(byte1 << 2) & 0x3f | (byte2 >> 6)];
+ out_buf[out_pos++] = int2char[byte2 & 0x3f];
+ }
+ }
+ }
+ assert out_pos == out_buf.length;
+ return out_buf;
+ }
+
+ public static void toByteArray(byte[] buf, int offs, int size, char[] inp) {
+ int out_pos = offs;
+ if (inp != null) {
+ int inp_len = inp.length;
+ if (inp_len % 4 != 0) {
+ throw new IllegalArgumentException(
+ "BASE64 string length must be a multiple of four.");
+ }
+ int out_len = inp_len / 4 * 3;
+ if (inp_len > 0 && inp[inp_len - 1] == '=') {
+ out_len--;
+ if (inp[inp_len - 2] == '=') {
+ out_len--;
+ }
+ }
+ if (out_len > size) {
+ throw new IllegalArgumentException(
+ "BASE64 data array is longer then destination buffer.");
+ }
+ int inp_pos = 0;
+ while (inp_pos < inp_len) {
+ int n0, n1, n2, n3;
+ char ch0 = inp[inp_pos++];
+ char ch1 = inp[inp_pos++];
+ char ch2 = inp[inp_pos++];
+ char ch3 = inp[inp_pos++];
+ if (ch0 >= char2int.length || (n0 = char2int[ch0]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch0);
+ }
+ if (ch1 >= char2int.length || (n1 = char2int[ch1]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch1);
+ }
+ buf[out_pos++] = (byte)((n0 << 2) | (n1 >> 4));
+ if (ch2 == '=') break;
+ if (ch2 >= char2int.length || (n2 = char2int[ch2]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch2);
+ }
+ buf[out_pos++] = (byte)((n1 << 4) | (n2 >> 2));
+ if (ch3 == '=') break;
+ if (ch3 >= char2int.length || (n3 = char2int[ch3]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch3);
+ }
+ buf[out_pos++] = (byte)((n2 << 6) | n3);
+ }
+ assert out_pos == offs + out_len;
+ }
+ while (out_pos < offs + size) buf[out_pos++] = 0;
+ }
+
+ public static byte[] toByteArray(char[] inp) {
+ int inp_len = inp.length;
+ int out_len = inp_len / 4 * 3;
+ if (inp_len > 0 && inp[inp_len - 1] == '=') {
+ out_len--;
+ if (inp[inp_len - 2] == '=') {
+ out_len--;
+ }
+ }
+ byte[] buf = new byte[out_len];
+ toByteArray(buf, 0, buf.length, inp);
+ return buf;
+ }
+
+ /*
+ * See RFC 2045.
+ */
+ private static final char int2char[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ /*
+ * See RFC 2045
+ */
+ private static final byte char2int[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51
+ };
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java
new file mode 100644
index 000000000..c50a5ad03
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class ChannelTCP extends StreamChannel {
+
+ private Socket socket;
+ private InputStream inp;
+ private OutputStream out;
+ private boolean closed;
+
+ public ChannelTCP(IPeer peer, final String host, final int port) {
+ super(peer);
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ socket = new Socket(host, port);
+ socket.setTcpNoDelay(true);
+ inp = new BufferedInputStream(socket.getInputStream());
+ out = new BufferedOutputStream(socket.getOutputStream());
+ /* Uncomment for testing of buffers.
+ inp = new BufferedInputStream(new FilterInputStream(socket.getInputStream()) {
+ public int read() throws IOException {
+ System.out.println("Inp 1");
+ return in.read();
+ }
+ public int read(byte b[]) throws IOException {
+ int n = in.read(b);
+ System.out.println("Inp " + n);
+ return n;
+ }
+ public int read(byte b[], int off, int len) throws IOException {
+ int n = in.read(b, off, len);
+ System.out.println("Inp " + n);
+ return n;
+ }
+ });
+ out = new BufferedOutputStream(new FilterOutputStream(socket.getOutputStream()){
+ public void write(int b) throws IOException {
+ System.out.println("Out 1");
+ out.write(b);
+ }
+ public void write(byte b[]) throws IOException {
+ System.out.println("Out " + b.length);
+ out.write(b);
+ }
+ public void write(byte b[], int off, int len) throws IOException {
+ System.out.println("Out " + len);
+ out.write(b, off, len);
+ }
+ });
+ */
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ ChannelTCP.this.start();
+ }
+ });
+ }
+ catch (final IOException x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ ChannelTCP.this.terminate(x);
+ }
+ });
+ }
+ }
+ };
+ thread.setName("TCF Socket Connect");
+ thread.start();
+ }
+
+ @Override
+ protected final int get() throws IOException {
+ try {
+ if (closed) return -1;
+ return inp.read();
+ }
+ catch (SocketException x) {
+ if (closed) return -1;
+ throw x;
+ }
+ }
+
+ @Override
+ protected final void put(int b) throws IOException {
+ assert b >= 0 && b <= 0xff;
+ if (closed) return;
+ out.write(b);
+ }
+
+ @Override
+ protected final void flush() throws IOException {
+ if (closed) return;
+ out.flush();
+ }
+
+ @Override
+ protected void stop() throws IOException {
+ closed = true;
+ socket.close();
+ out.close();
+ inp.close();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java
new file mode 100644
index 000000000..d704ba96b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package com.windriver.tcf.api.core;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+
+/**
+ * This is utility class that helps to implement sending a command and receiving
+ * command result over TCF communication channel. The class uses JSON to encode
+ * command arguments and to decode result data. Clients are expected to subclass
+ * Command and override done method.
+ *
+ * Note: most clients don't need to handle protocol commands directly and
+ * can use service APIs instead. Service API does all command encoding/decoding
+ * for a client.
+ *
+ * Typical usage example:
+ *
+ * public IToken getContext(String id, final DoneGetContext done) {
+ * return new Command(channel, IService.this, "getContext", new Object[]{ id }) {
+ * @Override
+ * public void done(Exception error, Object[] args) {
+ * Context ctx = null;
+ * if (error == null) {
+ * assert args.length == 3;
+ * error = JSON.toError(args[0], args[1]);
+ * if (args[2] != null) ctx = new Context(args[2]);
+ * }
+ * done.doneGetContext(token, error, ctx);
+ * }
+ * }.token;
+ * }
+ */
+public abstract class Command implements IChannel.ICommandListener {
+
+ private final IService service;
+ private final String command;
+ private final Object[] args;
+
+ public final IToken token;
+
+ private boolean done;
+
+ public Command(IChannel channel, IService service, String command, Object[] args) {
+ this.service = service;
+ this.command = command;
+ this.args = args;
+ IToken t = null;
+ try {
+ t = channel.sendCommand(service, command, JSON.toJSONSequence(args), this);
+ }
+ catch (Throwable y) {
+ t = new Token();
+ final Exception x = y instanceof Exception ? (Exception)y : new Exception(y);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ assert !done;
+ done = true;
+ done(x, null);
+ }
+ });
+ }
+ token = t;
+ }
+
+ public void progress(IToken token, byte[] data) {
+ assert this.token == token;
+ }
+
+ public void result(IToken token, byte[] data) {
+ assert this.token == token;
+ Exception error = null;
+ Object[] args = null;
+ try {
+ args = JSON.parseSequence(data);
+ }
+ catch (Exception e) {
+ error = e;
+ }
+ assert !done;
+ done = true;
+ done(error, args);
+ }
+
+ public void terminated(IToken token, Exception error) {
+ assert this.token == token;
+ assert !done;
+ done = true;
+ done(error, null);
+ }
+
+ public abstract void done(Exception error, Object[] args);
+
+ public String getCommandString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(service.getName());
+ buf.append(' ');
+ buf.append(command);
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) {
+ buf.append(i == 0 ? " " : ", ");
+ try {
+ buf.append(JSON.toJSON(args[i]));
+ }
+ catch (IOException x) {
+ buf.append("***");
+ buf.append(x.getMessage());
+ buf.append("***");
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String toErrorString(Object data) {
+ if (data instanceof String) {
+ return (String)data;
+ }
+ else if (data != null) {
+ Map map = (Map)data;
+ Collection