Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/com.windriver.tcf.api/src/com/windriver')
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java70
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java18
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java110
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java796
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java74
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java146
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java123
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java157
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java66
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java90
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java37
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java111
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java96
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java65
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java69
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java116
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java103
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java368
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java198
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java158
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java582
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java39
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java79
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java161
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java366
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java232
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java278
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java264
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java123
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java204
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java261
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java47
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java70
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java25
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java29
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java516
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java193
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java162
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java65
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java696
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java73
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java99
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java247
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java202
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java318
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java323
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java140
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java378
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java246
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java150
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java117
51 files changed, 9656 insertions, 0 deletions
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<Runnable> queue = new LinkedList<Runnable>();
+ 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<TraceListener> 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<String> redirect_queue = new LinkedList<String>();
+ private final Map<Class<?>,IService> local_service_by_class = new HashMap<Class<?>,IService>();
+ private final Map<Class<?>,IService> remote_service_by_class = new HashMap<Class<?>,IService>();
+ private final Map<String,IService> local_service_by_name = new HashMap<String,IService>();
+ private final Map<String,IService> remote_service_by_name = new HashMap<String,IService>();
+ private final LinkedList<Message> out_queue = new LinkedList<Message>();
+ private final Collection<IChannelListener> channel_listeners = new ArrayList<IChannelListener>();
+ private final Map<String,IChannel.IEventListener[]> event_listeners = new HashMap<String,IChannel.IEventListener[]>();
+ private final Map<String,IChannel.ICommandServer> command_servers = new HashMap<String,IChannel.ICommandServer>();
+ private final Map<String,Message> inp_tokens = new HashMap<String,Message>();
+ private final Map<String,Message> out_tokens = new HashMap<String,Message>();
+ 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<TraceListener> 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<String>());
+ }
+ catch (Throwable x) {
+ terminate(x);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void onLocatorHello(Collection<String> 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<String> 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<TraceListener>();
+ }
+ else {
+ trace_listeners = new ArrayList<TraceListener>(trace_listeners);
+ }
+ trace_listeners.add(listener);
+ }
+
+ public void removeTraceListener(TraceListener listener) {
+ trace_listeners = new ArrayList<TraceListener>(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<String> getLocalServices() {
+ assert Protocol.isDispatchThread();
+ return local_service_by_name.keySet();
+ }
+
+ public Collection<String> getRemoteServices() {
+ return remote_service_by_name.keySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <V extends IService> V getLocalService(Class<V> cls) {
+ return (V)local_service_by_class.get(cls);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <V extends IService> V getRemoteService(Class<V> 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<String, String> ro_attrs;
+ private final Map<String, String> rw_attrs;
+
+ public AbstractPeer(Map<String, String> attrs) {
+ if (attrs != null) {
+ rw_attrs = new HashMap<String, String>(attrs);
+ }
+ else {
+ rw_attrs = new HashMap<String, String>();
+ }
+ ro_attrs = new ReadOnlyMap<String, String>(rw_attrs);
+ assert getID() != null;
+ LocatorService.addPeer(this);
+ }
+
+ protected Map<String, String> getAttributesStorage() {
+ assert Protocol.isDispatchThread();
+ return rw_attrs;
+ }
+
+ public void dispose() {
+ assert Protocol.isDispatchThread();
+ Transport.peerDisposed(this);
+ LocatorService.removePeer(this);
+ }
+
+ public Map<String, String> 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
+ * <code>Command</code> and override <code>done</code> 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<String,Object> map = (Map<String,Object>)data;
+ Collection<Object> c = (Collection<Object>)map.get("params");
+ return new MessageFormat((String)map.get("format")).format(c.toArray());
+ }
+ return null;
+ }
+
+ public Exception toError(Object code, Object data) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "...";
+ return new Exception(
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java
new file mode 100644
index 000000000..a6b871740
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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 com.windriver.tcf.api.protocol.IPeer;
+
+public abstract class StreamChannel extends AbstractChannel {
+
+ public static final int ESC = 3;
+
+ public StreamChannel(IPeer peer) {
+ super(peer);
+ }
+
+ protected abstract int get() throws IOException;
+ protected abstract void put(int n) throws IOException;
+
+ @Override
+ protected final int read() throws IOException {
+ int res = get();
+ if (res < 0) return EOS;
+ assert res >= 0 && res <= 0xff;
+ if (res != ESC) return res;
+ int n = get();
+ switch (n) {
+ case 0: return ESC;
+ case 1: return EOM;
+ case 2: return EOS;
+ default:
+ if (n < 0) return EOS;
+ assert false;
+ return 0;
+ }
+ }
+
+ @Override
+ protected final void write(int n) throws IOException {
+ switch (n) {
+ case ESC: put(ESC); put(0); break;
+ case EOM: put(ESC); put(1); break;
+ case EOS: put(ESC); put(2); break;
+ default:
+ assert n >= 0 && n <= 0xff;
+ put(n);
+ }
+ }
+
+ @Override
+ protected void write(byte[] buf) throws IOException {
+ for (int i = 0; i < buf.length; i++) {
+ int n = buf[i] & 0xff;
+ put(n);
+ if (n == ESC) put(0);
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java
new file mode 100644
index 000000000..1bb1cd141
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import com.windriver.tcf.api.core.StreamChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+
+public class ChannelLoop extends StreamChannel {
+
+ private final byte[] buf = new byte[0x1000];
+ private int buf_inp;
+ private int buf_out;
+ private boolean waiting;
+ private boolean closed;
+
+ ChannelLoop(IPeer peer) {
+ super(peer);
+ start();
+ }
+
+ @Override
+ protected synchronized int get() throws IOException {
+ try {
+ while (buf_inp == buf_out) {
+ if (closed) return -1;
+ waiting = true;
+ wait();
+ }
+ int b = buf[buf_out] & 0xff;
+ buf_out = (buf_out + 1) % buf.length;
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ return b;
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+
+ @Override
+ protected synchronized void put(int b) throws IOException {
+ assert b >=0 && b <= 0xff;
+ try {
+ for (;;) {
+ int nxt_inp = (buf_inp + 1) % buf.length;
+ if (nxt_inp != buf_out) {
+ buf[buf_inp] = (byte)b;
+ buf_inp = nxt_inp;
+ break;
+ }
+ if (closed) return;
+ waiting = true;
+ wait();
+ }
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+
+ @Override
+ protected void flush() throws IOException {
+ }
+
+ @Override
+ protected synchronized void stop() throws IOException {
+ closed = true;
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java
new file mode 100644
index 000000000..9300e3ad4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.protocol.IChannel;
+
+public class LocalPeer extends AbstractPeer {
+
+ private static Map<String, String> createAttributes() {
+ Map<String, String> attrs = new HashMap<String, String>();
+ attrs.put(ATTR_ID, "TCFLocal");
+ attrs.put(ATTR_NAME, "Local Peer");
+ attrs.put(ATTR_OS_NAME, System.getProperty("os.name"));
+ attrs.put(ATTR_TRANSPORT_NAME, "Loop");
+ return attrs;
+ }
+
+ public LocalPeer() {
+ super(createAttributes());
+ }
+
+ public IChannel openChannel() {
+ return new ChannelLoop(this);
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java
new file mode 100644
index 000000000..cc8aeb422
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+public class ReadOnlyCollection<E> implements Set<E> {
+
+ private final Collection<E> base;
+
+ public ReadOnlyCollection(Collection<E> base) {
+ this.base = base;
+ }
+
+ private void error() {
+ throw new Error("Read only Collection");
+ }
+
+ public boolean add(E e) {
+ error();
+ return false;
+ }
+
+ public boolean addAll(Collection<? extends E> c) {
+ error();
+ return false;
+ }
+
+ public void clear() {
+ error();
+ }
+
+ public boolean contains(Object o) {
+ return base.contains(o);
+ }
+
+ public boolean containsAll(Collection<?> c) {
+ return base.containsAll(c);
+ }
+
+ public boolean isEmpty() {
+ return base.isEmpty();
+ }
+
+ public Iterator<E> iterator() {
+ final Iterator<E> iterator = base.iterator();
+ return new Iterator<E>() {
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public E next() {
+ return iterator.next();
+ }
+
+ public void remove() {
+ error();
+ }
+ };
+ }
+
+ public boolean remove(Object o) {
+ error();
+ return false;
+ }
+
+ public boolean removeAll(Collection<?> c) {
+ error();
+ return false;
+ }
+
+ public boolean retainAll(Collection<?> c) {
+ error();
+ return false;
+ }
+
+ public int size() {
+ return base.size();
+ }
+
+ public Object[] toArray() {
+ return base.toArray();
+ }
+
+ public <T> T[] toArray(T[] a) {
+ return base.toArray(a);
+ }
+
+ public boolean equals(Object o) {
+ return base.equals(o);
+ }
+
+ public int hashCode() {
+ return base.hashCode();
+ }
+
+ public String toString() {
+ return base.toString();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java
new file mode 100644
index 000000000..458d27f72
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+public class ReadOnlyMap<K,V> implements Map<K,V> {
+
+ private final Map<K,V> base;
+ private Set<K> key_set;
+ private Set<Map.Entry<K, V>> entry_set;
+ private Collection<V> values;
+
+ public ReadOnlyMap(Map<K,V> base) {
+ this.base = base;
+ }
+
+ private void error() {
+ throw new Error("Read only Map");
+ }
+
+ public void clear() {
+ error();
+ }
+
+ public boolean containsKey(Object key) {
+ return base.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return base.containsValue(value);
+ }
+
+ public Set<Map.Entry<K, V>> entrySet() {
+ if (entry_set == null) entry_set = new ReadOnlyCollection<Map.Entry<K, V>>(base.entrySet());
+ return entry_set;
+ }
+
+ public V get(Object key) {
+ return base.get(key);
+ }
+
+ public boolean isEmpty() {
+ return base.isEmpty();
+ }
+
+ public Set<K> keySet() {
+ if (key_set == null) key_set = new ReadOnlyCollection<K>(base.keySet());
+ return key_set;
+ }
+
+ public V put(K key, V value) {
+ error();
+ return null;
+ }
+
+ public void putAll(Map<? extends K, ? extends V> m) {
+ error();
+ }
+
+ public V remove(Object key) {
+ error();
+ return null;
+ }
+
+ public int size() {
+ return base.size();
+ }
+
+ public Collection<V> values() {
+ if (values == null) values = new ReadOnlyCollection<V>(base.values());
+ return values;
+ }
+
+ public boolean equals(Object o) {
+ return base.equals(o);
+ }
+
+ public int hashCode() {
+ return base.hashCode();
+ }
+
+ public String toString() {
+ return base.toString();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java
new file mode 100644
index 000000000..fa4c93eef
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.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.tcf.api.internal.core;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.core.ChannelTCP;
+import com.windriver.tcf.api.protocol.IChannel;
+
+public class RemotePeer extends AbstractPeer {
+
+ public RemotePeer(Map<String,String> attrs) {
+ super(attrs);
+ }
+
+ public boolean updateAttributes(Map<String,String> attrs1) {
+ boolean equ = true;
+ Map<String,String> attrs0 = getAttributesStorage();
+ assert attrs1.get(ATTR_ID).equals(attrs0.get(ATTR_ID));
+ for (Iterator<String> i = attrs0.keySet().iterator(); i.hasNext();) {
+ String key = i.next();
+ if (!attrs0.get(key).equals(attrs1.get(key))) {
+ equ = false;
+ break;
+ }
+ }
+ for (Iterator<String> i = attrs1.keySet().iterator(); i.hasNext();) {
+ String key = i.next();
+ if (!attrs1.get(key).equals(attrs0.get(key))) {
+ equ = false;
+ break;
+ }
+ }
+ if (!equ) {
+ attrs0.clear();
+ attrs0.putAll(attrs1);
+ }
+ return !equ;
+ }
+
+ public IChannel openChannel() {
+ String transport = getTransportName();
+ if (transport.equals("TCP")) {
+ Map<String,String> attrs = getAttributes();
+ String host = attrs.get(ATTR_IP_HOST);
+ String port = attrs.get(ATTR_IP_PORT);
+ if (host == null) throw new Error("No host name");
+ if (port == null) throw new Error("No port number");
+ return new ChannelTCP(this, host, Integer.parseInt(port));
+ }
+ else {
+ throw new Error("Unknow transport name: " + transport);
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java
new file mode 100644
index 000000000..9892b9cbd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.io.UnsupportedEncodingException;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+
+public class Token implements IToken {
+
+ private static int cnt = 0;
+
+ private final String id;
+ private final byte[] bytes;
+ private final IChannel.ICommandListener listener;
+
+ public Token() {
+ id = null;
+ bytes = null;
+ listener = null;
+ }
+
+ public Token(IChannel.ICommandListener listener) {
+ this.listener = listener;
+ id = Integer.toString(cnt++);
+ try {
+ bytes = id.getBytes("ASCII");
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public Token(byte[] bytes) {
+ this.bytes = bytes;
+ listener = null;
+ try {
+ id = new String(bytes, "ASCII");
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public boolean cancel() {
+ return false;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public IChannel.ICommandListener getListener() {
+ return listener;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java
new file mode 100644
index 000000000..3e2d1840e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.internal.core;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.core.AbstractChannel;
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ILocator;
+
+public class Transport {
+
+ private static final Collection<AbstractChannel> channels =
+ new LinkedList<AbstractChannel>();
+ private static final Collection<Protocol.ChannelOpenListener> listeners =
+ new LinkedList<Protocol.ChannelOpenListener>();
+
+ public static void channelOpened(final AbstractChannel channel) {
+ channels.add(channel);
+ for (Protocol.ChannelOpenListener l : listeners) {
+ try {
+ l.onChannelOpen(channel);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+
+ public static void channelClosed(final AbstractChannel channel, final Throwable x) {
+ channels.remove(channel);
+ }
+
+ public static IChannel[] getOpenChannels() {
+ return channels.toArray(new IChannel[channels.size()]);
+ }
+
+ public static void addChanalOpenListener(Protocol.ChannelOpenListener listener) {
+ listeners.add(listener);
+ }
+
+ public static void removeChanalOpenListener(Protocol.ChannelOpenListener listener) {
+ listeners.remove(listener);
+ }
+
+ public static void peerDisposed(AbstractPeer peer) {
+ Collection<AbstractChannel> bf = new ArrayList<AbstractChannel>(channels);
+ for (Iterator<AbstractChannel> i = bf.iterator(); i.hasNext();) {
+ AbstractChannel c = i.next();
+ if (c.getRemotePeer() != peer) continue;
+ c.close();
+ }
+ }
+
+ /**
+ * Transmit TCF event message.
+ * The message is sent to all open communication channels – broadcasted.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ public static void sendEvent(String service_name, String event_name, byte[] data) {
+ for (Iterator<AbstractChannel> i = channels.iterator(); i.hasNext();) {
+ AbstractChannel channel = i.next();
+ IService s = channel.getRemoteService(service_name);
+ if (s != null) channel.sendEvent(s, event_name, data);
+ }
+ }
+
+ /**
+ * Call back after TCF messages sent by this host up to this moment are delivered
+ * to their intended targets. This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need cross channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ public static void sync(final Runnable done) {
+ final Set<IToken> set = new HashSet<IToken>();
+ ILocator.DoneSync done_sync = new ILocator.DoneSync() {
+ public void doneSync(IToken token) {
+ assert set.contains(token);
+ set.remove(token);
+ if (set.isEmpty()) done.run();
+ }
+ };
+ for (Iterator<AbstractChannel> i = channels.iterator(); i.hasNext();) {
+ AbstractChannel channel = i.next();
+ ILocator s = channel.getRemoteService(ILocator.class);
+ if (s != null) set.add(s.sync(done_sync));
+ }
+ if (set.isEmpty()) Protocol.invokeLater(done);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java
new file mode 100644
index 000000000..88ad937bb
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.internal.services.local;
+
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.protocol.IChannel;
+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.IDiagnostics;
+
+public class DiagnosticsService implements IDiagnostics {
+
+ private final IChannel channel;
+
+ private class CommandServer implements IChannel.ICommandServer {
+
+ public void command(IToken token, String name, byte[] data) {
+ try {
+ if (name.equals("echo")) {
+ channel.sendResult(token, data);
+ }
+ else if (name.equals("getTestList")) {
+ channel.sendResult(token, JSON.toJSONSequence(new Object[]{
+ new Integer(0), null, new String[0]}));
+ }
+ else {
+ channel.terminate(new Exception("Illegal command: " + name));
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ }
+
+ public DiagnosticsService(IChannel channel) {
+ this.channel = channel;
+ channel.addCommandServer(this, new CommandServer());
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken echo(final String s, final DoneEcho done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneEcho(token, null, s);
+ }
+ });
+ return token;
+ }
+
+ public IToken getTestList(final DoneGetTestList done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneGetTestList(token, null, new String[0]);
+ }
+ });
+ return token;
+ }
+
+ public IToken runTest(final String s, final DoneRunTest done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneRunTest(token, new Exception("Test suite not found: " + s), null);
+ }
+ });
+ return token;
+ }
+
+ public IToken cancelTest(String context_id, final DoneCancelTest done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneCancelTest(token, null);
+ }
+ });
+ return token;
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, final DoneGetSymbol done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneGetSymbol(token, new Exception("Invalid context"), null);
+ }
+ });
+ return token;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java
new file mode 100644
index 000000000..9672433ea
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * 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.internal.services.local;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.core.AbstractChannel;
+import com.windriver.tcf.api.internal.core.LocalPeer;
+import com.windriver.tcf.api.internal.core.RemotePeer;
+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.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ * Locator service uses transport layer to search
+ * for peers and to collect and maintain up-to-date
+ * data about peer’s attributes and capabilities (services).
+ */
+public class LocatorService implements ILocator {
+
+ private static LocatorService locator;
+ private static final Map<String,IPeer> peers = new HashMap<String,IPeer>();
+ private static final Collection<LocatorListener> listeners = new ArrayList<LocatorListener>();
+
+ private static LocalPeer local_peer;
+
+ private DatagramSocket socket;
+
+ private Thread output_thread = new Thread() {
+ public void run() {
+ for (;;) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ sendPeerInfoRequest();
+ }
+ });
+ try {
+ sleep(5 * 1000);
+ }
+ catch (InterruptedException x) {
+ break;
+ }
+ }
+ }
+ };
+
+ private Thread input_thread = new Thread() {
+ public void run() {
+ for (;;) {
+ try {
+ byte[] buf = new byte[0x1000];
+ final DatagramPacket p = new DatagramPacket(buf, buf.length);
+ socket.receive(p);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ handleDatagramPacket(p);
+ }
+ });
+ }
+ catch (Exception x) {
+ Activator.log("Cannot read from datagram socket", x);
+ break;
+ }
+ }
+ }
+ };
+
+ public LocatorService() {
+ locator = this;
+ try {
+ socket = new DatagramSocket();
+ socket.setBroadcast(true);
+ input_thread.setName("TCF Locator Receiver");
+ output_thread.setName("TCF Locator Transmitter");
+ input_thread.start();
+ output_thread.start();
+ }
+ catch (Exception x) {
+ Activator.log("Cannot create datagram socket", x);
+ }
+ }
+
+ public static LocalPeer getLocalPeer() {
+ return local_peer;
+ }
+
+ public static void addPeer(IPeer peer) {
+ assert peers.get(peer.getID()) == null;
+ if (peer instanceof LocalPeer) local_peer = (LocalPeer)peer;
+ peers.put(peer.getID(), peer);
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerAdded(peer);
+ }
+ }
+
+ public static void removePeer(IPeer peer) {
+ assert peers.get(peer.getID()) == peer;
+ peers.remove(peer);
+ String id = peer.getID();
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerRemoved(id);
+ }
+ }
+
+ private void notifyPeer(IPeer peer) {
+ assert peers.get(peer.getID()) == peer;
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerChanged(peer);
+ }
+ }
+
+ public static void channelStarted(final AbstractChannel channel) {
+ channel.addEventListener(locator, new IChannel.IEventListener() {
+ public void event(String name, byte[] data) {
+ locator.event(channel, name, data);
+ }
+ });
+ channel.addCommandServer(locator, new IChannel.ICommandServer() {
+ public void command(IToken token, String name, byte[] data) {
+ locator.command(channel, token, name, data);
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ private void event(AbstractChannel channel, String name, byte[] data) {
+ try {
+ if (name.equals("Hello")) {
+ Collection<String> c = (Collection<String>)JSON.parseSequence(data)[0];
+ channel.onLocatorHello(c);
+ }
+ else {
+ throw new IOException("Unknown event: Locator." + name);
+ }
+ }
+ catch (IOException e) {
+ channel.terminate(e);
+ }
+ }
+
+ private void command(AbstractChannel channel, IToken token, String name, byte[] data) {
+ try {
+ if (name.equals("redirect")) {
+ // String peer_id = (String)JSON.parseSequence(data)[0];
+ // TODO: perform local ILocator.redirect
+ channel.sendResult(token, JSON.toJSONSequence(new Object[]{
+ new Integer(0), null }));
+ }
+ else if (name.equals("sync")) {
+ channel.sendResult(token, null);
+ }
+ else {
+ channel.terminate(new Exception("Illegal command: " + name));
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+
+ private void sendPeerInfoRequest() {
+ try {
+ byte[] buf = new byte[8];
+ int i = 0;
+ buf[i++] = 'T';
+ buf[i++] = 'C';
+ buf[i++] = 'F';
+ buf[i++] = '1';
+ buf[i++] = CONF_REQ_INFO;
+ buf[i++] = 0;
+ buf[i++] = 0;
+ buf[i++] = 0;
+ for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) {
+ NetworkInterface f = e.nextElement();
+ /* TODO: Class InterfaceAddress does not exists in Java versions before 1.6.
+ * When support for old Java versions is not needed any more,
+ * the code below should be replaced with:
+ * for (InterfaceAddress ia : f.getInterfaceAddresses()) {
+ * socket.send(new DatagramPacket(buf, buf.length, ia.getBroadcast(), 1534));
+ * }
+ */
+ Enumeration<InetAddress> n = f.getInetAddresses();
+ while (n.hasMoreElements()) {
+ InetAddress ina = n.nextElement();
+ byte[] adr = ina.getAddress();
+ if (adr.length != 4) {
+ // TODO: Support IPv6
+ // System.out.println("Dont support IPv6: " + ina);
+ continue;
+ }
+ /* Since we don't know actual broadcast address,
+ * lets try different combinations.
+ * Hopefully one of them will work.
+ */
+ int h = adr[0] & 0xff;
+ if (h >= 1 && h <= 127 && h != 38) {
+ adr[3] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[2] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[1] = (byte)255;
+ }
+ else if (h >= 128 && h <= 191) {
+ adr[3] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[2] = (byte)255;
+ }
+ else {
+ adr[3] = (byte)(adr[3] | 0x0f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x01f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x03f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x07f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)255;
+ }
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ }
+ }
+ }
+ catch (Exception x) {
+ Activator.log("Cannot send datagram packet", x);
+ }
+ }
+
+ private void handleDatagramPacket(DatagramPacket p) {
+ try {
+ byte[] buf = p.getData();
+ int len = p.getLength();
+ if (len < 8) return;
+ if (buf[0] != 'T') return;
+ if (buf[1] != 'C') return;
+ if (buf[2] != 'F') return;
+ if (buf[3] != '1') return;
+ switch (buf[4]) {
+ case CONF_PEER_INFO:
+ handlePeerInfoPacket(p);
+ break;
+ case CONF_REQ_INFO:
+ handleReqInfoPacket(p);
+ break;
+ }
+ }
+ catch (Throwable x) {
+ Activator.log("Invalid datagram packet received", x);
+ }
+ }
+
+ private void handlePeerInfoPacket(DatagramPacket p) throws Exception {
+ Map<String,String> map = new HashMap<String,String>();
+ String s = new String(p.getData(), 8, p.getLength() - 8, "UTF8");
+ int len = s.length();
+ int i = 0;
+ while (i < len) {
+ int i0 = i;
+ while (i < len && s.charAt(i) != '=' && s.charAt(i) != 0) i++;
+ int i1 = i;
+ if (i < len && s.charAt(i) == '=') i++;
+ int i2 = i;
+ while (i < len && s.charAt(i) != 0) i++;
+ int i3 = i;
+ if (i < len && s.charAt(i) == 0) i++;
+ String key = s.substring(i0, i1);
+ String val = s.substring(i2, i3);
+ map.put(key, val);
+ }
+ String id = map.get(IPeer.ATTR_ID);
+ if (id == null) throw new Exception("Invalid peer info: no ID");
+ IPeer peer = peers.get(id);
+ if (peer instanceof RemotePeer) {
+ if (((RemotePeer)peer).updateAttributes(map)) {
+ notifyPeer(peer);
+ }
+ }
+ else {
+ new RemotePeer(map);
+ }
+ }
+
+ private void handleReqInfoPacket(DatagramPacket p) {
+ byte[] buf = p.getData();
+ int len = p.getLength();
+ // TODO: handleReqInfoPacket()
+ }
+
+ /*----------------------------------------------------------------------------------*/
+
+ /*
+ * Return local instance of Locator service
+ */
+ public static LocatorService getLocator() {
+ return locator;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#getName()
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#getPeers()
+ */
+ public Map<String,IPeer> getPeers() {
+ return peers;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#redirect()
+ */
+ public IToken redirect(String peer_id, DoneRedirect done) {
+ throw new Error("Channel redirect cannot be done on local peer");
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#sync()
+ */
+ public IToken sync(DoneSync done) {
+ throw new Error("Channel sync cannot be done on local peer");
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#addListener(com.windriver.tcf.api.protocol.ILocator.Listener)
+ */
+ public void addListener(LocatorListener listener) {
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#removeListener(com.windriver.tcf.api.protocol.ILocator.Listener)
+ */
+ public void removeListener(LocatorListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java
new file mode 100644
index 000000000..475ff79fe
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class BreakpointsProxy implements IBreakpoints {
+
+ private final IChannel channel;
+ private final Map<BreakpointsListener,IChannel.IEventListener> listeners =
+ new HashMap<BreakpointsListener,IChannel.IEventListener>();
+
+ public BreakpointsProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken set(Map<String, Object>[] properties, final DoneCommand done) {
+ return new Command(channel, this, "set", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken add(Map<String, Object> properties, final DoneCommand done) {
+ return new Command(channel, this, "add", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken change(Map<String, Object> properties, final DoneCommand done) {
+ return new Command(channel, this, "change", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken disable(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "disable", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken enable(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "enable", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken remove(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "remove", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken getIDs(final DoneGetIDs done) {
+ return new Command(channel, this, "getIDs", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetIDs(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getProperties(String id, final DoneGetProperties done) {
+ return new Command(channel, this, "getProperties", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ map = (Map<String,Object>)args[2];
+ }
+ done.doneGetProperties(token, error, map);
+ }
+ }.token;
+ }
+
+ public IToken getStatus(String id, final DoneGetStatus done) {
+ return new Command(channel, this, "getStatus", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ map = (Map<String,Object>)args[2];
+ }
+ done.doneGetStatus(token, error, map);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ public void addListener(final BreakpointsListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("status")) {
+ assert args.length == 2;
+ listener.breakpointStatusChanged((String)args[0], (Map<String,Object>)args[1]);
+ }
+ else {
+ throw new IOException("Breakpoints service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(BreakpointsListener listener) {
+ IChannel.IEventListener l = listeners.get(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java
new file mode 100644
index 000000000..cafcb845e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IDiagnostics;
+
+public class DiagnosticsProxy implements IDiagnostics {
+
+ private final IChannel channel;
+
+ private static class Symbol implements ISymbol {
+
+ private final Map<String,Object> props;
+
+ Symbol(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String getSectionName() {
+ return (String)props.get("Section");
+ }
+
+ public Number getValue() {
+ return (Number)props.get("Value");
+ }
+
+ public boolean isAbs() {
+ Boolean b = (Boolean)props.get("Abs");
+ return b != null && b.booleanValue();
+ }
+
+ public boolean isCommon() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("COMMON");
+ }
+
+ public boolean isGlobal() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("GLOBAL");
+ }
+
+ public boolean isLocal() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("LOCAL");
+ }
+
+ public boolean isUndef() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("UNDEF");
+ }
+ }
+
+ public DiagnosticsProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken echo(String s, final DoneEcho done) {
+ return new Command(channel, this, "echo", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String str = null;
+ if (error == null) {
+ assert args.length == 1;
+ str = (String)args[0];
+ }
+ done.doneEcho(token, error, str);
+ }
+ }.token;
+ }
+
+ public IToken getTestList(final DoneGetTestList done) {
+ return new Command(channel, this, "getTestList", null) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetTestList(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken runTest(String s, final DoneRunTest done) {
+ return new Command(channel, this, "runTest", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String str = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ str = (String)args[2];
+ }
+ done.doneRunTest(token, error, str);
+ }
+ }.token;
+ }
+
+ public IToken cancelTest(String s, final DoneCancelTest done) {
+ return new Command(channel, this, "cancelTest", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCancelTest(token, error);
+ }
+ }.token;
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, final DoneGetSymbol done) {
+ return new Command(channel, this, "getSymbol", new Object[]{ context_id, symbol_name }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ ISymbol sym = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ sym = toSymbol(args[2]);
+ }
+ done.doneGetSymbol(token, error, sym);
+ }
+ }.token;
+ }
+
+ private String[] toStringArray(Collection<String> c) {
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ @SuppressWarnings("unchecked")
+ private ISymbol toSymbol(Object o) {
+ if (o == null) return null;
+ return new Symbol((Map<String,Object>)o);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java
new file mode 100644
index 000000000..38d8678ef
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Base64;
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IFileSystem;
+
+public class FileSystemProxy implements IFileSystem {
+
+ private final class FileHandle implements IFileHandle {
+ final String id;
+
+ FileHandle(String id) {
+ this.id = id;
+ }
+
+ public IFileSystem getService() {
+ return FileSystemProxy.this;
+ }
+
+ public String toString() {
+ return "[File Handle '" + id + "']";
+ }
+ }
+
+ private static final class Status extends FileSystemException {
+
+ private static final long serialVersionUID = -1636567076145085980L;
+
+ private final int status;
+
+ Status(int status, String message) {
+ super(message);
+ this.status = status;
+ }
+
+ Status(Exception x) {
+ super(x);
+ this.status = STATUS_FAILURE;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+ }
+
+ private abstract class FileSystemCommand extends Command {
+
+ FileSystemCommand(String command, Object[] args) {
+ super(channel, FileSystemProxy.this, command, args);
+ }
+
+ public Status toFSError(Object code, Object data) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 32) cmd = cmd.substring(0, 32) + "...";
+ return new Status(error_code,
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code);
+ }
+ }
+
+ private final IChannel channel;
+
+ public FileSystemProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken close(IFileHandle handle, final DoneClose done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("close", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneClose(token, s);
+ }
+ }.token;
+ }
+
+ public IToken setstat(String path, FileAttrs attrs, final DoneSetStat done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("setstat", new Object[]{ path, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSetStat(token, s);
+ }
+ }.token;
+ }
+
+ public IToken fsetstat(IFileHandle handle, FileAttrs attrs, final DoneSetStat done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("fsetstat", new Object[]{ id, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSetStat(token, s);
+ }
+ }.token;
+ }
+
+ public IToken stat(String path, final DoneStat done) {
+ return new FileSystemCommand("stat", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken fstat(IFileHandle handle, final DoneStat done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("fstat", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken lstat(String path, final DoneStat done) {
+ return new FileSystemCommand("lstat", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken mkdir(String path, FileAttrs attrs, final DoneMkDir done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("mkdir", new Object[]{ path, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneMkDir(token, s);
+ }
+ }.token;
+ }
+
+ public IToken open(String file_name, int flags, FileAttrs attrs, final DoneOpen done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("open", new Object[]{ file_name, new Integer(flags), dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileHandle h = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ h = toFileHandle(args[2]);
+ }
+ }
+ done.doneOpen(token, s, h);
+ }
+ }.token;
+ }
+
+ public IToken opendir(String path, final DoneOpen done) {
+ return new FileSystemCommand("opendir", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileHandle h = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ h = toFileHandle(args[2]);
+ }
+ }
+ done.doneOpen(token, s, h);
+ }
+ }.token;
+ }
+
+ public IToken read(IFileHandle handle, long offset, int len, final DoneRead done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("read", new Object[]{
+ id, Long.valueOf(offset), Integer.valueOf(len) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ byte[] b = null;
+ boolean eof = false;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 4;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ String str = (String)args[0];
+ if (str != null) b = Base64.toByteArray(str.toCharArray());
+ eof = ((Boolean)args[3]).booleanValue();
+ }
+ }
+ done.doneRead(token, s, b, eof);
+ }
+ }.token;
+ }
+
+ public IToken readdir(IFileHandle handle, final DoneReadDir done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("readdir", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ DirEntry[] b = null;
+ boolean eof = false;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 4;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ b = toDirEntryArray(args[0]);
+ eof = ((Boolean)args[3]).booleanValue();
+ }
+ }
+ done.doneReadDir(token, s, b, eof);
+ }
+ }.token;
+ }
+
+ public IToken roots(final DoneRoots done) {
+ return new FileSystemCommand("roots", null) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ DirEntry[] b = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ b = toDirEntryArray(args[0]);
+ }
+ }
+ done.doneRoots(token, s, b);
+ }
+ }.token;
+ }
+
+ public IToken readlink(String path, final DoneReadLink done) {
+ return new FileSystemCommand("readlink", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ String p = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ p = (String)args[2];
+ }
+ }
+ done.doneReadLink(token, s, p);
+ }
+ }.token;
+ }
+
+ public IToken realpath(String path, final DoneRealPath done) {
+ return new FileSystemCommand("realpath", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ String p = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ p = (String)args[2];
+ }
+ }
+ done.doneRealPath(token, s, p);
+ }
+ }.token;
+ }
+
+ public IToken remove(String file_name, final DoneRemove done) {
+ return new FileSystemCommand("remove", new Object[]{ file_name }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRemove(token, s);
+ }
+ }.token;
+ }
+
+ public IToken rename(String old_path, String new_path, final DoneRename done) {
+ return new FileSystemCommand("rename", new Object[]{ old_path, new_path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRename(token, s);
+ }
+ }.token;
+ }
+
+ public IToken rmdir(String path, final DoneRemove done) {
+ return new FileSystemCommand("rmdir", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRemove(token, s);
+ }
+ }.token;
+ }
+
+ public IToken symlink(String link_path, String target_path, final DoneSymLink done) {
+ return new FileSystemCommand("symlink", new Object[]{ link_path, target_path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSymLink(token, s);
+ }
+ }.token;
+ }
+
+ public IToken write(IFileHandle handle, long offset, byte[] data,
+ int data_pos, int data_size, final DoneWrite done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("write", new Object[]{
+ id, Long.valueOf(offset), Base64.toBase64(data, data_pos, data_size) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneWrite(token, s);
+ }
+ }.token;
+ }
+
+ public IToken copy(String src_path, String dst_path,
+ boolean copy_permissions, boolean copy_uidgid, final DoneCopy done) {
+ return new FileSystemCommand("copy", new Object[]{
+ src_path, dst_path, Boolean.valueOf(copy_permissions),
+ Boolean.valueOf(copy_uidgid) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneCopy(token, s);
+ }
+ }.token;
+ }
+
+ public IToken user(final DoneUser done) {
+ return new FileSystemCommand("user", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ int r_uid = 0;
+ int e_uid = 0;
+ int r_gid = 0;
+ int e_gid = 0;
+ String home = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 5;
+ r_uid = ((Number)args[0]).intValue();
+ e_uid = ((Number)args[1]).intValue();
+ r_gid = ((Number)args[2]).intValue();
+ e_gid = ((Number)args[3]).intValue();
+ home = (String)args[4];
+ }
+ done.doneUser(token, s, r_uid, e_uid, r_gid, e_gid, home);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ private Object toObject(FileAttrs attrs) {
+ if (attrs == null) return null;
+ Map<String,Object> m = new HashMap<String,Object>();
+ if (attrs.attributes != null) m.putAll(attrs.attributes);
+ if ((attrs.flags & ATTR_SIZE) != 0) {
+ m.put("Size", Long.valueOf(attrs.size));
+ }
+ if ((attrs.flags & ATTR_UIDGID) != 0) {
+ m.put("UID", Integer.valueOf(attrs.uid));
+ m.put("GID", Integer.valueOf(attrs.gid));
+ }
+ if ((attrs.flags & ATTR_PERMISSIONS) != 0) {
+ m.put("Permissions", Integer.valueOf(attrs.permissions));
+ }
+ if ((attrs.flags & ATTR_ACMODTIME) != 0) {
+ m.put("ATime", Long.valueOf(attrs.atime));
+ m.put("MTime", Long.valueOf(attrs.mtime));
+ }
+ return m;
+ }
+
+ @SuppressWarnings("unchecked")
+ private FileAttrs toFileAttrs(Object o) {
+ if (o == null) return null;
+ Map<String,Object> m = new HashMap<String,Object>((Map<String,Object>)o);
+ int flags = 0;
+ long size = 0;
+ int uid = 0;
+ int gid = 0;
+ int permissions = 0;
+ long atime = 0;
+ long mtime = 0;
+ Number n = (Number)m.remove("Size");
+ if (n != null) {
+ size = n.longValue();
+ flags |= ATTR_SIZE;
+ }
+ Number n1 = (Number)m.remove("UID");
+ Number n2 = (Number)m.remove("GID");
+ if (n1 != null && n2 != null) {
+ uid = n1.intValue();
+ gid = n2.intValue();
+ flags |= ATTR_UIDGID;
+ }
+ n = (Number)m.remove("Permissions");
+ if (n != null) {
+ permissions = n.intValue();
+ flags |= ATTR_PERMISSIONS;
+ }
+ n1 = (Number)m.remove("ATime");
+ n2 = (Number)m.remove("MTime");
+ if (n1 != null && n2 != null) {
+ atime = n1.longValue();
+ mtime = n2.longValue();
+ flags |= ATTR_ACMODTIME;
+ }
+ return new FileAttrs(flags, size, uid, gid, permissions, atime, mtime, m);
+ }
+
+ private FileHandle toFileHandle(Object o) {
+ if (o == null) return null;
+ return new FileHandle(o.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ private DirEntry[] toDirEntryArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ DirEntry[] res = new DirEntry[c.size()];
+ int i = 0;
+ for (Map<String,Object> m : c) {
+ res[i++] = new DirEntry(
+ (String)m.get("FileName"),
+ (String)m.get("LongName"),
+ toFileAttrs(m.get("Attrs")));
+ }
+ return res;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java
new file mode 100644
index 000000000..36293b5c2
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+
+/**
+ * Objects of GenericProxy class represent remote services, which don't
+ * have a proxy class defined for them.
+ * Clients still can use such services, but framework will not provide
+ * service specific utility methods for message formatting and parsing.
+ */
+public class GenericProxy implements IService {
+
+ private final IChannel channel;
+ private final String name;
+
+ public GenericProxy(IChannel channel, String name) {
+ this.channel = channel;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public IChannel getChannel() {
+ return channel;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java
new file mode 100644
index 000000000..51e32cd7f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java
@@ -0,0 +1,79 @@
+package com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ILineNumbers;
+
+public class LineNumbersProxy implements ILineNumbers {
+
+ private final IChannel channel;
+
+ public LineNumbersProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken mapToSource(String context_id, Number start_address,
+ Number end_address, final DoneMapToSource done) {
+ return new Command(channel, this, "mapToSource", new Object[]{ context_id,
+ start_address, end_address }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ CodeArea[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toTextAreaArray(args[2]);
+ }
+ done.doneMapToSource(token, error, arr);
+ }
+ }.token;
+ }
+
+ private static int getInteger(Map<String,Object> map, String name, int def) {
+ Number n = (Number)map.get(name);
+ if (n == null) return def;
+ return n.intValue();
+ }
+
+ private static String getString(Map<String,Object> map, String name, String def) {
+ String s = (String)map.get(name);
+ if (s == null) return def;
+ return s;
+ }
+
+ private static boolean getBoolean(Map<String,Object> map, String name) {
+ Boolean b = (Boolean)map.get(name);
+ if (b == null) return false;
+ return b.booleanValue();
+ }
+
+ @SuppressWarnings("unchecked")
+ private CodeArea[] toTextAreaArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ CodeArea[] arr = new CodeArea[c.size()];
+ String directory = null;
+ String file = null;
+ for (Map<String,Object> area : c) {
+ directory = getString(area, "Dir", directory);
+ file = getString(area, "File", file);
+ arr[n++] = new CodeArea(directory, file,
+ getInteger(area, "SLine", 0), getInteger(area, "SCol", 0),
+ getInteger(area, "ELine", 0), getInteger(area, "ECol", 0),
+ (Number)area.get("SAddr"), (Number)area.get("EAddr"),
+ getInteger(area, "ISA", 0),
+ getBoolean(area, "IsStmt"), getBoolean(area, "BasicBlock"),
+ getBoolean(area, "PrologueEnd"), getBoolean(area, "EpilogueBegin"));
+ }
+ return arr;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java
new file mode 100644
index 000000000..91dccfb38
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+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.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+public class LocatorProxy implements ILocator {
+
+ private final IChannel channel;
+ private final Map<String,IPeer> peers = new HashMap<String,IPeer>();
+ private final Collection<LocatorListener> listeners = new ArrayList<LocatorListener>();
+
+ private class Peer implements IPeer {
+
+ private final Map<String, String> attrs;
+
+ Peer(Map<String,String> attrs) {
+ this.attrs = attrs;
+ }
+
+ public Map<String, String> getAttributes() {
+ assert Protocol.isDispatchThread();
+ return attrs;
+ }
+
+ public String getID() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_ID);
+ }
+
+ public String getName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_NAME);
+ }
+
+ public String getOSName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_OS_NAME);
+ }
+
+ public String getTransportName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_TRANSPORT_NAME);
+ }
+
+ public IChannel openChannel() {
+ assert Protocol.isDispatchThread();
+ IChannel c = channel.getRemotePeer().openChannel();
+ c.redirect(getID());
+ return c;
+ }
+ };
+
+ private final IChannel.IEventListener event_listener = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("peerAdded")) {
+ assert args.length == 1;
+ IPeer peer = new Peer((Map<String,String>)args[0]);
+ peers.put(peer.getID(), peer);
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerAdded(peer);
+ }
+ }
+ else if (name.equals("peerChanged")) {
+ assert args.length == 1;
+ Map<String,String> m = (Map<String,String>)args[0];
+ if (m == null) throw new Error("Locator service: invalid peerChanged event - no peer ID");
+ IPeer peer = peers.get(m.get(IPeer.ATTR_ID));
+ if (peer == null) throw new Error("Invalid peerChanged event: unknown peer ID");
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerChanged(peer);
+ }
+ }
+ else if (name.equals("peerRemoved")) {
+ assert args.length == 1;
+ String id = (String)args[0];
+ IPeer peer = peers.get(id);
+ if (peer == null) throw new Error("Locator service: invalid peerRemoved event - unknown peer ID");
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerRemoved(id);
+ }
+ }
+ else {
+ throw new IOException("Locator service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+
+ public LocatorProxy(IChannel channel) {
+ this.channel = channel;
+ channel.addEventListener(this, event_listener);
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public Map<String,IPeer> getPeers() {
+ return peers;
+ }
+
+ public IToken redirect(String peer_id, final DoneRedirect done) {
+ return new Command(channel, this, "redirect", new Object[]{ peer_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneRedirect(token, error);
+ }
+ }.token;
+ }
+
+ public IToken sync(final DoneSync done) {
+ return new Command(channel, this, "sync", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error != null) channel.terminate(error);
+ done.doneSync(token);
+ }
+ }.token;
+ }
+
+ public void addListener(LocatorListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(LocatorListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java
new file mode 100644
index 000000000..19b3e1aa4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Base64;
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IMemory;
+
+public class MemoryProxy implements IMemory {
+
+ private final IChannel channel;
+ private final Map<MemoryListener,IChannel.IEventListener> listeners =
+ new HashMap<MemoryListener,IChannel.IEventListener>();
+
+ private static class Range implements Comparable<Range> {
+ int offs;
+ int size;
+ int stat;
+ String msg;
+
+ public int compareTo(Range o) {
+ if (offs < o.offs) return -1;
+ if (offs > o.offs) return +1;
+ return 0;
+ }
+ }
+
+ private class MemoryErrorReport extends MemoryError implements ErrorOffset {
+
+ private static final long serialVersionUID = 796525409870265390L;
+ private final Range[] ranges;
+
+ @SuppressWarnings("unchecked")
+ MemoryErrorReport(String msg, Number addr, Object ranges) {
+ super(msg);
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)ranges;
+ this.ranges = new Range[c.size()];
+ int n = 0;
+ BigInteger addr_bi = addr instanceof BigInteger ?
+ (BigInteger)addr : new BigInteger(addr.toString());
+ for (Map<String,Object> m : c) {
+ Range r = new Range();
+ Number x = (Number)m.get("addr");
+ BigInteger y = x instanceof BigInteger ?
+ (BigInteger)x : new BigInteger(x.toString());
+ r.offs = addr_bi.subtract(y).intValue();
+ r.size = ((Number)m.get("size")).intValue();
+ r.stat = ((Number)m.get("stat")).intValue();
+ r.msg = Command.toErrorString(m.get("msg"));
+ assert r.offs >= 0;
+ assert r.size >= 0;
+ this.ranges[n++] = r;
+ }
+ Arrays.sort(this.ranges);
+ }
+
+ public String getMessage(int offset) {
+ int l = 0;
+ int h = ranges.length - 1;
+ while (l <= h) {
+ int n = (l + h) / 2;
+ Range r = ranges[n];
+ if (r.offs > offset) {
+ h = n - 1;
+ }
+ else if (offset >= r.offs + r.size) {
+ l = n + 1;
+ }
+ else {
+ return r.msg;
+ }
+ }
+ return null;
+ }
+
+ public int getStatus(int offset) {
+ int l = 0;
+ int h = ranges.length - 1;
+ while (l <= h) {
+ int n = (l + h) / 2;
+ Range r = ranges[n];
+ if (r.offs > offset) {
+ h = n - 1;
+ }
+ else if (offset >= r.offs + r.size) {
+ l = n + 1;
+ }
+ else {
+ return r.stat;
+ }
+ }
+ return BYTE_UNKNOWN;
+ }
+ }
+
+ private class MemContext implements MemoryContext {
+
+ private final Map<String,Object> props;
+
+ MemContext(Map<String,Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ String s = (String)props.get(PROP_PARENT_ID);
+ if (s == null) return "";
+ return s;
+ }
+
+ public int getAddressSize() {
+ Number n = (Number)props.get(PROP_ADDRESS_SIZE);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public int getProcessID() {
+ Number n = (Number)props.get(PROP_PROCESS_ID);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public boolean isBigEndian() {
+ Boolean n = (Boolean)props.get(PROP_BIG_ENDIAN);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public IToken fill(final Number addr, int word_size,
+ byte[] value, int size, int mode, final DoneMemory done) {
+ return new MemoryCommand("fill", new Object[] {
+ getID(), addr, word_size, size, mode, value
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 3;
+ e = toMemoryError(addr, args[0], args[1], args[2]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public IToken get(final Number addr, int word_size,
+ final byte[] buf, final int offs, final int size,
+ int mode, final DoneMemory done) {
+ return new MemoryCommand("get", new Object[] {
+ getID(), addr, word_size, size, mode
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 4;
+ String str = (String)args[0];
+ if (str != null) Base64.toByteArray(buf, offs, size, str.toCharArray());
+ e = toMemoryError(addr, args[1], args[2], args[3]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public IToken set(final Number addr, int word_size,
+ byte[] buf, int offs, int size, int mode, final DoneMemory done) {
+ return new MemoryCommand("set", new Object[] {
+ getID(), addr, word_size, size, mode, Base64.toBase64(buf, offs, size)
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 3;
+ e = toMemoryError(addr, args[0], args[1], args[2]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Memory Context " + props.toString() + "]";
+ }
+ }
+
+ public MemoryProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public void addListener(final MemoryListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextAdded")) {
+ assert args.length == 1;
+ listener.contextAdded(toContextArray(args[0]));
+ }
+ else if (name.equals("contextChanged")) {
+ assert args.length == 1;
+ listener.contextChanged(toContextArray(args[0]));
+ }
+ else if (name.equals("contextRemoved")) {
+ assert args.length == 1;
+ listener.contextRemoved(toStringArray(args[0]));
+ }
+ else if (name.equals("memoryChanged")) {
+ assert args.length == 2;
+ listener.memoryChanged((String)args[0],
+ toAddrArray(args[1]), toSizeArray(args[1]));
+ }
+ else {
+ throw new IOException("Memory service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(MemoryListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ public IToken getContext(String context_id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ MemContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new MemContext((Map<String,Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ private abstract class MemoryCommand extends Command {
+
+ MemoryCommand(String cmd, Object[] args) {
+ super(channel, MemoryProxy.this, cmd, args);
+ }
+
+ MemoryError toMemoryError(Number addr, Object code, Object data, Object ranges) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "...";
+ return new MemoryErrorReport(
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code, addr, ranges);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private MemoryContext[] toContextArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return new MemoryContext[0];
+ int n = 0;
+ MemoryContext[] ctx = new MemoryContext[c.size()];
+ for (Iterator<Map<String,Object>> i = c.iterator(); i.hasNext();) {
+ ctx[n++] = new MemContext(i.next());
+ }
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private long[] toSizeArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ long[] a = new long[c.size()];
+ int n = 0;
+ for (Map<String,Object> m : c) {
+ Number sz = (Number)m.get("size");
+ a[n++] = sz == null ? 0 : sz.longValue();
+ }
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Number[] toAddrArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ Number[] a = new Number[c.size()];
+ int n = 0;
+ for (Map<String,Object> m : c) {
+ a[n++] = (Number)m.get("addr");
+ }
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java
new file mode 100644
index 000000000..4db81a295
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IProcesses;
+
+public class ProcessesProxy implements IProcesses {
+
+ private final IChannel channel;
+
+ private class ProcessContext implements IProcesses.ProcessContext {
+
+ private final Map<String,Object> props;
+
+ ProcessContext(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENTID);
+ }
+
+ public boolean canTerminate() {
+ Boolean b = (Boolean)props.get(PROP_CAN_TERMINATE);
+ return b != null && b.booleanValue();
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public boolean isAttached() {
+ Boolean b = (Boolean)props.get(PROP_ATTACHED);
+ return b != null && b.booleanValue();
+ }
+
+ public IToken attach(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "attach", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken detach(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "detach", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken signal(int signal, final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "signal", new Object[]{ getID(), signal }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken terminate(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "terminate", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String toString() {
+ return "[Processes Context " + props.toString() + "]";
+ }
+ }
+
+ public ProcessesProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, boolean attached_only, final DoneGetChildren done) {
+ return new Command(channel, this,
+ "getChildren", new Object[]{ parent_context_id, attached_only }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] ids = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ ids = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, ids);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this,
+ "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ ProcessContext ctx = null;
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new ProcessContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getEnvironment(final DoneGetEnvironment done) {
+ return new Command(channel, this, "getEnvironment", null) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,String> env = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ env = toEnvMap(args[2]);
+ }
+ done.doneGetEnvironment(token, error, env);
+ }
+ }.token;
+ }
+
+ public IToken start(String directory, String file,
+ String[] command_line, Map<String,String> environment,
+ boolean attach, final DoneStart done) {
+ return new Command(channel, this,
+ "start", new Object[]{ directory, file, command_line,
+ toEnvStringArray(environment), attach }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ ProcessContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new ProcessContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneStart(token, error, ctx);
+ }
+ }.token;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static String[] toStringArray(Object o) {
+ if (o == null) return new String[0];
+ Collection<String> c = (Collection<String>)o;
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ private static String[] toEnvStringArray(Map<String,String> m) {
+ if (m == null) return new String[0];
+ int n = 0;
+ String[] arr = new String[m.size()];
+ for (String s : m.keySet()) {
+ arr[n++] = s + "=" + m.get(s);
+ }
+ return arr;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<String,String> toEnvMap(Object o) {
+ Map<String,String> m = new HashMap<String,String>();
+ if (o == null) return m;
+ Collection<String> c = (Collection<String>)o;
+ for (String s : c) {
+ int i = s.indexOf('=');
+ if (i >= 0) m.put(s.substring(0, i), s.substring(i + 1));
+ else m.put(s, "");
+ }
+ return m;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java
new file mode 100644
index 000000000..e313078ec
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IRegisters;
+
+public class RegistersProxy implements IRegisters {
+
+ private final IChannel channel;
+ private final Map<RegistersListener,IChannel.IEventListener> listeners =
+ new HashMap<RegistersListener,IChannel.IEventListener>();
+
+ private class Context implements RegistersContext {
+
+ private final Map<String,Object> props;
+
+ Context(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String[] getAvailableFormats() {
+ return toStringArray(props.get(PROP_FORMATS));
+ }
+
+ public int[] getBitNumbers() {
+ return toIntArray(props.get(PROP_BITS));
+ }
+
+ public String getDescription() {
+ return (String)props.get(PROP_DESCRIPTION);
+ }
+
+ public int getFirstBitNumber() {
+ Number n = (Number)props.get(PROP_FIST_BIT);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public NamedValue[] getNamedValues() {
+ return toValuesArray(props.get(PROP_VALUES));
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENT_ID);
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public boolean hasSideEffects() {
+ Boolean n = (Boolean)props.get(PROP_SIDE_EFFECTS);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isBigEndian() {
+ Boolean n = (Boolean)props.get(PROP_BIG_ENDIAN);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isFloat() {
+ Boolean n = (Boolean)props.get(PROP_FLOAT);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isLeftToRight() {
+ Boolean n = (Boolean)props.get(PROP_LEFT_TO_RIGHT);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isReadOnce() {
+ Boolean n = (Boolean)props.get(PROP_READ_ONCE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isReadable() {
+ Boolean n = (Boolean)props.get(PROP_READBLE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isVolatile() {
+ Boolean n = (Boolean)props.get(PROP_VOLATILE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isWriteOnce() {
+ Boolean n = (Boolean)props.get(PROP_WRITE_ONCE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isWriteable() {
+ Boolean n = (Boolean)props.get(PROP_WRITEABLE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public IToken get(String format, final DoneGet done) {
+ return new Command(channel, RegistersProxy.this, "get",
+ new Object[]{ getID(), format }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String val = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ val = (String)args[2];
+ }
+ done.doneGet(token, error, val);
+ }
+ }.token;
+ }
+
+ public IToken set(String format, String value, final DoneSet done) {
+ return new Command(channel, RegistersProxy.this, "set",
+ new Object[]{ getID(), format, value }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneSet(token, error);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Registers Context " + props.toString() + "]";
+ }
+ }
+
+ public RegistersProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Context ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new Context((Map<String,Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public void addListener(final RegistersListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextChanged")) {
+ listener.contextChanged();
+ }
+ else if (name.equals("registerChanged")) {
+ assert args.length == 1;
+ listener.registerChanged((String)args[0]);
+ }
+ else {
+ throw new IOException("Registers service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(RegistersListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ @SuppressWarnings("unchecked")
+ private int[] toIntArray(Object o) {
+ Collection<Number> c = (Collection<Number>)o;
+ if (c == null) return null;
+ int i = 0;
+ int[] arr = new int[c.size()];
+ for (Number n : c) arr[i++] = n.intValue();
+ return arr;
+ }
+
+ @SuppressWarnings("unchecked")
+ private NamedValue[] toValuesArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ int i = 0;
+ NamedValue[] arr = new NamedValue[c.size()];
+ for (final Map<String,Object> m : c) {
+ arr[i++] = new NamedValue() {
+
+ public String getDescription() {
+ return (String)m.get("Description");
+ }
+
+ public String getName() {
+ return (String)m.get("Name");
+ }
+
+ public Number getValue() {
+ return (Number)m.get("Value");
+ }
+ };
+ }
+ return arr;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java
new file mode 100644
index 000000000..774a5e6ec
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class RunControlProxy implements IRunControl {
+
+ private final IChannel channel;
+ private final Map<RunControlListener,IChannel.IEventListener> listeners =
+ new HashMap<RunControlListener,IChannel.IEventListener>();
+
+ private class RunContext implements IRunControl.RunControlContext {
+
+ private final Map<String, Object> props;
+
+ RunContext(Map<String, Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ String s = (String)props.get(PROP_PARENT_ID);
+ if (s == null) return "";
+ return s;
+ }
+
+ public boolean isContainer() {
+ Boolean b = (Boolean)props.get(PROP_IS_CONTAINER);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean hasState() {
+ Boolean b = (Boolean)props.get(PROP_HAS_STATE);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean canResume(int mode) {
+ if (props.containsKey(PROP_CAN_RESUME)) {
+ int b = ((Number)props.get(PROP_CAN_RESUME)).intValue();
+ return (b & (1 << mode)) != 0;
+ }
+ return false;
+ }
+
+ public boolean canCount(int mode) {
+ if (props.containsKey(PROP_CAN_COUNT)) {
+ int b = ((Number)props.get(PROP_CAN_COUNT)).intValue();
+ return (b & (1 << mode)) != 0;
+ }
+ return false;
+ }
+
+ public boolean canSuspend() {
+ Boolean b = (Boolean)props.get(PROP_CAN_SUSPEND);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean canTerminate() {
+ Boolean b = (Boolean)props.get(PROP_CAN_TERMINATE);
+ return b != null && b.booleanValue();
+ }
+
+ public IToken getState(final DoneGetState done) {
+ return new Command(channel, RunControlProxy.this, "getState", new Object[]{ getID() }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ boolean susp = false;
+ String pc = null;
+ String reason = null;
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 6;
+ error = toError(args[0], args[1]);
+ susp = ((Boolean)args[2]).booleanValue();
+ if (args[3] != null) pc = ((Number)args[3]).toString();
+ reason = (String)args[4];
+ map = (Map<String,Object>)args[5];
+ }
+ done.doneGetState(token, error, susp, pc, reason, map);
+ }
+ }.token;
+ }
+
+ public IToken resume(int mode, int count, DoneCommand done) {
+ return command("resume", new Object[]{ getID(), mode, count }, done);
+ }
+
+ public IToken suspend(DoneCommand done) {
+ return command("suspend", new Object[]{ getID() }, done);
+ }
+
+ public IToken terminate(DoneCommand done) {
+ return command("terminate", new Object[]{ getID() }, done);
+ }
+
+ private IToken command(String cmd, Object[] args, final DoneCommand done) {
+ return new Command(channel, RunControlProxy.this, cmd, args) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Run Control Context " + props.toString() + "]";
+ }
+ }
+
+ public RunControlProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public void addListener(final RunControlListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextSuspended")) {
+ assert args.length == 4;
+ listener.contextSuspended(
+ (String)args[0],
+ args[1] == null ? null : ((Number)args[1]).toString(),
+ (String)args[2], (Map<String,Object>)args[3]);
+ }
+ else if (name.equals("contextResumed")) {
+ assert args.length == 1;
+ listener.contextResumed((String)args[0]);
+ }
+ else if (name.equals("contextAdded")) {
+ assert args.length == 1;
+ listener.contextAdded(toContextArray(args[0]));
+ }
+ else if (name.equals("contextChanged")) {
+ assert args.length == 1;
+ listener.contextChanged(toContextArray(args[0]));
+ }
+ else if (name.equals("contextRemoved")) {
+ assert args.length == 1;
+ listener.contextRemoved(toStringArray(args[0]));
+ }
+ else if (name.equals("contextException")) {
+ assert args.length == 2;
+ listener.contextException((String)args[0], (String)args[1]);
+ }
+ else if (name.equals("containerSuspended")) {
+ assert args.length == 5;
+ listener.containerSuspended(
+ (String)args[0],
+ args[1] == null ? null : ((Number)args[1]).toString(),
+ (String)args[2], (Map)args[3],
+ toStringArray(args[4]));
+ }
+ else if (name.equals("containerResumed")) {
+ assert args.length == 1;
+ listener.containerResumed(toStringArray(args[0]));
+ }
+ else {
+ throw new IOException("RunControl service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(RunControlListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ public IToken getContext(String context_id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ RunControlContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new RunContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ @SuppressWarnings("unchecked")
+ private RunControlContext[] toContextArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ RunControlContext[] ctx = new RunControlContext[c.size()];
+ for (Map<String, Object> m : c) ctx[n++] = new RunContext(m);
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java
new file mode 100644
index 000000000..5385c5d1f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.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.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IStackTrace;
+
+public class StackTraceProxy implements IStackTrace {
+
+ private final IChannel channel;
+
+ private class Context implements StackTraceContext {
+
+ private final Map<String,Object> props;
+
+ Context(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public Number getArgumentsAddress() {
+ return (Number)props.get(PROP_ARGUMENTS_ADDRESS);
+ }
+
+ public int getArgumentsCount() {
+ Number n = (Number)props.get(PROP_ARGUMENTS_COUNT);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public Number getFrameAddress() {
+ return (Number)props.get(PROP_FRAME_ADDRESS);
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENT_ID);
+ }
+
+ public Number getReturnAddress() {
+ return (Number)props.get(PROP_RETURN_ADDRESS);
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+ }
+
+ public StackTraceProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String[] id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ StackTraceContext[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[1], args[2]);
+ arr = toContextArray(args[0]);
+ }
+ done.doneGetContext(token, error, arr);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ @SuppressWarnings("unchecked")
+ private StackTraceContext[] toContextArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ StackTraceContext[] ctx = new StackTraceContext[c.size()];
+ for (Map<String,Object> m : c) ctx[n++] = new Context(m);
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java
new file mode 100644
index 000000000..6e4648bc8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * 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.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ISysMonitor;
+
+public class SysMonitorProxy implements ISysMonitor {
+
+ private final IChannel channel;
+
+ private class SysMonitorContext implements ISysMonitor.SysMonitorContext {
+
+ private final Map<String, Object> props;
+
+ SysMonitorContext(Map<String, Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getCurrentWorkingDirectory() {
+ return (String)props.get(PROP_CWD);
+ }
+
+ public String getFile() {
+ return (String)props.get(PROP_FILE);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENTID);
+ }
+
+ public String getRoot() {
+ return (String)props.get(PROP_ROOT);
+ }
+
+ public String getGroupName() {
+ return (String)props.get(PROP_GROUPNAME);
+ }
+
+ public long getPGRP() {
+ if (!props.containsKey(PROP_PGRP)) return -1;
+ return ((Number)props.get(PROP_PGRP)).longValue();
+ }
+
+ public long getPID() {
+ if (!props.containsKey(PROP_PID)) return -1;
+ return ((Number)props.get(PROP_PID)).longValue();
+ }
+
+ public long getPPID() {
+ if (!props.containsKey(PROP_PPID)) return -1;
+ return ((Number)props.get(PROP_PPID)).longValue();
+ }
+
+ public long getRSS() {
+ if (!props.containsKey(PROP_RSS)) return -1;
+ return ((Number)props.get(PROP_RSS)).longValue();
+ }
+
+ public String getState() {
+ return (String)props.get(PROP_STATE);
+ }
+
+ public long getTGID() {
+ if (!props.containsKey(PROP_TGID)) return -1;
+ return ((Number)props.get(PROP_TGID)).longValue();
+ }
+
+ public long getTracerPID() {
+ if (!props.containsKey(PROP_TRACERPID)) return -1;
+ return ((Number)props.get(PROP_TRACERPID)).longValue();
+ }
+
+ public long getUGID() {
+ if (!props.containsKey(PROP_UGID)) return -1;
+ return ((Number)props.get(PROP_UGID)).longValue();
+ }
+
+ public long getUID() {
+ if (!props.containsKey(PROP_UID)) return -1;
+ return ((Number)props.get(PROP_UID)).longValue();
+ }
+
+ public String getUserName() {
+ return (String)props.get(PROP_USERNAME);
+ }
+
+ public long getVSize() {
+ if (!props.containsKey(PROP_VSIZE)) return -1;
+ return ((Number)props.get(PROP_VSIZE)).longValue();
+ }
+
+ public long getPSize() {
+ if (!props.containsKey(PROP_PSIZE)) return -1;
+ return ((Number)props.get(PROP_PSIZE)).longValue();
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String toString() {
+ return "[Sys Monitor Context " + props.toString() + "]";
+ }
+ }
+
+ public SysMonitorProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ SysMonitorContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new SysMonitorContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getCommandLine(String id, final DoneGetCommandLine done) {
+ return new Command(channel, this, "getCommandLine", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetCommandLine(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getEnvironment(String id, final DoneGetEnvironment done) {
+ return new Command(channel, this, "getEnvironment", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetEnvironment(token, error, arr);
+ }
+ }.token;
+ }
+
+ private static String[] toStringArray(Collection<String> c) {
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java
new file mode 100644
index 000000000..4b15660b8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * 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.protocol;
+
+import java.util.Collection;
+
+/**
+ * IChannel represents communication link connecting two end points (peers).
+ * The channel asynchronously transmits messages: commands, results and events.
+ * A single channel may be used to communicate with multiple services.
+ * Multiple channels may be used to connect the same peers, however no command or event
+ * ordering is guaranteed across channels.
+ */
+
+public interface IChannel {
+
+ /**
+ * Channel state IDs
+ */
+ static final int
+ STATE_OPENNING = 0,
+ STATE_OPEN = 1,
+ STATE_CLOSED = 2;
+
+ /**
+ * @return channel state, see STATE_*
+ */
+ int getState();
+
+ /**
+ * Send command message to remote peer for execution. Commands can be queued
+ * locally before transmission. Sending commands too fast can fill up
+ * communication channel buffers. Calling thread will be blocked until
+ * enough buffer space is freed up by transmitting pending messages.
+ * @param service - a remote service that will be sent the command
+ * @param name - command name
+ * @param args - command arguments encoded into array of bytes
+ * @param done - call back object
+ * @return pending command handle
+ */
+ IToken sendCommand(IService service, String name, byte[] args, ICommandListener done);
+
+ /**
+ * Command listener interface. Clients implement this interface to
+ * receive command results.
+ */
+ interface ICommandListener {
+
+ /**
+ * Called when progress message (intermediate result) is received
+ * from remote peer.
+ * @param token - command handle
+ * @param data - progress message arguments encoded into array of bytes
+ */
+ void progress(IToken token, byte[] data);
+
+ /**
+ * Called when command result received from remote peer.
+ * @param token - command handle
+ * @param data - command result message arguments encoded into array of bytes
+ */
+ void result(IToken token, byte[] data);
+
+ /**
+ * Called when communication channel was closed while command was waiting for result.
+ * @param token - command handle
+ * @param error - exception that forced the channel to close
+ */
+ void terminated(IToken token, Exception error);
+ }
+
+ /**
+ * Send result message to remote peer. Messages can be queued locally before
+ * transmission. Sending messages too fast can fill up communication channel
+ * buffers. Calling thread will be blocked until enough buffer space is
+ * freed up by transmitting pending messages.
+ * @param token - command handle
+ * @param results - result message arguments encoded into array of bytes
+ */
+ void sendResult(IToken token, byte[] results);
+
+ /**
+ * Get current level of outbound traffic congestion.
+ *
+ * @return integer value in range –100..100, where –100 means no pending
+ * messages (no traffic), 0 means optimal load, and positive numbers
+ * indicate level of congestion.
+ *
+ * Note: inbound traffic congestion is detected by framework and reported to
+ * remote peer without client needed to be involved.
+ */
+ int getCongestion();
+
+ /**
+ * Channel listener interface.
+ */
+ interface IChannelListener {
+
+ /**
+ * Called when a channel is opened.
+ */
+ void onChannelOpened();
+
+ /**
+ * Called when channel closed. If it is closed because of an error,
+ * ‘error’ parameter will describe the error. ‘error’ is null if channel
+ * is closed normally by calling Channel.close().
+ * @param error - channel exception or null
+ */
+ void onChannelClosed(Throwable error);
+
+ /**
+ * Notifies listeners about channel congestion level changes.
+ * When level > 0 client should delay sending more messages.
+ * @param level - current congestion level
+ */
+ void congestionLevel(int level);
+ }
+
+ /**
+ * Subscribe a channel listener. The listener will be notified about changes of
+ * channel state and changes of outbound traffic congestion level.
+ * @param listener - channel listener implementation
+ */
+ void addChannelListener(IChannelListener listener);
+
+ /**
+ * Remove a channel listener.
+ * @param listener - channel listener implementation
+ */
+ void removeChannelListener(IChannelListener listener);
+
+ /**
+ * Command server interface.
+ * This interface is to be implemented by service providers.
+ */
+ interface ICommandServer {
+
+ /**
+ * Called every time a command is received from remote peer.
+ * @param token - command handle
+ * @param name - command name
+ * @param data - command arguments encoded into array of bytes
+ */
+ void command(IToken token, String name, byte[] data);
+ }
+
+ /**
+ * Subscribe a command server. The server will be notified about command
+ * messages received through this channel for given service.
+ * @param service - local service implementation
+ * @param server - implementation of service commands listener
+ */
+ void addCommandServer(IService service, ICommandServer server);
+
+ /**
+ * Remove a command server.
+ * @param service - local service implementation
+ * @param server - implementation of service commands listener
+ */
+ void removeCommandServer(IService service, ICommandServer server);
+
+ /**
+ * A generic interface for service event listener.
+ * Services usually define a service specific event listener interface.
+ * Clients should user service specific listener interface, unless no such interface is defined.
+ */
+ interface IEventListener {
+ /**
+ * Called when service event message is received
+ * @param name - event name
+ * @param data - event arguments encode as array of bytes
+ */
+ void event(String name, byte[] data);
+ }
+
+ /**
+ * Subscribe an event listener for given service.
+ * @param service - remote service proxy
+ * @param server - implementation of service event listener
+ */
+ void addEventListener(IService service, IEventListener listener);
+
+ /**
+ * Unsubscribe an event listener for given service.
+ * @param service - remote service proxy
+ * @param server - implementation of service event listener
+ */
+ void removeEventListener(IService service, IEventListener listener);
+
+ /**
+ * @return IPeer object representing local endpoint of communication channel.
+ */
+ IPeer getLocalPeer();
+
+ /**
+ * @return IPeer object representing remote endpoint of communication channel.
+ */
+ IPeer getRemotePeer();
+
+ /**
+ * @return collection of services available on local peer.
+ */
+ Collection<String> getLocalServices();
+
+ /**
+ * @return an object representing a service from local peer.
+ * Return null if the service is not available.
+ */
+ IService getLocalService(String service_name);
+
+ /**
+ * @return an object representing a service from local peer.
+ * Service object should implement given interface.
+ * Return null if implementation of the interface is not available.
+ */
+ <V extends IService> V getLocalService(Class<V> service_interface);
+
+ /**
+ * @return collection of services available on remote peer.
+ */
+ Collection<String> getRemoteServices();
+
+ /**
+ * @return an object representing a service from remote peer.
+ * Return null if the service is not available.
+ */
+ IService getRemoteService(String service_name);
+
+ /**
+ * @return an object representing a service from remote peer.
+ * Service object should implement given interface.
+ * Return null if implementation of the interface is not available.
+ */
+ <V extends IService> V getRemoteService(Class<V> service_interface);
+
+ /**
+ * Close communication channel.
+ */
+ void close();
+
+ /**
+ * Close channel in case of communication error.
+ * @param error - cause of channel termination
+ */
+ void terminate(Throwable error);
+
+ /**
+ * Redirect this channel to given peer using this channel remote peer locator service as a proxy.
+ * @param peer_id - peer that will become new remote communication endpoint of this channel
+ */
+ void redirect(String peer_id);
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java
new file mode 100644
index 000000000..0ace6e635
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.protocol;
+
+/**
+ * Clients of the framework should implement this interface and call Protocol.setEventQueue.
+ * Implementation should encapsulate a queue and asynchronous event dispatch machinery, which
+ * extracts events from the queue and dispatches them by calling event's run() method.
+ * The implementation is used by framework to queue and dispatch all events.
+ */
+public interface IEventQueue {
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of this event queue.
+ * Events are dispatched in same order as queued.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed asynchronously.
+ */
+ void invokeLater(Runnable runnable);
+
+ /**
+ * Returns true if the calling thread is this event queue's dispatch thread.
+ * Use this call the ensure that a given task is being executed (or not being) on dispatch thread.
+ *
+ * @return true if running on the dispatch thread.
+ */
+ boolean isDispatchThread();
+
+ /**
+ * Get current level of queue congestion.
+ *
+ * @return integer value in range –100..100, where –100 means no pending
+ * messages (no traffic), 0 means optimal load, and positive numbers
+ * indicate level of congestion.
+ */
+ public int getCongestion();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java
new file mode 100644
index 000000000..7abc75e2c
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.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.protocol;
+
+import java.util.Map;
+
+/**
+ * Both hosts and targets are represented by objects
+ * implementing IPeer interface. A peer can act as host or
+ * target depending on services it implements.
+ * List of currently known peers can be retrieved by
+ * calling ILocator.getPeers()
+ */
+public interface IPeer {
+
+ /**
+ * Peer property names. Implementation can define additional properties.
+ */
+ static final String
+ ATTR_ID = "ID",
+ ATTR_NAME = "Name",
+ ATTR_OS_NAME = "OSName",
+ ATTR_TRANSPORT_NAME = "TransportName",
+ ATTR_IP_HOST = "Host",
+ ATTR_IP_ALIASES = "Aliases",
+ ATTR_IP_ADDRESSES = "Addresses",
+ ATTR_IP_PORT = "Port";
+
+
+ /**
+ * @return map of peer attributes
+ */
+ Map<String, String> getAttributes();
+
+ /**
+ * @return peer unique ID, same as getAttributes().get(ATTR_ID)
+ */
+ String getID();
+
+ /**
+ * @return peer name, same as getAttributes().get(ATTR_NAME)
+ */
+ String getName();
+
+ /**
+ * Same as getAttributes().get(ATTR_OS_NAME)
+ */
+ String getOSName();
+
+ /**
+ * Same as getAttributes().get(ATTR_TRANSPORT_NAME)
+ */
+ String getTransportName();
+
+ /**
+ * Open channel to communicate with this peer.
+ * Note: the channel is not fully open yet when this method returns.
+ * It’s state is IChannel.STATE_OPENNING.
+ * Protocol.Listener will be called when the channel will be opened or closed.
+ */
+ IChannel openChannel();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java
new file mode 100644
index 000000000..d6eb3d4f1
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.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.tcf.api.protocol;
+
+/**
+ * Base interface for all service interfaces. A client can get list of available services
+ * by calling Peer.getServices()
+ */
+
+public interface IService {
+
+ /**
+ * Get unique name of this service.
+ * @return service name.
+ */
+ String getName();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java
new file mode 100644
index 000000000..b42645107
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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.protocol;
+
+/**
+ * IToken is created by the framework for each command sent to a remote peer.
+ * It is used to match results to commands and to cancel pending commands.
+ */
+public interface IToken {
+
+ /**
+ * Try to cancel a command associated with given token. A command can be
+ * canceled by this method only if it was not transmitted yet to remote peer
+ * for execution. Successfully canceled command does not produce any result
+ * messages.
+ *
+ * @return true if successful.
+ */
+ boolean cancel();
+
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java
new file mode 100644
index 000000000..16fdcb5e8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java
@@ -0,0 +1,516 @@
+/*******************************************************************************
+ * 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.protocol;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+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 com.windriver.tcf.api.internal.core.ReadOnlyCollection;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+
+/**
+ * JSON is TCF preferred marshaling. This class implements generation and parsing of JSON strings.
+ * The code is optimized for speed since it is a time-critical part of the framework.
+ */
+public class JSON {
+
+ private static char[] tmp_buf = new char[0x1000];
+ private static byte[] tmp_bbf = new byte[0x1000];
+ private static int tmp_buf_pos;
+
+ private static Reader reader;
+ private static final char[] cur_buf = new char[0x1000];
+ private static int cur_buf_pos;
+ private static int cur_buf_len;
+ private static int cur_ch;
+
+ // This buffer is used to create nice error reports
+ private static final char[] err_buf = new char[100];
+ private static int err_buf_pos;
+ private static int err_buf_cnt;
+
+ private static void write(char ch) {
+ if (tmp_buf_pos >= tmp_buf.length) {
+ char[] tmp = new char[tmp_buf.length * 2];
+ System.arraycopy(tmp_buf, 0, tmp, 0, tmp_buf_pos);
+ tmp_buf = tmp;
+ }
+ tmp_buf[tmp_buf_pos++] = ch;
+ }
+
+ private static void write(String s) {
+ int l = s.length();
+ for (int i = 0; i < l; i++) {
+ char ch = s.charAt(i);
+ if (tmp_buf_pos >= tmp_buf.length) write(ch);
+ else tmp_buf[tmp_buf_pos++] = ch;
+ }
+ }
+
+ private static void writeUInt(int n) {
+ assert n >= 0;
+ if (n >= 10) writeUInt(n / 10);
+ write((char)('0' + n % 10));
+ }
+
+ private static void read() throws IOException {
+ if (cur_buf_pos >= cur_buf_len) {
+ cur_buf_len = reader.read(cur_buf);
+ cur_buf_pos = 0;
+ if (cur_buf_len < 0) {
+ cur_buf_len = 0;
+ cur_ch = -1;
+ return;
+ }
+ }
+ cur_ch = cur_buf[cur_buf_pos++];
+ err_buf[err_buf_pos++] = (char)cur_ch;
+ if (err_buf_pos >= err_buf.length) {
+ err_buf_pos = 0;
+ err_buf_cnt++;
+ }
+ }
+
+ private static void error() throws IOException {
+ error("syntax error");
+ }
+
+ private static void error(String msg) throws IOException {
+ StringBuffer bf = new StringBuffer();
+ bf.append("JSON " + msg + ":");
+ int cnt = 0;
+ boolean nl = true;
+ for (int i = 0;; i++) {
+ char ch = 0;
+ if (err_buf_cnt == 0 && i < err_buf_pos) {
+ ch = err_buf[i];
+ }
+ else if (err_buf_cnt > 0 && i < err_buf.length) {
+ ch = err_buf[(err_buf_pos + i) % err_buf.length];
+ }
+ else {
+ int n = reader.read();
+ if (n < 0) break;
+ ch = (char)n;
+ }
+ if (nl) {
+ bf.append("\n ");
+ if (err_buf_cnt == 0) bf.append(cnt);
+ else bf.append('*');
+ bf.append(": ");
+ if (cnt == 0 && err_buf_cnt > 0) bf.append("...");
+ nl = false;
+ }
+ if (ch == 0) {
+ cnt++;
+ nl = true;
+ continue;
+ }
+ bf.append(ch);
+ }
+ throw new IOException(bf.toString());
+ }
+
+ private static int readHexDigit() throws IOException {
+ int n = 0;
+ if (cur_ch >= '0' && cur_ch <= '9') n = cur_ch - '0';
+ else if (cur_ch >= 'A' && cur_ch <= 'F') n = cur_ch - 'A' + 10;
+ else if (cur_ch >= 'a' && cur_ch <= 'f') n = cur_ch - 'a' + 10;
+ else error();
+ read();
+ return n;
+ }
+
+ private static Object readNestedObject() throws IOException {
+ switch (cur_ch) {
+ case '"':
+ read();
+ tmp_buf_pos = 0;
+ for (;;) {
+ if (cur_ch <= 0) error();
+ if (cur_ch == '"') break;
+ if (cur_ch == '\\') {
+ read();
+ if (cur_ch <= 0) error();
+ switch (cur_ch) {
+ case '"':
+ case '\\':
+ case '/':
+ break;
+ case 'b':
+ cur_ch = '\b';
+ break;
+ case 'f':
+ cur_ch = '\f';
+ break;
+ case 'n':
+ cur_ch = '\n';
+ break;
+ case 'r':
+ cur_ch = '\r';
+ break;
+ case 't':
+ cur_ch = '\t';
+ break;
+ case 'u':
+ read();
+ int n = 0;
+ n |= readHexDigit() << 12;
+ n |= readHexDigit() << 8;
+ n |= readHexDigit() << 4;
+ n |= readHexDigit();
+ write((char)n);
+ continue;
+ default:
+ error();
+ break;
+ }
+ }
+ if (tmp_buf_pos >= tmp_buf.length) {
+ write((char)cur_ch);
+ }
+ else {
+ tmp_buf[tmp_buf_pos++] = (char)cur_ch;
+ }
+ if (cur_buf_pos >= cur_buf_len) {
+ read();
+ }
+ else {
+ cur_ch = cur_buf[cur_buf_pos++];
+ err_buf[err_buf_pos++] = (char)cur_ch;
+ if (err_buf_pos >= err_buf.length) {
+ err_buf_pos = 0;
+ err_buf_cnt++;
+ }
+ }
+ }
+ read();
+ return new String(tmp_buf, 0, tmp_buf_pos);
+ case '[':
+ Collection<Object> l = new ArrayList<Object>();
+ read();
+ if (cur_ch <= 0) error();
+ if (cur_ch != ']') {
+ for (;;) {
+ l.add(readNestedObject());
+ if (cur_ch == ']') break;
+ if (cur_ch != ',') error();
+ read();
+ }
+ }
+ read();
+ return new ReadOnlyCollection<Object>(l);
+ case '{':
+ Map<String,Object> m = new HashMap<String,Object>();
+ read();
+ if (cur_ch <= 0) error();
+ if (cur_ch != '}') {
+ for (;;) {
+ String key = (String)readNestedObject();
+ if (cur_ch != ':') error();
+ read();
+ Object val = readNestedObject();
+ m.put(key, val);
+ if (cur_ch == '}') break;
+ if (cur_ch != ',') error();
+ read();
+ }
+ }
+ read();
+ return new ReadOnlyMap<String,Object>(m);
+ case 'n':
+ read();
+ if (cur_ch != 'u') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ return null;
+ case 'f':
+ read();
+ if (cur_ch != 'a') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ if (cur_ch != 's') error();
+ read();
+ if (cur_ch != 'e') error();
+ read();
+ return Boolean.FALSE;
+ case 't':
+ read();
+ if (cur_ch != 'r') error();
+ read();
+ if (cur_ch != 'u') error();
+ read();
+ if (cur_ch != 'e') error();
+ read();
+ return Boolean.TRUE;
+ default:
+ boolean neg = cur_ch == '-';
+ if (neg) read();
+ if (cur_ch >= '0' && cur_ch <= '9') {
+ // TODO: float number
+ int v = 0;
+ while (v <= 0x7fffffff / 10 - 1) {
+ v = v * 10 + (cur_ch - '0');
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new Integer(neg ? -v : v);
+ }
+ }
+ long vl = v;
+ while (vl < 0x7fffffffffffffffl / 10 - 1) {
+ vl = vl * 10 + (cur_ch - '0');
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new Long(neg ? -vl : vl);
+ }
+ }
+ StringBuffer sb = new StringBuffer();
+ if (neg) sb.append('-');
+ sb.append(vl);
+ while (true) {
+ sb.append(cur_ch);
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new BigInteger(sb.toString());
+ }
+ }
+ }
+ error();
+ return null;
+ }
+ }
+
+ private static Object readObject() throws IOException {
+ Object o = readNestedObject();
+ if (cur_ch >= 0) error();
+ return o;
+ }
+
+ private static Object[] readSequence() throws IOException {
+ List<Object> l = new ArrayList<Object>();
+ while (cur_ch >= 0) {
+ l.add(readNestedObject());
+ if (cur_ch != 0) error("missing \\0 terminator");
+ read();
+ }
+ return l.toArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void writeObject(Object o) throws IOException {
+ if (o == null) {
+ write("null");
+ }
+ else if (o instanceof Boolean) {
+ write(o.toString());
+ }
+ else if (o instanceof Number) {
+ write(o.toString());
+ }
+ else if (o instanceof String) {
+ String s = (String)o;
+ char[] arr = new char[s.length()];
+ s.getChars(0, arr.length, arr, 0);
+ writeObject(arr);
+ }
+ else if (o instanceof char[]) {
+ char[] s = (char[])o;
+ write('"');
+ int l = s.length;
+ for (int i = 0; i < l; i++) {
+ char ch = s[i];
+ switch (ch) {
+ case 0:
+ write("\\u0000");
+ break;
+ case '\r':
+ write("\\r");
+ break;
+ case '\n':
+ write("\\n");
+ break;
+ case '\t':
+ write("\\t");
+ break;
+ case '\b':
+ write("\\b");
+ break;
+ case '\f':
+ write("\\f");
+ break;
+ case '"':
+ case '\\':
+ write('\\');
+ default:
+ if (tmp_buf_pos >= tmp_buf.length) write(ch);
+ else tmp_buf[tmp_buf_pos++] = ch;
+ }
+ }
+ write('"');
+ }
+ else if (o instanceof byte[]) {
+ write('[');
+ byte[] arr = (byte[])o;
+ boolean comma = false;
+ for (int i = 0; i < arr.length; i++) {
+ if (comma) write(',');
+ writeUInt(arr[i] & 0xff);
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Object[]) {
+ write('[');
+ Object[] arr = (Object[])o;
+ boolean comma = false;
+ for (int i = 0; i < arr.length; i++) {
+ if (comma) write(',');
+ writeObject(arr[i]);
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Collection) {
+ write('[');
+ boolean comma = false;
+ for (Iterator<Object> i = ((Collection<Object>)o).iterator(); i.hasNext();) {
+ if (comma) write(',');
+ writeObject(i.next());
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Map) {
+ Map<String,Object> map = (Map<String,Object>)o;
+ write('{');
+ boolean comma = false;
+ for (Iterator<Map.Entry<String,Object>> i = map.entrySet().iterator(); i.hasNext();) {
+ if (comma) write(',');
+ Map.Entry<String,Object> e = i.next();
+ writeObject(e.getKey());
+ write(':');
+ writeObject(e.getValue());
+ comma = true;
+ }
+ write('}');
+ }
+ else {
+ throw new IOException("JSON: unsupported object type");
+ }
+ }
+
+ private static byte[] toBytes() throws UnsupportedEncodingException {
+ int inp_pos = 0;
+ int out_pos = 0;
+ while (inp_pos < tmp_buf_pos) {
+ if (out_pos >= tmp_bbf.length - 4) {
+ byte[] tmp = new byte[tmp_bbf.length * 2];
+ System.arraycopy(tmp_bbf, 0, tmp, 0, out_pos);
+ tmp_bbf = tmp;
+ }
+ int ch = tmp_buf[inp_pos++];
+ if (ch < 0x80) {
+ tmp_bbf[out_pos++] = (byte)ch;
+ }
+ else if (ch < 0x800) {
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) | 0xc0);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ else if (ch < 0x10000) {
+ tmp_bbf[out_pos++] = (byte)((ch >> 12) | 0xe0);
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ else {
+ tmp_bbf[out_pos++] = (byte)((ch >> 18) | 0xf0);
+ tmp_bbf[out_pos++] = (byte)((ch >> 12) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ }
+ byte[] res = new byte[out_pos];
+ System.arraycopy(tmp_bbf, 0, res, 0, out_pos);
+ return res;
+ }
+
+ public static String toJSON(Object o) throws IOException {
+ assert Protocol.isDispatchThread();
+ tmp_buf_pos = 0;
+ writeObject(o);
+ return new String(tmp_buf, 0, tmp_buf_pos);
+ }
+
+ public static byte[] toJASONBytes(Object o) throws IOException {
+ assert Protocol.isDispatchThread();
+ tmp_buf_pos = 0;
+ writeObject(o);
+ return toBytes();
+ }
+
+ public static byte[] toJSONSequence(Object[] o) throws IOException {
+ assert Protocol.isDispatchThread();
+ if (o == null || o.length == 0) return null;
+ tmp_buf_pos = 0;
+ for (int i = 0; i < o.length; i++) {
+ writeObject(o[i]);
+ write((char)0);
+ }
+ return toBytes();
+ }
+
+ public static Object parseOne(String s) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new StringReader(s);
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readObject();
+ }
+
+ public static Object parseOne(byte[] b) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readObject();
+ }
+
+ public static Object[] parseSequence(byte[] b) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readSequence();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java
new file mode 100644
index 000000000..7e577ccf5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * 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.protocol;
+
+import com.windriver.tcf.api.internal.core.LocalPeer;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ *
+ * Class Protocol provides static methods to access Target Communication Framework root objects:
+ * 1. the framework event queue and dispatch thread;
+ * 2. local instance of Locator service, which maintains a list of available targets;
+ * 3. list of open communication channels.
+ */
+public class Protocol {
+
+ private static IEventQueue event_queue;
+
+ /**
+ * Before TCF can be used it should be given an object implementing IEventQueue interface.
+ * The implementation maintains a queue of objects implementing Runnable interface and
+ * executes <code>run</code> methods of that objects in a sequence by a single thread.
+ * The thread in referred as TCF event dispatch thread. Objects in the queue are called TCF events.
+ * Executing <code>run</code> method of an event is also called dispatching of event.
+ *
+ * Only few methods in TCF APIs are thread safe - can be invoked from any thread.
+ * If a method description does not say "can be invoked from any thread" explicitly -
+ * the method must be invoked from TCF event dispatch thread. All TCF listeners are
+ * invoked from the dispatch thread.
+ *
+ * @param event_queue - IEventQueue implementation.
+ */
+ public static void setEventQueue(IEventQueue event_queue) {
+ assert Protocol.event_queue == null;
+ Protocol.event_queue = event_queue;
+ event_queue.invokeLater(new Runnable() {
+
+ public void run() {
+ new LocatorService();
+ new LocalPeer();
+ }
+ });
+ }
+
+ /**
+ * @return instance of IEventQueue that is used for TCF events.
+ */
+ public static IEventQueue getEventQueue() {
+ return event_queue;
+ }
+
+ /**
+ * Returns true if the calling thread is TCF event dispatch thread.
+ * Use this call the ensure that a given task is being executed (or not being)
+ * on dispatch thread.
+ *
+ * @return true if running on the dispatch thread.
+ */
+ public static boolean isDispatchThread() {
+ return event_queue != null && event_queue.isDispatchThread();
+ }
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of the framework.
+ * Events are dispatched in same order as queued.
+ * If invokeLater is called from the dispatching thread
+ * the <i>runnable.run()</i> will still be deferred until
+ * all pending events have been processed.
+ *
+ * This method can be invoked from any thread.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed asynchronously.
+ */
+ public static void invokeLater(Runnable runnable) {
+ event_queue.invokeLater(runnable);
+ }
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of the framework.
+ * Calling thread is suspended until the method is executed.
+ *
+ * This method can be invoked from any thread.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed on dispatch thread.
+ */
+ public static void invokeAndWait(final Runnable runnable) {
+ if (event_queue.isDispatchThread()) {
+ runnable.run();
+ }
+ else {
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ runnable.run();
+ }
+ finally {
+ synchronized (this) {
+ notify();
+ }
+ }
+ }
+ };
+ synchronized (r) {
+ event_queue.invokeLater(r);
+ try {
+ r.wait();
+ }
+ catch (InterruptedException x) {
+ throw new Error(x);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get instance of the framework locator service.
+ * The service can be used to discover available remote peers.
+ *
+ * @return instance of ILocator.
+ */
+ public static ILocator getLocator() {
+ return LocatorService.getLocator();
+ }
+
+ /**
+ * Return an array of all open channels.
+ * @return an array of IChannel
+ */
+ public static IChannel[] getOpenChannels() {
+ return Transport.getOpenChannels();
+ }
+
+ /**
+ * Interface to be implemented by clients willing to be notified when
+ * new TCF communication channel is opened.
+ */
+ public interface ChannelOpenListener {
+ public void onChannelOpen(IChannel channel);
+ }
+
+ /**
+ * Add a listener that will be notified when new channel is opened.
+ * @param listener
+ */
+ public static void addChannelOpenListener(ChannelOpenListener listener) {
+ Transport.addChanalOpenListener(listener);
+ }
+
+ /**
+ * Remove channel opening listener.
+ * @param listener
+ */
+ public static void removeChannelOpenListener(ChannelOpenListener listener) {
+ Transport.removeChanalOpenListener(listener);
+ }
+
+ /**
+ * Transmit TCF event message.
+ * The message is sent to all open communication channels – broadcasted.
+ */
+ public static void sendEvent(String service_name, String event_name, byte[] data) {
+ Transport.sendEvent(service_name, event_name, data);
+ }
+
+ /**
+ * Call back after TCF messages sent by this host up to this moment are delivered
+ * to their intended target. This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need cross channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ */
+ public static void sync(Runnable done) {
+ Transport.sync(done);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java
new file mode 100644
index 000000000..fbcb5e0b5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * Breakpoint is represented by unique identifier and set of properties.
+ * Breakpoint identifier (String id) needs to be unique across all hosts and targets.
+ *
+ * Breakpoint properties (Map<String,Object>) is extendable collection of named attributes,
+ * which define breakpoint location and behavior. This module defines some common
+ * attribute names (see PROP_*), host tools and target agents may support additional attributes.
+ *
+ * For each breakpoint a target agent maintains another extendable collection of named attributes:
+ * breakpoint status (Map<String,Object>, see STATUS_*). While breakpoint properties are
+ * persistent and represent user input, breakpoint status reflects dynamic target agent reports
+ * about breakpoint current state, like actual addresses where breakpoint is planted or planting errors.
+ */
+public interface IBreakpoints extends IService {
+
+ /**
+ * Service name.
+ */
+ static final String NAME = "Breakpoints";
+
+ /**
+ * Breakpoint property names.
+ */
+ static final String
+ PROP_ID = "ID", // String
+ PROP_ENABLED = "Enabled", // Boolean
+ PROP_ADDRESS = "Address", // String
+ PROP_CONDITION = "Condition", // String
+ PROP_FILE = "File", // String
+ PROP_LINE = "Line", // Number
+ PROP_COLUMN = "Column"; // Number
+
+ /**
+ * Breakpoint status field names.
+ */
+ static final String
+ STATUS_PLANTED = "Planted", // Array of addresses
+ STATUS_ERROR = "Error", // String
+ STATUS_FILE = "File", // String
+ STATUS_LINE = "Line", // Number
+ STATUS_COLUMN = "Column"; // Number
+
+ /**
+ * Call back interface for breakpoint service commands.
+ */
+ interface DoneCommand {
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Download breakpoints data to target agent.
+ * The command is intended to be used only to initialize target breakpoints table
+ * when communication channel is open. After that, host should
+ * notify target about (incremental) changes in breakpoint data by sending
+ * add, change and remove commands.
+ *
+ * @param properties - array of breakpoints.
+ * @param done - command result call back object.
+ */
+ IToken set(Map<String,Object>[] properties, DoneCommand done);
+
+ /**
+ * Called when breakpoint is added into breakpoints table.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */
+ IToken add(Map<String,Object> properties, DoneCommand done);
+
+ /**
+ * Called when breakpoint properties are changed.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */
+ IToken change(Map<String,Object> properties, DoneCommand done);
+
+ /**
+ * Tell target to change (only) PROP_ENABLED breakpoint property 'true'.
+ * @param ids - array of enabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */
+ IToken enable(String[] ids, DoneCommand done);
+
+ /**
+ * Tell target to change (only) PROP_ENABLED breakpoint property to 'false'.
+ * @param ids - array of disabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */
+ IToken disable(String[] ids, DoneCommand done);
+
+ /**
+ * Tell target to remove breakpoint.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken remove(String[] ids, DoneCommand done);
+
+ /**
+ * Upload IDs of breakpoints known to target agent.
+ * @param done - command result call back object.
+ */
+ IToken getIDs(DoneGetIDs done);
+
+ interface DoneGetIDs {
+ void doneGetIDs(IToken token, Exception error, String[] ids);
+ }
+
+ /**
+ * Upload properties of given breakpoint from target agent breakpoint table.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken getProperties(String id, DoneGetProperties done);
+
+ interface DoneGetProperties {
+ void doneGetProperties(IToken token, Exception error, Map<String,Object> properties);
+ }
+
+ /**
+ * Upload status of given breakpoint from target agent.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken getStatus(String id, DoneGetStatus done);
+
+ interface DoneGetStatus {
+ void doneGetStatus(IToken token, Exception error, Map<String,Object> status);
+ }
+
+ /**
+ * Breakpoints service events listener.
+ */
+ interface BreakpointsListener {
+
+ /**
+ * Called when breakpoint status changes.
+ * @param id - unique breakpoint identifier.
+ * @param status - breakpoint status.
+ */
+ void breakpointStatusChanged(String id, Map<String,Object> status);
+ }
+
+ void addListener(BreakpointsListener listener);
+
+ void removeListener(BreakpointsListener listener);
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java
new file mode 100644
index 000000000..9552c4a6d
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.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.tcf.api.services;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * This is optional service that can be implemented by a peer.
+ * If implemented, the service can be used for testing of the peer and
+ * communication channel functionality and reliability.
+ */
+
+public interface IDiagnostics extends IService {
+
+ public static final String NAME = "Diagnostics";
+
+ public IToken echo(String s, DoneEcho done);
+
+ public interface DoneEcho {
+ public void doneEcho(IToken token, Throwable error, String s);
+ }
+
+ public IToken getTestList(DoneGetTestList done);
+
+ public interface DoneGetTestList {
+ public void doneGetTestList(IToken token, Throwable error, String[] list);
+ }
+
+ public IToken runTest(String s, DoneRunTest done);
+
+ public interface DoneRunTest {
+ public void doneRunTest(IToken token, Throwable error, String context_id);
+ }
+
+ public IToken cancelTest(String context_id, DoneCancelTest done);
+
+ public interface DoneCancelTest {
+ public void doneCancelTest(IToken token, Throwable error);
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, DoneGetSymbol done);
+
+ public interface DoneGetSymbol {
+ public void doneGetSymbol(IToken token, Throwable error, ISymbol symbol);
+ }
+
+ public interface ISymbol {
+ public String getSectionName();
+ public Number getValue();
+ public boolean isUndef();
+ public boolean isCommon();
+ public boolean isGlobal();
+ public boolean isLocal();
+ public boolean isAbs();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java
new file mode 100644
index 000000000..70213469b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java
@@ -0,0 +1,696 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * File System service provides file transfer (and more generally file
+ * system access) functionality in TCF. The service design is
+ * derived from SSH File Transfer Protocol specifications.
+ *
+ * Request Synchronization and Reordering
+ *
+ * The protocol and implementations MUST process requests relating to
+ * the same file in the order in which they are received. In other
+ * words, if an application submits multiple requests to the server, the
+ * results in the responses will be the same as if it had sent the
+ * requests one at a time and waited for the response in each case. For
+ * example, the server may process non-overlapping read/write requests
+ * to the same file in parallel, but overlapping reads and writes cannot
+ * be reordered or parallelized. However, there are no ordering
+ * restrictions on the server for processing requests from two different
+ * file transfer connections. The server may interleave and parallelize
+ * them at will.
+ *
+ * There are no restrictions on the order in which responses to
+ * outstanding requests are delivered to the client, except that the
+ * server must ensure fairness in the sense that processing of no
+ * request will be indefinitely delayed even if the client is sending
+ * other requests so that there are multiple outstanding requests all
+ * the time.
+ *
+ * There is no limit on the number of outstanding (non-acknowledged)
+ * requests that the client may send to the server. In practice this is
+ * limited by the buffering available on the data stream and the queuing
+ * performed by the server. If the server's queues are full, it should
+ * not read any more data from the stream, and flow control will prevent
+ * the client from sending more requests.
+ *
+ * File Names
+ *
+ * This protocol represents file names as strings. File names are
+ * assumed to use the slash ('/') character as a directory separator.
+ *
+ * File names starting with a slash are "absolute", and are relative to
+ * the root of the file system. Names starting with any other character
+ * are relative to the user's default directory (home directory). Client
+ * can use 'user()' command to retrieve current user home directory.
+ *
+ * Servers SHOULD interpret a path name component ".." as referring to
+ * the parent directory, and "." as referring to the current directory.
+ * If the server implementation limits access to certain parts of the
+ * file system, it must be extra careful in parsing file names when
+ * enforcing such restrictions. There have been numerous reported
+ * security bugs where a ".." in a path name has allowed access outside
+ * the intended area.
+ *
+ * An empty path name is valid, and it refers to the user's default
+ * directory (usually the user's home directory).
+ *
+ * Otherwise, no syntax is defined for file names by this specification.
+ * Clients should not make any other assumptions; however, they can
+ * splice path name components returned by readdir() together
+ * using a slash ('/') as the separator, and that will work as expected.
+ */
+public interface IFileSystem extends IService {
+
+ /**
+ * Service name.
+ */
+ static final String NAME = "FileSystem";
+
+ /**
+ * Flags to be used with open() method.
+ */
+ static final int
+
+ /**
+ * Open the file for reading.
+ */
+ O_READ = 0x00000001,
+
+ /**
+ * Open the file for writing. If both this and O_READ are
+ * specified, the file is opened for both reading and writing.
+ */
+ O_WRITE = 0x00000002,
+
+ /**
+ * Force all writes to append data at the end of the file.
+ */
+ O_APPEND = 0x00000004,
+
+ /**
+ * If this flag is specified, then a new file will be created if one
+ * does not already exist (if O_TRUNC is specified, the new file will
+ * be truncated to zero length if it previously exists).
+ */
+ O_CREAT = 0x00000008,
+
+ /**
+ * Forces an existing file with the same name to be truncated to zero
+ * length when creating a file by specifying O_CREAT.
+ * O_CREAT MUST also be specified if this flag is used.
+ */
+ O_TRUNC = 0x00000010,
+
+ /**
+ * Causes the request to fail if the named file already exists.
+ * O_CREAT MUST also be specified if this flag is used.
+ */
+ O_EXCL = 0x00000020;
+
+ /**
+ * Flags to be used together with FileAttrs.
+ * The flags specify which of the fields are present. Those fields
+ * for which the corresponding flag is not set are not present (not
+ * included in the message).
+ */
+ static final int
+ ATTR_SIZE = 0x00000001,
+ ATTR_UIDGID = 0x00000002,
+ ATTR_PERMISSIONS = 0x00000004,
+ ATTR_ACMODTIME = 0x00000008;
+
+ /**
+ * FileAttrs is used both when returning file attributes from
+ * the server and when sending file attributes to the server. When
+ * sending it to the server, the flags field specifies which attributes
+ * are included, and the server will use default values for the
+ * remaining attributes (or will not modify the values of remaining
+ * attributes). When receiving attributes from the server, the flags
+ * specify which attributes are included in the returned data. The
+ * server normally returns all attributes it knows about.
+ */
+ final static class FileAttrs {
+
+ /**
+ * The `flags' specify which of the fields are present.
+ */
+ public final int flags;
+
+ /**
+ * The `size' field specifies the size of the file in bytes.
+ */
+ public final long size;
+
+ /**
+ * The `uid' and `gid' fields contain numeric Unix-like user and group
+ * identifiers, respectively.
+ */
+ public final int uid;
+ public final int gid;
+
+ /**
+ * The `permissions' field contains a bit mask of file permissions as
+ * defined by posix [1].
+ */
+ public final int permissions;
+
+ /**
+ * The `atime' and `mtime' contain the access and modification times of
+ * the files, respectively. They are represented as milliseconds from
+ * midnight Jan 1, 1970 in UTC.
+ */
+ public final long atime;
+ public final long mtime;
+
+ /**
+ * Additional (non-standard) attributes.
+ */
+ public final Map<String,Object> attributes;
+
+ public FileAttrs(int flags, long size, int uid, int gid,
+ int permissions, long atime, long mtime, Map<String,Object> attributes) {
+ this.flags = flags;
+ this.size = size;
+ this.uid = uid;
+ this.gid = gid;
+ this.permissions = permissions;
+ this.atime = atime;
+ this.mtime = mtime;
+ this.attributes = attributes;
+ }
+
+ /**
+ * Determines if the file system object is a file on the remote file system.
+ *
+ * @return true if and only if the object on the remote system can be considered to have "contents" that
+ * have the potential to be read and written as a byte stream.
+ */
+ public boolean isFile() {
+ if ((flags & ATTR_PERMISSIONS) == 0) return false;
+ return (permissions & S_IFMT) == S_IFREG;
+ }
+
+ /**
+ * Determines if the file system object is a directory on the remote file system.
+ *
+ * @return true if and only if the object on the remote system is a directory.
+ * That is, it contains entries that can be interpreted as other files.
+ */
+ public boolean isDirectory() {
+ if ((flags & ATTR_PERMISSIONS) == 0) return false;
+ return (permissions & S_IFMT) == S_IFDIR;
+ }
+ }
+
+ /**
+ * The following flags are defined for the 'permissions' field:
+ */
+ static final int
+ S_IFMT = 0170000, // bitmask for the file type bitfields
+ S_IFSOCK = 0140000, // socket
+ S_IFLNK = 0120000, // symbolic link
+ S_IFREG = 0100000, // regular file
+ S_IFBLK = 0060000, // block device
+ S_IFDIR = 0040000, // directory
+ S_IFCHR = 0020000, // character device
+ S_IFIFO = 0010000, // fifo
+ S_ISUID = 0004000, // set UID bit
+ S_ISGID = 0002000, // set GID bit (see below)
+ S_ISVTX = 0001000, // sticky bit (see below)
+ S_IRWXU = 00700, // mask for file owner permissions
+ S_IRUSR = 00400, // owner has read permission
+ S_IWUSR = 00200, // owner has write permission
+ S_IXUSR = 00100, // owner has execute permission
+ S_IRWXG = 00070, // mask for group permissions
+ S_IRGRP = 00040, // group has read permission
+ S_IWGRP = 00020, // group has write permission
+ S_IXGRP = 00010, // group has execute permission
+ S_IRWXO = 00007, // mask for permissions for others (not in group)
+ S_IROTH = 00004, // others have read permission
+ S_IWOTH = 00002, // others have write permisson
+ S_IXOTH = 00001; // others have execute permission
+
+ final static class DirEntry {
+ /**
+ * `filename' is a file name being returned. It is a relative name within
+ * the directory, without any path components;
+ */
+ public final String filename;
+
+ /**
+ * `longname' is an expanded format for the file name, similar to what
+ * is returned by "ls -l" on Unix systems.
+ * The format of the `longname' field is unspecified by this protocol.
+ * It MUST be suitable for use in the output of a directory listing
+ * command (in fact, the recommended operation for a directory listing
+ * command is to simply display this data). However, clients SHOULD NOT
+ * attempt to parse the longname field for file attributes; they SHOULD
+ * use the attrs field instead.
+ */
+ public final String longname;
+
+ /**
+ * `attrs' is the attributes of the file.
+ */
+ public final FileAttrs attrs;
+
+ public DirEntry(String filename, String longname, FileAttrs attrs) {
+ this.filename = filename;
+ this.longname = longname;
+ this.attrs = attrs;
+ }
+ }
+
+ /**
+ * Opaque representation of open file handle.
+ * Note: open file handle can be used only with service instance that
+ * created the handle.
+ */
+ interface IFileHandle {
+ IFileSystem getService();
+ }
+
+ /**
+ * Status codes.
+ */
+ static final int
+
+ /**
+ * Indicates successful completion of the operation.
+ */
+ STATUS_OK = 0,
+
+ /**
+ * Indicates end-of-file condition; for read() it means that no
+ * more data is available in the file, and for readdir() it
+ * indicates that no more files are contained in the directory.
+ */
+ STATUS_EOF = 1,
+
+ /**
+ * This code is returned when a reference is made to a file which
+ * should exist but doesn't.
+ */
+ STATUS_NO_SUCH_FILE = 2,
+
+ /**
+ * is returned when the authenticated user does not have sufficient
+ * permissions to perform the operation.
+ */
+ STATUS_PERMISSION_DENIED = 3,
+
+ /**
+ * is a generic catch-all error message; it should be returned if an
+ * error occurs for which there is no more specific error code.
+ *
+ */
+ STATUS_FAILURE = 4,
+
+ /**
+ * may be returned if a badly formatted packet or protocol
+ * incompatibility is detected.
+ */
+ STATUS_BAD_MESSAGE = 5,
+
+ /**
+ * is a pseudo-error which indicates that the client has no
+ * connection to the server (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */
+ STATUS_NO_CONNECTION = 6,
+
+ /**
+ * is a pseudo-error which indicates that the connection to the
+ * server has been lost (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */
+ STATUS_CONNECTION_LOST = 7,
+
+ /**
+ * indicates that an attempt was made to perform an operation which
+ * is not supported for the server (it may be generated locally by
+ * the client if e.g. the version number exchange indicates that a
+ * required feature is not supported by the server, or it may be
+ * returned by the server if the server does not implement an
+ * operation).
+ */
+ STATUS_OP_UNSUPPORTED = 8;
+
+ abstract static class FileSystemException extends IOException {
+
+ protected FileSystemException(String message) {
+ super(message);
+ }
+
+ protected FileSystemException(Exception x) {
+ super(x.getMessage());
+ initCause(x);
+ }
+
+ public abstract int getStatus();
+ }
+
+ /**
+ * Open or create a file on a remote system.
+ *
+ * @param file_name specifies the file name. See 'File Names' for more information.
+ * @param flags is a bit mask of O_* flags.
+ * @param attrs specifies the initial attributes for the file.
+ * Default values will be used for those attributes that are not specified.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken open(String file_name, int flags, FileAttrs attrs, DoneOpen done);
+
+ interface DoneOpen {
+ void doneOpen(IToken token, FileSystemException error, IFileHandle handle);
+ }
+
+ /**
+ * Close a file on a remote system.
+ *
+ * @param handle is a handle previously returned in the response to
+ * open() or opendir().
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken close(IFileHandle handle, DoneClose done);
+
+ interface DoneClose {
+ void doneClose(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Read bytes from an open file.
+ * In response to this request, the server will read as many bytes as it
+ * can from the file (up to `len'), and return them in a byte array.
+ * If an error occurs or EOF is encountered, the server may return
+ * fewer bytes then requested. Call back method doneRead() argument 'error'
+ * will be not null in case of error, and argument 'eof' will be
+ * true in case of EOF. For normal disk files, it is guaranteed
+ * that this will read the specified number of bytes, or up to end of file
+ * or error. For e.g. device files this may return fewer bytes than requested.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start reading.
+ * @param len is the maximum number of bytes to read.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken read(IFileHandle handle, long offset, int len, DoneRead done);
+
+ interface DoneRead {
+ void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof);
+ }
+
+ /**
+ * Write bytes into an open file.
+ * The write will extend the file if writing beyond the end of the file.
+ * It is legal to write way beyond the end of the file; the semantics
+ * are to write zeroes from the end of the file to the specified offset
+ * and then the data.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start writing.
+ * @param data is byte array that contains data for writing.
+ * @param data_pos if offset in 'data' of first byte to write.
+ * @param data_size is the number of bytes to write.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken write(IFileHandle handle, long offset,
+ byte[] data, int data_pos, int data_size, DoneWrite done);
+
+ interface DoneWrite {
+ void doneWrite(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve file attributes.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken stat(String path, DoneStat done);
+
+ /**
+ * Retrieve file attributes.
+ * Unlike 'stat()', 'lstat()' does not follow symbolic links.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken lstat(String path, DoneStat done);
+
+ /**
+ * Retrieve file attributes for an open file (identified by the file handle).
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken fstat(IFileHandle handle, DoneStat done);
+
+ interface DoneStat {
+ void doneStat(IToken token, FileSystemException error, FileAttrs attrs);
+ }
+
+ /**
+ * Set file attributes.
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ * An error will be returned if the specified file system object does
+ * not exist or the user does not have sufficient rights to modify the
+ * specified attributes.
+ *
+ * @param path specifies the file system object (e.g. file or directory)
+ * whose attributes are to be modified.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken setstat(String path, FileAttrs attrs, DoneSetStat done);
+
+ /**
+ * Set file attributes for an open file (identified by the file handle).
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken fsetstat(IFileHandle handle, FileAttrs attrs, DoneSetStat done);
+
+ interface DoneSetStat {
+ void doneSetStat(IToken token, FileSystemException error);
+ }
+
+ /**
+ * The opendir() command opens a directory for reading.
+ * Once the directory has been successfully opened, files (and
+ * directories) contained in it can be listed using readdir() requests.
+ * When the client no longer wishes to read more names from the
+ * directory, it SHOULD call close() for the handle. The handle
+ * should be closed regardless of whether an error has occurred or not.
+
+ * @param path - name of the directory to be listed (without any trailing slash).
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken opendir(String path, DoneOpen done);
+
+ /**
+ * The files in a directory can be listed using the opendir() and
+ * readdir() requests. Each readdir() request returns one
+ * or more file names with full file attributes for each file. The
+ * client should call readdir() repeatedly until it has found the
+ * file it is looking for or until the server responds with a
+ * message indicating an error or end of file. The client should then
+ * close the handle using the close() request.
+ * Note: directory entries "." and ".." are NOT included into readdir()
+ * response.
+ * @param handle - file handle created by opendir()
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken readdir(IFileHandle handle, DoneReadDir done);
+
+ interface DoneReadDir {
+ void doneReadDir(IToken token, FileSystemException error, DirEntry[] entries, boolean eof);
+ }
+
+ /**
+ * Create a directory on the server.
+ *
+ * @param path - specifies the directory to be created.
+ * @param attrs - new directory attributes.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken mkdir(String path, FileAttrs attrs, DoneMkDir done);
+
+ interface DoneMkDir {
+ void doneMkDir(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Remove a directory.
+ * An error will be returned if no directory
+ * with the specified path exists, or if the specified directory is not
+ * empty, or if the path specified a file system object other than a
+ * directory.
+ *
+ * @param path - specifies the directory to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken rmdir(String path, DoneRemove done);
+
+ interface DoneRemove {
+ void doneRemove(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve file system roots - top level file system objects.
+ * UNIX file system can report just one root with path "/". Other types of systems
+ * can have more the one root. For example, Windows server can return multiple roots:
+ * one per disc (e.g. "/C:/", "/D:/", etc.). Note: even Windows implementation of
+ * the service must use forward slash as directory separator, and must start
+ * absolute path with "/". Server should implement proper translation of
+ * protocol file names to OS native names and back.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken roots(DoneRoots done);
+
+ interface DoneRoots {
+ void doneRoots(IToken token, FileSystemException error, DirEntry[] entries);
+ }
+
+ /**
+ * Remove a file or symbolic link.
+ * This request cannot be used to remove directories.
+ *
+ * @param file_name is the name of the file to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken remove(String file_name, DoneRemove done);
+
+ /**
+ * Canonicalize any given path name to an absolute path.
+ * This is useful for converting path names containing ".." components or
+ * relative pathnames without a leading slash into absolute paths.
+ *
+ * @param path specifies the path name to be canonicalized.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken realpath(String path, DoneRealPath done);
+
+ interface DoneRealPath {
+ void doneRealPath(IToken token, FileSystemException error, String path);
+ }
+
+ /**
+ * Rename a file.
+ * It is an error if there already exists a file
+ * with the name specified by 'new_path'. The server may also fail rename
+ * requests in other situations, for example if `old_path' and `new_path'
+ * point to different file systems on the server.
+ *
+ * @param old_path is the name of an existing file or directory.
+ * @param new_path is the new name for the file or directory.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken rename(String old_path, String new_path, DoneRename done);
+
+ interface DoneRename {
+ void doneRename(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Read the target of a symbolic link.
+ *
+ * @param path specifies the path name of the symbolic link to be read.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken readlink(String path, DoneReadLink done);
+
+ interface DoneReadLink {
+ void doneReadLink(IToken token, FileSystemException error, String path);
+ }
+
+ /**
+ * Create a symbolic link on the server.
+ *
+ * @param link_path specifies the path name of the symbolic link to be created.
+ * @param target_path specifies the target of the symbolic link.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken symlink(String link_path, String target_path, DoneSymLink done);
+
+ interface DoneSymLink {
+ void doneSymLink(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Copy a file on remote system.
+ *
+ * @param src_path specifies the path name of the file to be copied.
+ * @param dst_path specifies destination file name.
+ * @param copy_permissions - if true then copy source file permissions.
+ * @param copy_ownership - if true then copy source file UID and GID.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken copy(String src_path, String dst_path,
+ boolean copy_permissions, boolean copy_ownership, DoneCopy done);
+
+ interface DoneCopy {
+ void doneCopy(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve information about user account, which is used by server
+ * to access file system on behalf of the client.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken user(DoneUser done);
+
+ interface DoneUser {
+ void doneUser(IToken token, FileSystemException error,
+ int real_uid, int effective_uid, int real_gid, int effective_gid,
+ String home);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java
new file mode 100644
index 000000000..2547e6f1e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.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.tcf.api.services;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * Line numbers service associates locations in the source files with the corresponding
+ * machine instruction addresses in the executable object.
+ */
+public interface ILineNumbers extends IService {
+
+ static final String NAME = "LineNumbers";
+
+ /**
+ * TextArea represent a continues area in source text mapped to
+ * continues range of code addresses.
+ * Line and columns are counted starting from 0.
+ * File name can be relative path, in such case client should
+ * use TextArea directory name as origin for the path.
+ * File and directory names are valid on a host where code was compiled.
+ * It is client responsibility to map names to this host file system.
+ */
+ final class CodeArea {
+ public final String directory;
+ public final String file;
+ public final int start_line;
+ public final int start_column;
+ public final int end_line;
+ public final int end_column;
+ public final Number start_address;
+ public final Number end_address;
+ public final int isa;
+ public final boolean is_statement;
+ public final boolean basic_block;
+ public final boolean prologue_end;
+ public final boolean epilogue_begin;
+
+ public CodeArea(String directory, String file, int start_line, int start_column,
+ int end_line, int end_column, Number start_address, Number end_address, int isa,
+ boolean is_statement, boolean basic_block,
+ boolean prologue_end, boolean epilogue_begin) {
+ this.directory = directory;
+ this.file = file;
+ this.start_line = start_line;
+ this.start_column = start_column;
+ this.end_line = end_line;
+ this.end_column = end_column;
+ this.start_address = start_address;
+ this.end_address = end_address;
+ this.isa = isa;
+ this.is_statement = is_statement;
+ this.basic_block = basic_block;
+ this.prologue_end = prologue_end;
+ this.epilogue_begin = epilogue_begin;
+ }
+ }
+
+ IToken mapToSource(String context_id, Number start_address, Number end_address, DoneMapToSource done);
+
+ interface DoneMapToSource {
+ void doneMapToSource(IToken token, Exception error, CodeArea[] areas);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java
new file mode 100644
index 000000000..9116d9d7f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.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.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * ILocator service uses transport layer to search for peers and to collect data about
+ * peer’s attributes and capabilities (services). Discovery mechanism depends on transport protocol
+ * and is part of that protocol handler. Targets, known to other hosts, can be found through
+ * remote instances of ILocator service. Automatically discovered targets require no further
+ * configuration. Additional targets can be configured manually.
+ *
+ * Clients should use Protocol.getLocator() to obtain local instance of ILocator,
+ * then ILocator.getPeers() can be used to get list of available peers (hosts and targets).
+ */
+
+public interface ILocator extends IService {
+
+ static final String NAME = "Locator";
+
+ /**
+ * Auto-configuration command and response codes.
+ */
+ static final int
+ CONF_REQ_INFO = 1,
+ CONF_PEER_INFO = 2;
+
+ /**
+ * @return Locator service name: "Locator"
+ */
+ String getName();
+
+ /**
+ * Get map (ID -> IPeer) of available peers (hosts and targets).
+ * The method return cached (currently known to the framework) list of peers.
+ * The list is updated according to event received from transport layer
+ */
+ Map<String,IPeer> getPeers();
+
+ /**
+ * Redirect this service channel to given peer using this service as a proxy.
+ * @param peer_id - Peer ID.
+ */
+ IToken redirect(String peer_id, DoneRedirect done);
+
+ interface DoneRedirect {
+ void doneRedirect(IToken token, Exception error);
+ }
+
+ /**
+ * Call back after TCF messages sent to this target up to this moment are delivered.
+ * This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ IToken sync(DoneSync done);
+
+ interface DoneSync {
+ void doneSync(IToken token);
+ }
+
+ /**
+ * Add a listener for ILocator service events.
+ */
+ void addListener(LocatorListener listener);
+
+ /**
+ * Remove a listener for ILocator service events.
+ */
+ void removeListener(LocatorListener listener);
+
+ interface LocatorListener {
+ void peerAdded(IPeer peer);
+
+ void peerChanged(IPeer peer);
+
+ void peerRemoved(String id);
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java
new file mode 100644
index 000000000..0f01c4a95
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.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.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IMemory service provides basic operations to read/write memory on a target.
+ */
+public interface IMemory extends IService {
+
+ static final String NAME = "Memory";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_BIG_ENDIAN = "BigEndian",
+ PROP_ADDRESS_SIZE = "AddressSize";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, MemoryContext context);
+ }
+
+ /**
+ * Retrieve contexts available for memory commands.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Memory access mode:
+ * Carry on when some of the memory cannot be accessed and
+ * return MemoryError at the end if any of the bytes
+ * were not processed correctly.
+ */
+ final static int MODE_CONTINUEONERROR = 0x1;
+
+ /**
+ * Memory access mode:
+ * Verify result of memory operations (by reading and comparing).
+ */
+ final static int MODE_VERIFY = 0x2;
+
+ interface MemoryContext {
+
+ /**
+ * Retrieve context ID.
+ * Same as (String)getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Retrieve parent context ID.
+ * Same as (String)getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Retrieves process ID, if applicable.
+ * @return process system ID.
+ */
+ int getProcessID();
+
+ /**
+ * Retrieve memory endianess.
+ * @return true if memory id big-endian.
+ */
+ boolean isBigEndian();
+
+ /**
+ * Retrieve memory address size.
+ * @return number of bytes used to store memory address value.
+ */
+ int getAddressSize();
+
+ /**
+ * Retrieve context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Set target memory.
+ * If 'word_size' is 0 it means client does not care about word size.
+ */
+ IToken set(Number addr, int word_size, byte[] buf,
+ int offs, int size, int mode, DoneMemory done);
+
+ /**
+ * Read target memory.
+ */
+ IToken get(Number addr, int word_size, byte[] buf,
+ int offs, int size, int mode, DoneMemory done);
+
+ /**
+ * Fill target memory with given pattern.
+ * 'size' is number of bytes to fill.
+ */
+ IToken fill(Number addr, int word_size, byte[] value,
+ int size, int mode, DoneMemory done);
+ }
+
+ /**
+ * Client call back interface for set(), get() and fill() commands.
+ */
+ interface DoneMemory {
+ public void doneMemory(IToken token, MemoryError error);
+ }
+
+ class MemoryError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public MemoryError(String msg) {
+ super(msg);
+ }
+ }
+
+ /**
+ * ErrorOffset interface can be implemented by MemoryError object,
+ * which is returned by get, set and fill commands.
+ *
+ * get/set/fill () returns this exception when reading failed
+ * for some but not all bytes, and MODE_CONTINUEONERROR
+ * has been set in mode. (For example, when only part of the request
+ * translates to valid memory addresses.)
+ * Exception.getMessage can be used for generalized message of the
+ * possible reasons of partial memory operation.
+ */
+ interface ErrorOffset {
+
+ // Error may have per byte information
+ final static int
+ BYTE_VALID = 0x00,
+ BYTE_UNKNOWN = 0x01, // e.g. out of range
+ BYTE_INVALID = 0x02,
+ BYTE_CANNOT_READ = 0x04,
+ BYTE_CANNOT_WRITE = 0x08;
+
+ int getStatus(int offset);
+
+ /**
+ * Returns the detail message string about the
+ * byte associated with specified location.
+ * @return the detail error message string.
+ */
+ String getMessage(int offset);
+
+ }
+
+ /**
+ * Add memory service event listener.
+ * @param listener - event listener implementation.
+ */
+ void addListener(MemoryListener listener);
+
+ /**
+ * Remove memory service event listener.
+ * @param listener - event listener implementation.
+ */
+ void removeListener(MemoryListener listener);
+
+ /**
+ * Memory event listener is notified when memory context hierarchy
+ * changes, and when memory is modified by memory service commands.
+ */
+ interface MemoryListener {
+
+ /**
+ * Called when a new memory access context(s) is created.
+ */
+ void contextAdded(MemoryContext[] contexts);
+
+ /**
+ * Called when a memory access context(s) properties changed.
+ */
+ void contextChanged(MemoryContext[] contexts);
+
+ /**
+ * Called when memory access context(s) is removed.
+ */
+ void contextRemoved(String[] context_ids);
+
+ /**
+ * Called when target memory content was changed and clients
+ * need to update themselves. Clients, at least, should invalidate
+ * corresponding cached memory data.
+ * Not every change is notified - it is not possible,
+ * only those, which are not caused by normal execution of the debuggee.
+ * ‘addr’ and ‘size’ can be null if unknown.
+ */
+ void memoryChanged(String context_id, Number[] addr, long[] size);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java
new file mode 100644
index 000000000..531e8e57a
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IProcesses service provides access to the target OS's process
+ * information, allows to start and terminate a process, and allows
+ * to attach and detach a process for debugging. Debug services,
+ * like IMemory and IRunControl, require a process to be attached
+ * before they can access it.
+ */
+public interface IProcesses extends IService {
+
+ static final String NAME = "Processes";
+
+ /**
+ * Retrieve context info for given context ID.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * Context IDs are valid across TCF services, so it is allowed to issue
+ * 'IProcesses.getContext' command with a context that was obtained,
+ * for example, from Memory service.
+ * However, 'Processes.getContext' is supposed to return only process specific data,
+ * If the ID is not a process ID, 'IProcesses.getContext' may not return any
+ * useful information
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, ProcessContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, boolean attached_only, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Context property names.
+ */
+ static final String
+ /** The TCF context ID */
+ PROP_ID = "ID",
+
+ /** The TCF parent context ID */
+ PROP_PARENTID = "ParentID",
+
+ /** Is the context attached */
+ PROP_ATTACHED = "Attached",
+
+ /** Can terminate the context */
+ PROP_CAN_TERMINATE = "CanTerminate",
+
+ /** Process name. Client UI can show this name to a user */
+ PROP_NAME = "Name";
+
+ interface ProcessContext {
+
+ /**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get process name.
+ * Client UI can show this name to a user.
+ * Same as getProperties().get(“Name”)
+ */
+ String getName();
+
+ /**
+ * Utility method to read context property PROP_ATTACHED.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * @return value of PROP_ATTACHED.
+ */
+ boolean isAttached();
+
+ /**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * @return value of PROP_CAN_TERMINATE.
+ */
+ boolean canTerminate();
+
+ /**
+ * Get all available context properties.
+ * @return Map 'property name' -> 'property value'
+ */
+ Map<String, Object> getProperties();
+
+ /**
+ * Attach debugger to a process.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken attach(DoneCommand done);
+
+ /**
+ * Detach debugger from a process.
+ * Process execution will continue without debugger supervision.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken detach(DoneCommand done);
+
+ /**
+ * Terminate a process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken terminate(DoneCommand done);
+
+ /**
+ * Send a signal to a process.
+ * @param signal - signal ID.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken signal(int signal, DoneCommand done);
+ }
+
+ interface DoneCommand {
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Get default set of environment variables used to start a new process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken getEnvironment(DoneGetEnvironment done);
+
+ interface DoneGetEnvironment {
+ void doneGetEnvironment(IToken token, Exception error, Map<String,String> environment);
+ }
+
+ /**
+ * Start a new process on remote machine.
+ * @param directory - initial value of working directory for the process.
+ * @param file - process image file.
+ * @param command_line - command line arguments for the process.
+ * @param environment - map of environment variables for the process,
+ * if null then default set of environment variables will be used.
+ * @param attach - if true debugger should be attached to the process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken start(String directory, String file,
+ String[] command_line, Map<String,String> environment,
+ boolean attach, DoneStart done);
+
+ interface DoneStart {
+ void doneStart(IToken token, Exception error, ProcessContext process);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java
new file mode 100644
index 000000000..2cf4de1f4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java
@@ -0,0 +1,318 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IRegisters service provides access to target CPU register values and properties.
+ */
+public interface IRegisters extends IService {
+
+ static final String NAME = "Registers";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_DESCRIPTION = "Description",
+ PROP_FORMATS = "Formats",
+ PROP_READBLE = "Readable",
+ PROP_READ_ONCE = "ReadOnce",
+ PROP_WRITEABLE = "Writeable",
+ PROP_WRITE_ONCE = "WriteOnce",
+ PROP_SIDE_EFFECTS = "SideEffects",
+ PROP_VOLATILE = "Volatile",
+ PROP_FLOAT = "Float",
+ PROP_BIG_ENDIAN = "BigEndian",
+ PROP_LEFT_TO_RIGHT = "LeftToRight",
+ PROP_FIST_BIT = "FirstBit",
+ PROP_BITS = "Bits",
+ PROP_VALUES = "Values";
+
+ /**
+ * Standard known formats for register data.
+ */
+ static final String
+ FORMAT_BINARY = "Binary",
+ FORMAT_OCTAL = "Octal",
+ FORMAT_DECIMAL = "Decimal",
+ FORMAT_HEX = "Hex",
+ FORMAT_NATURAL = "Natural";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, RegistersContext context);
+ }
+
+ /**
+ * Retrieve contexts available for registers commands.
+ * A context corresponds to an execution thread, stack frame, registers group, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * RegistersContext objects represent register groups, registers and bit fields.
+ */
+ interface RegistersContext {
+ /**
+ * Get Context ID.
+ * @return context ID.
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * @return parent context ID.
+ */
+ String getParentID();
+
+ /**
+ * Get context (register, register group, bit field) name.
+ * @return context name.
+ */
+ String getName();
+
+ /**
+ * Get context description.
+ * @return context description.
+ */
+ String getDescription();
+
+ /**
+ * Get value formats available for register get/set commands.
+ * See FORMAT_* for knows format IDs definition.
+ * @return array of supported format IDs.
+ */
+ String[] getAvailableFormats();
+
+ /**
+ * Check if context value can be read.
+ * @return true if can read value of the context.
+ */
+ boolean isReadable();
+
+ /**
+ * Check if reading the context (register) destroys its current value -
+ * it can be read only once.
+ * @return true if read-once register.
+ */
+ boolean isReadOnce();
+
+ /**
+ * Check if context value can be written.
+ * @return true if can write value of the context.
+ */
+ boolean isWriteable();
+
+ /**
+ * Check if register value can not be overwritten - every write counts.
+ * @return true if write-once register.
+ */
+ boolean isWriteOnce();
+
+ /**
+ * Check if writing the context can change values of other registers.
+ * @return true if has side effects.
+ */
+ boolean hasSideEffects();
+
+ /**
+ * Check if the register value can change even when target is stopped.
+ * @return true if the register value can change at any time.
+ */
+ boolean isVolatile();
+
+ /**
+ * Check if the register value is a floating-point value.
+ * @return true if a floating-point register.
+ */
+ boolean isFloat();
+
+ /**
+ * Check endianess of the context.
+ * Big endian means decreasing numeric significance with increasing bit number.
+ * @return true if big endian.
+ */
+ boolean isBigEndian();
+
+ /**
+ * Check if the lowest numbered bit (i.e. bit #0 or bit #1 depending on
+ * getFirstBitNumber() value) should be shown to user as the left-most bit or
+ * the right-most bit.
+ * @return true if the first bit is left-most bit.
+ */
+ boolean isLeftToRight();
+
+ /**
+ * If the context has bit field children, bit positions of the fields
+ * can be zero-based or 1-based.
+ * @return first bit position - 0 or 1.
+ */
+ int getFirstBitNumber();
+
+ /**
+ * If context is a bit field, get the field bit numbers in parent context.
+ * @return array of bit numbers.
+ */
+ int[] getBitNumbers();
+
+ /**
+ * A context can have predefined names (mnemonics) for some its values.
+ * This method returns a list of such named values.
+ * @return array of named values or null.
+ */
+ NamedValue[] getNamedValues();
+
+ /**
+ * Get complete map of context properties.
+ * @return map of context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Read value of the context.
+ * @param format - ID of a format to use for result value.
+ * @param done - call back object.
+ * @return - pending command handle.
+ */
+ IToken get(String format, DoneGet done);
+
+ /**
+ * Set value of the context.
+ * @param format - ID of a format used for value.
+ * @param value - value to write into the context.
+ * @param done - call back object.
+ * @return - pending command handle.
+ */
+ IToken set(String format, String value, DoneSet done);
+ }
+
+ /**
+ * A register context can have predefined names (mnemonics) for some its values.
+ * NamedValue objects represent such values.
+ */
+ interface NamedValue {
+ /**
+ * Get number associated with this named value.
+ * @return the value as a number.
+ */
+ Number getValue();
+
+ /**
+ * Get name (mnemonic) of the value.
+ * @return value name.
+ */
+ String getName();
+
+ /**
+ * Get human readable description of the value.
+ * @return value description.
+ */
+ String getDescription();
+ }
+
+ /**
+ * 'get' command call back interface.
+ */
+ interface DoneGet {
+ void doneGet(IToken token, Exception error, String value);
+ }
+
+ /**
+ * 'set' command call back interface.
+ */
+ interface DoneSet {
+ void doneSet(IToken token, Exception error);
+ }
+
+ /**
+ * Add registers service event listener.
+ * @param listener - event listener implementation.
+ */
+ void addListener(RegistersListener listener);
+
+ /**
+ * Remove registers service event listener.
+ * @param listener - event listener implementation.
+ */
+ void removeListener(RegistersListener listener);
+
+ /**
+ * Registers event listener is notified when registers context hierarchy
+ * changes, and when a register is modified by the service commands.
+ */
+ interface RegistersListener {
+
+ /**
+ * Called when register context properties changed.
+ * Most targets have static set of registers and register properties.
+ * Such targets never generate this event. However, some targets,
+ * for example, JTAG probes, allow user to modify register definitions.
+ * Clients should flush all cached register context data.
+ */
+ void contextChanged();
+
+ /**
+ * Called when register content was changed and clients
+ * need to update themselves. Clients, at least, should invalidate
+ * corresponding cached registers data.
+ * Not every change is notified - it is not possible,
+ * only those, which are not caused by normal execution of the debuggee.
+ */
+ void registerChanged(String context_id);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java
new file mode 100644
index 000000000..fc8befbcc
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+public interface IRunControl extends IService {
+
+ static final String NAME = "RunControl";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_IS_CONTAINER = "IsContainer",
+ PROP_HAS_STATE = "HasState",
+ PROP_CAN_RESUME = "CanResume",
+ PROP_CAN_COUNT = "CanCount",
+ PROP_CAN_SUSPEND = "CanSuspend",
+ PROP_CAN_TERMINATE = "CanTerminate";
+
+ /**
+ * Context resume modes.
+ */
+ static final int
+ RM_RESUME = 0,
+ RM_STEP_OVER = 1,
+ RM_STEP_INTO = 2,
+ RM_STEP_OVER_LINE = 3,
+ RM_STEP_INTO_LINE = 4,
+ RM_STEP_OUT = 5;
+
+ /**
+ * State change reason of a context.
+ * Reason can be any text, but if it is one of predefined strings,
+ * a generic client might be able to handle it better.
+ */
+ static final String
+ REASON_USER_REQUEST = "Suspended",
+ REASON_STEP = "Step",
+ REASON_BREAKPOINT = "Breakpoint",
+ REASON_EXCEPTION = "Exception",
+ REASON_CONTAINER = "Container",
+ REASON_WATCHPOINT = "Watchpoint",
+ REASON_SIGNAL = "Signal",
+ REASON_SHAREDLIB = "Shared Library",
+ REASON_ERROR = "Error";
+
+ /**
+ * Retrieve context properties for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client callback interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, RunControlContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client callback interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */
+ interface RunControlContext {
+
+ /**
+ * Retrieve context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Retrieve parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get context properties. See PROP_* definitions for property names.
+ * Context properties are read only, clients should not try to modify them.
+ * @return Map of context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Utility method to read context property PROP_IS_CONTAINER.
+ * Executing resume or suspend command on a container causes all its children to resume or suspend.
+ * @return value of PROP_IS_CONTAINER.
+ */
+ boolean isContainer();
+
+ /**
+ * Utility method to read context property PROP_HAS_STATE.
+ * Only context that has a state can be resumed or suspended.
+ * @return value of PROP_HAS_STATE.
+ */
+ boolean hasState();
+
+ /**
+ * Utility method to read context property PROP_CAN_SUSPEND.
+ * Value 'true' means suspend command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already suspended.
+ * @return value of PROP_CAN_SUSPEND.
+ */
+ boolean canSuspend();
+
+ /**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_RESUME.
+ * Value 'true' means resume command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * @param mode - resume mode, see RM_*.
+ * @return value of requested bit of PROP_CAN_RESUME.
+ */
+ boolean canResume(int mode);
+
+ /**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_COUNT.
+ * Value 'true' means resume command with count other then 1 is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * @param mode - resume mode, see RM_*.
+ * @return value of requested bit of PROP_CAN_COUNT.
+ */
+ boolean canCount(int mode);
+
+ /**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * Value 'true' means terminate command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already exited.
+ * @return value of PROP_CAN_SUSPEND.
+ */
+ boolean canTerminate();
+
+ /**
+ * Send a command to retrieve current state of a context.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken getState(DoneGetState done);
+
+ /**
+ * Send a command to suspend a context.
+ * Also suspends children if context is a container.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken suspend(DoneCommand done);
+
+ /**
+ * Send a command to resume a context.
+ * Also resumes children if context is a container.
+ * @param mode - defines how to resume the context, see RM_*.
+ * @param count - if mode implies stepping, defines how many steps to perform.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken resume(int mode, int count, DoneCommand done);
+
+ /**
+ * Send a command to terminate a context.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken terminate(DoneCommand done);
+ }
+
+ class RunControlError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ interface DoneGetState {
+ void doneGetState(IToken token, Exception error, boolean suspended, String pc,
+ String reason, Map<String,Object> params);
+ }
+
+ interface DoneCommand {
+ /**
+ * Called when run control command execution is complete.
+ * @param token - pending command handle.
+ * @param error - command execution error or null.
+ */
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Add run control event listener.
+ * @param listener - run control event listener to add.
+ */
+ void addListener(RunControlListener listener);
+
+ /**
+ * Remove run control event listener.
+ * @param listener - run control event listener to remove.
+ */
+ void removeListener(RunControlListener listener);
+
+ /**
+ * Service events listener interface.
+ */
+ interface RunControlListener {
+
+ /**
+ * Called when new contexts are created.
+ * @param contexts - array of new context properties.
+ */
+ void contextAdded(RunControlContext contexts[]);
+
+ /**
+ * Called when a context properties changed.
+ * @param contexts - array of new context properties.
+ */
+ void contextChanged(RunControlContext contexts[]);
+
+ /**
+ * Called when contexts are removed.
+ * @param context_ids - aray of removed context IDs.
+ */
+ void contextRemoved(String context_ids[]);
+
+ /**
+ * Called when a thread is suspended.
+ * @param context - ID of a context that was suspended.
+ * @param pc - program counter of the context, can be null.
+ * @param reason - human readable description of suspend reason.
+ * @param params - additional, target specific data about suspended context.
+ */
+ void contextSuspended(String context, String pc,
+ String reason, Map<String,Object> params);
+
+ /**
+ * Called when a thread is resumed.
+ * @param context - ID of a context that was resumed.
+ */
+ void contextResumed(String context);
+
+ /**
+ * Called when target simultaneously suspends multiple threads in a container
+ * (process, core, etc.).
+ *
+ * @param context - ID of a context responsible for the event. It can be container ID or
+ * any one of container children, for example, it can be thread that hit "suspend all" breakpoint.
+ * Client expected to move focus (selection) to this context.
+ * @param pc - program counter of the context.
+ * @param reason - human readable description of suspend reason.
+ * @param params - additional target specific data about suspended context.
+ * @param suspended_ids - full list of all contexts that were suspended.
+ */
+ void containerSuspended(String context, String pc,
+ String reason, Map<String,Object> params, String[] suspended_ids);
+
+ /**
+ * Called when target simultaneously resumes multiple threads in a container (process,
+ * core, etc.).
+ *
+ * @param context_ids - full list of all contexts that were resumed.
+ */
+ void containerResumed(String[] context_ids);
+
+ /**
+ * Called when an exception is detected in a target thread.
+ * @param context - ID of a context that caused an exception.
+ * @param msg - human readable description of the exception.
+ */
+ void contextException(String context, String msg);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java
new file mode 100644
index 000000000..a3657bcab
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+public interface IStackTrace extends IService {
+
+ static final String NAME = "StackTrace";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_FRAME_ADDRESS = "FP",
+ PROP_RETURN_ADDRESS = "RP",
+ PROP_ARGUMENTS_COUNT = "ArgsCnt",
+ PROP_ARGUMENTS_ADDRESS = "ArgsAddr";
+
+ /**
+ * Retrieve context info for given context IDs.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * @param id – array of context IDs.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String[] id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – array of context data or null if error.
+ */
+ void doneGetContext(IToken token, Exception error, StackTraceContext[] context);
+ }
+
+ /**
+ * Retrieve stack trace context list.
+ * Parent context usually corresponds to an execution thread.
+ * Some targets have more then one stack. In such case children of a thread
+ * are stacks, and stack frames are deeper in the hierarchy - they can be
+ * retrieved with additional getChildren commands.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * @param parent_context_id – parent context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ * Stack frames are ordered from stack bottom to top.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * StackTraceContext represents stack trace objects - stacks and stack frames.
+ */
+ interface StackTraceContext {
+
+ /**
+ * Get Context ID.
+ * @return context ID.
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * @return parent context ID.
+ */
+ String getParentID();
+
+ /**
+ * Get context name - if context represents a stack.
+ * @return context name or null.
+ */
+ String getName();
+
+ /**
+ * Get memory address of this frame.
+ * @return address or null if not a stack frame.
+ */
+ Number getFrameAddress();
+
+ /**
+ * Get program counter saved in this stack frame -
+ * it is address of instruction to be executed when the function returns.
+ * @return return address or null if not a stack frame.
+ */
+ Number getReturnAddress();
+
+ /**
+ * Get number of function arguments for this frame.
+ * @return function arguments count.
+ */
+ int getArgumentsCount();
+
+ /**
+ * Get address of function arguments area in memory.
+ * @return function arguments address or null if not available.
+ */
+ Number getArgumentsAddress();
+
+ /**
+ * Get complete map of context properties.
+ * @return map of context properties.
+ */
+ Map<String,Object> getProperties();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java
new file mode 100644
index 000000000..f154c9c0e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java
@@ -0,0 +1,378 @@
+/*******************************************************************************
+ * 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.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * This is optional service that can be implemented by a peer.
+ * If implemented, the service can be used for monitoring system activity and utilization.
+ * It provides list of running processes, different process attributes like command line, environment, etc.,
+ * and some resource utilization data. The service can be used by a client to provide functionality
+ * similar to Unix 'top' utility or Windows 'Task Manager'.
+ */
+public interface ISysMonitor extends IService {
+
+ static final String NAME = "SysMonitor";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client callback interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, SysMonitorContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client callback interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Context property names.
+ */
+ static final String
+ /** The TCF context ID */
+ PROP_ID = "ID",
+
+ /** The TCF parent context ID */
+ PROP_PARENTID = "ParentID",
+
+ /** Current working directory of the process */
+ PROP_CWD = "CWD",
+
+ /** The process's root directory (as set by chroot) */
+ PROP_ROOT = "Root",
+
+ /** User ID of the process owner */
+ PROP_UID = "UID",
+
+ /** Group ID of the process owner */
+ PROP_UGID = "UGID",
+
+ /** User name of the process owner */
+ PROP_USERNAME = "UserName",
+
+ /** Group name of the process owner */
+ PROP_GROUPNAME = "GroupName",
+
+ /** System process ID */
+ PROP_PID = "PID",
+
+ /** Executable file of the process */
+ PROP_FILE = "File",
+
+ /** One character from the string "RSDZTW" where R is running, S is
+ * sleeping in an interruptible wait, D is waiting in uninterruptible
+ * disk sleep, Z is zombie, T is traced or stopped (on a signal), and W
+ * is paging.*/
+ PROP_STATE = "State",
+
+ /** System ID of the parent process */
+ PROP_PPID = "PPID",
+
+ /** The process group ID of the process */
+ PROP_PGRP = "PGRP",
+
+ /** The session ID of the process */
+ PROP_SESSION = "Session",
+
+ /** The tty the process uses */
+ PROP_TTY = "TTY",
+
+ /** The process group ID of the process which currently owns the tty that
+ * the process is connected to. */
+ PROP_TGID = "TGID",
+
+ /** ID of a process that has attached this process for tracing or debugging */
+ PROP_TRACERPID = "TracerPID",
+
+ /** The kernel flags word of the process. Details depend on the kernel */
+ PROP_FLAGS = "Flags",
+
+ /** The number of minor faults the process has made which have not
+ * required loading a memory page from disk */
+ PROP_MINFLT = "MinFlt",
+
+ /** The number of minor faults that the process's waited-for children have made */
+ PROP_CMINFLT = "CMinFlt",
+
+ /** The number of major faults the process has made which have required
+ * loading a memory page from disk */
+ PROP_MAJFLT = "MajFlt",
+
+ /** The number of major faults that the process's waited-for children
+ * have made */
+ PROP_CMAJFLT = "CMajFlt",
+
+ /** The number of milliseconds that this process has been scheduled in user mode */
+ PROP_UTIME = "UTime",
+
+ /** The number of milliseconds that this process has been scheduled in kernel mode */
+ PROP_STIME = "STime",
+
+ /** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */
+ PROP_CUTIME = "CUTime",
+
+ /** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */
+ PROP_CSTIME = "CSTime",
+
+ /** The standard nice value */
+ PROP_PRIORITY = "Priority",
+
+ /** The nice value */
+ PROP_NICE = "Nice",
+
+ /** The time in milliseconds before the next SIGALRM is sent to the process
+ * due to an interval timer */
+ PROP_ITREALVALUE = "ITRealValue",
+
+ /** The time in milliseconds the process started after system boot */
+ PROP_STARTTIME = "StartTime",
+
+ /** Virtual memory size in bytes */
+ PROP_VSIZE = "VSize",
+
+ /** Memory pages size in bytes */
+ PROP_PSIZE = "PSize",
+
+ /** Resident Set Size: number of pages the process has in real memory,
+ * minus used for administrative purposes. This is just the pages which
+ * count towards text, data, or stack space. This does not include
+ * pages which have not been demand-loaded in, or which are swapped out */
+ PROP_RSS = "RSS",
+
+ /** Current limit in bytes on the rss of the process */
+ PROP_RLIMIT = "RLimit",
+
+ /** The address above which program text can run */
+ PROP_CODESTART = "CodeStart",
+
+ /** The address below which program text can run */
+ PROP_CODEEND = "CodeEnd",
+
+ /** The address of the start of the stack */
+ PROP_STACKSTART = "StackStart",
+
+ /** The bitmap of pending signals */
+ PROP_SIGNALS = "Signals",
+
+ /** The bitmap of blocked signals */
+ PROP_SIGBLOCK = "SigBlock",
+
+ /** The bitmap of ignored signals */
+ PROP_SIGIGNORE = "SigIgnore",
+
+ /** The bitmap of caught signals */
+ PROP_SIGCATCH = "SigCatch",
+
+ /** This is the "channel" in which the process is waiting. It is the
+ * address of a system call, and can be looked up in a name list if you
+ * need a textual name */
+ PROP_WCHAN = "WChan",
+
+ /** Number of pages swapped */
+ PROP_NSWAP = "NSwap",
+
+ /** Cumulative NSwap for child processes */
+ PROP_CNSWAP = "CNSwap",
+
+ /** Signal to be sent to parent when this process exits */
+ PROP_EXITSIGNAL = "ExitSignal",
+
+ /** CPU number last executed on */
+ PROP_PROCESSOR = "Processor",
+
+ /** Real-time scheduling priority */
+ PROP_RTPRIORITY = "RTPriority",
+
+ /** Scheduling policy */
+ PROP_POLICY = "Policy";
+
+
+ /**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */
+ interface SysMonitorContext {
+
+ /**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get process group ID.
+ * Same as getProperties().get(“PGRP”)
+ */
+ long getPGRP();
+
+ /**
+ * Get process ID.
+ * Same as getProperties().get(“PID”)
+ */
+ long getPID();
+
+ /**
+ * Get process parent ID.
+ * Same as getProperties().get(“PPID”)
+ */
+ long getPPID();
+
+ /**
+ * Get process TTY group ID.
+ * Same as getProperties().get(“TGID”)
+ */
+ long getTGID();
+
+ /**
+ * Get tracer process ID.
+ * Same as getProperties().get(“TracerPID”)
+ */
+ long getTracerPID();
+
+ /**
+ * Get process owner user ID.
+ * Same as getProperties().get(“UID”)
+ */
+ long getUID();
+
+ /**
+ * Get process owner user name.
+ * Same as getProperties().get(“UserName”)
+ */
+ String getUserName();
+
+ /**
+ * Get process owner user group ID.
+ * Same as getProperties().get(“UGID”)
+ */
+ long getUGID();
+
+ /**
+ * Get process owner user group name.
+ * Same as getProperties().get(“GroupName”)
+ */
+ String getGroupName();
+
+ /**
+ * Get process state.
+ * Same as getProperties().get(“State”)
+ */
+ String getState();
+
+ /**
+ * Get process virtual memory size in bytes.
+ * Same as getProperties().get(“VSize”)
+ */
+ long getVSize();
+
+ /**
+ * Get process virtual memory page size in bytes.
+ * Same as getProperties().get(“PSize”)
+ */
+ long getPSize();
+
+ /**
+ * Get number of memory pages in process resident set.
+ * Same as getProperties().get(“RSS”)
+ */
+ long getRSS();
+
+ /**
+ * Get context executable file.
+ * Same as getProperties().get(“File”)
+ */
+ String getFile();
+
+ /**
+ * Get context current file system root.
+ * Same as getProperties().get(“Root”)
+ */
+ String getRoot();
+
+ /**
+ * Get context current working directory.
+ * Same as getProperties().get(“CWD”)
+ */
+ String getCurrentWorkingDirectory();
+
+ /**
+ * Get all available context properties.
+ * @return Map 'property name' -> 'property value'
+ */
+ Map<String,Object> getProperties();
+ }
+
+ /**
+ * Get context command line.
+ */
+ IToken getCommandLine(String id, DoneGetCommandLine done);
+
+ interface DoneGetCommandLine {
+ void doneGetCommandLine(IToken token, Exception error, String[] cmd_line);
+ }
+
+ /**
+ * Get context environment variables.
+ */
+ IToken getEnvironment(String id, DoneGetEnvironment done);
+
+ interface DoneGetEnvironment {
+ void doneGetEnvironment(IToken token, Exception error, String[] environment);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java
new file mode 100644
index 000000000..da81ce5e0
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+
+/**
+ * TCFFileInputStream is high performance InputStream implementation over TCF FileSystem service.
+ * The class uses read-ahead buffers to achieve maximum throughput.
+ */
+public final class TCFFileInputStream extends InputStream {
+
+ private static final int BUF_SIZE = 0x1000;
+ private static final int MAX_READ_AHEAD = 8;
+
+ private static class Buffer {
+
+ final long seq;
+
+ IToken token;
+ byte[] buf;
+ boolean eof;
+
+ Buffer(long seq) {
+ this.seq = seq;
+ }
+ }
+
+ private final IFileHandle handle;
+ private long mark = 0;
+ private Buffer buf;
+ private int buf_pos = 0;
+ private long buf_seq = 0;
+ private boolean closed = false;
+
+ private boolean suspend_read_ahead;
+ private Runnable waiting_client;
+ private final LinkedList<Buffer> read_ahead_buffers = new LinkedList<Buffer>();
+
+ public TCFFileInputStream(IFileHandle handle) {
+ this.handle = handle;
+ }
+
+ private void startReadAhead(Buffer prv) {
+ if (prv.eof) return;
+ if (suspend_read_ahead) return;
+ if (read_ahead_buffers.size() > 0) {
+ prv = read_ahead_buffers.getLast();
+ if (prv.eof) return;
+ }
+ long seq = prv.seq + 1;
+ while (read_ahead_buffers.size() < MAX_READ_AHEAD) {
+ final Buffer buf = new Buffer(seq);
+ IFileSystem fs = handle.getService();
+ buf.token = fs.read(handle, buf.seq * BUF_SIZE, BUF_SIZE, new IFileSystem.DoneRead() {
+ public void doneRead(IToken token, FileSystemException error,
+ byte[] data, boolean eof) {
+ assert buf.token == token;
+ assert read_ahead_buffers.contains(buf);
+ buf.token = null;
+ if (error == null) {
+ assert data != null && data.length <= BUF_SIZE;
+ assert eof || data.length == BUF_SIZE;
+ buf.buf = data;
+ buf.eof = eof;
+ startReadAhead(buf);
+ }
+ else {
+ suspend_read_ahead = true;
+ read_ahead_buffers.remove(buf);
+ }
+ if (waiting_client != null) {
+ Protocol.invokeLater(waiting_client);
+ waiting_client = null;
+ }
+ }
+ });
+ read_ahead_buffers.add(buf);
+ seq++;
+ }
+ }
+
+ private boolean stopReadAhead(Runnable done) {
+ suspend_read_ahead = true;
+ for (Iterator<Buffer> i = read_ahead_buffers.iterator(); i.hasNext();) {
+ Buffer buf = i.next();
+ if (buf.token == null || buf.token.cancel()) i.remove();
+ }
+ if (read_ahead_buffers.size() > 0) {
+ assert waiting_client == null;
+ waiting_client = done;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public synchronized int read() throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ while (buf == null || buf_pos >= buf.buf.length) {
+ if (buf != null && buf.eof) return -1;
+ long offset = buf_seq * BUF_SIZE + buf_pos;
+ buf_seq = offset / BUF_SIZE;
+ buf_pos = (int)(offset % BUF_SIZE);
+ buf = new TCFTask<Buffer>() {
+ public void run() {
+ assert waiting_client == null;
+ while (read_ahead_buffers.size() > 0) {
+ Buffer buf = read_ahead_buffers.getFirst();
+ if (buf.seq == buf_seq) {
+ if (buf.token != null) {
+ waiting_client = this;
+ }
+ else {
+ read_ahead_buffers.remove(buf);
+ startReadAhead(buf);
+ done(buf);
+ }
+ return;
+ }
+ suspend_read_ahead = true;
+ if (buf.token != null && buf.token.cancel()) buf.token = null;
+ if (buf.token != null) {
+ waiting_client = this;
+ return;
+ }
+ read_ahead_buffers.remove(buf);
+ }
+ IFileSystem fs = handle.getService();
+ fs.read(handle, buf_seq * BUF_SIZE, BUF_SIZE, new IFileSystem.DoneRead() {
+ public void doneRead(IToken token, FileSystemException error,
+ byte[] data, boolean eof) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ assert data != null && data.length <= BUF_SIZE;
+ assert eof || data.length == BUF_SIZE;
+ Buffer buf = new Buffer(buf_seq);
+ buf.buf = data;
+ buf.eof = eof;
+ if (!eof) {
+ suspend_read_ahead = false;
+ startReadAhead(buf);
+ }
+ done(buf);
+ }
+ });
+ }
+ }.getIO();
+ assert buf.token == null;
+ assert buf.eof || buf.buf.length == BUF_SIZE;
+ }
+ assert buf.seq == buf_seq;
+ return buf.buf[buf_pos++] & 0xff;
+ }
+
+ @Override
+ public synchronized int read(final byte arr[], final int off, final int len) throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ if (arr == null) throw new NullPointerException();
+ if (off < 0 || len < 0 || len > arr.length - off) throw new IndexOutOfBoundsException();
+ int pos = 0;
+ while (pos < len) {
+ if (buf != null && buf_pos < buf.buf.length) {
+ int buf_len = buf.buf.length;
+ int n = len - pos < buf_len - buf_pos ? len - pos : buf_len - buf_pos;
+ System.arraycopy(buf.buf, buf_pos, arr, off + pos, n);
+ pos += n;
+ buf_pos += n;
+ }
+ else {
+ int c = read();
+ if (c == -1) {
+ if (pos == 0) return -1;
+ break;
+ }
+ arr[off + pos++] = (byte)c;
+ }
+ }
+ return pos;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ new TCFTask<Object>() {
+ public void run() {
+ if (!stopReadAhead(this)) return;
+ done(this);
+ }
+ }.getIO();
+ buf_seq = mark / BUF_SIZE;
+ buf_pos = (int)(mark % BUF_SIZE);
+ if (buf != null && buf.seq != buf_seq) buf = null;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ mark = buf_seq * BUF_SIZE + buf_pos;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (closed) return;
+ new TCFTask<Object>() {
+ public void run() {
+ if (!stopReadAhead(this)) return;
+ assert read_ahead_buffers.isEmpty();
+ IFileSystem fs = handle.getService();
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(this);
+ }
+ });
+ }
+ }.getIO();
+ closed = true;
+ buf_seq = 0;
+ buf_pos = 0;
+ buf = null;
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java
new file mode 100644
index 000000000..486e119e6
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+
+/**
+ * TCFFileOutputStream is high performance OutputStream implementation over TCF FileSystem service.
+ * The class uses write-back buffers to achieve maximum throughput.
+ */
+public final class TCFFileOutputStream extends OutputStream {
+
+ private static final int BUF_SIZE = 0x1000;
+ private static final int MAX_WRITE_BACK = 8;
+
+ private final IFileHandle handle;
+ private final Set<IToken> write_commands = new HashSet<IToken>();
+ private final int[] dirty = new int[1];
+ private final byte[] buf = new byte[BUF_SIZE];
+ private int buf_pos = 0;
+ private long offset = 0;
+ private IOException flush_error;
+ private boolean closed;
+
+ public TCFFileOutputStream(IFileHandle handle) {
+ this.handle = handle;
+ }
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ if (buf_pos == BUF_SIZE) flush();
+ buf[buf_pos++] = (byte)b;
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ if (len == 0) return;
+ if (b == null) throw new NullPointerException();
+ if (off < 0 || off > b.length || len < 0 ||
+ off + len > b.length || off + len < 0)
+ throw new IndexOutOfBoundsException();
+ while (len > 0) {
+ if (buf_pos == BUF_SIZE) flush();
+ if (buf_pos == 0 && len > BUF_SIZE) {
+ flush(b, off, len);
+ return;
+ }
+ int n = BUF_SIZE - buf_pos;
+ if (len < n) n = len;
+ System.arraycopy(b, off, buf, buf_pos, n);
+ off += n;
+ len -= n;
+ buf_pos += n;
+ }
+ }
+
+ @Override
+ public synchronized void flush() throws IOException {
+ if (buf_pos == 0) return;
+ flush(buf, 0, buf_pos);
+ buf_pos = 0;
+ }
+
+ private void flush(final byte[] buf, final int off, final int len) throws IOException {
+ synchronized (dirty) {
+ if (flush_error != null) throw flush_error;
+ while (dirty[0] >= MAX_WRITE_BACK) {
+ try {
+ dirty.wait();
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ new TCFTask<Object>() {
+ public void run() {
+ IFileSystem fs = handle.getService();
+ write_commands.add(fs.write(handle, offset, buf, off, len, new IFileSystem.DoneWrite() {
+ public void doneWrite(IToken token, FileSystemException error) {
+ assert write_commands.contains(token);
+ write_commands.remove(token);
+ if (error != null) {
+ for (Iterator<IToken> i = write_commands.iterator(); i.hasNext();) {
+ if (i.next().cancel()) i.remove();
+ }
+ }
+ synchronized (dirty) {
+ if (error != null && flush_error == null) flush_error = error;
+ dirty[0] = write_commands.size();
+ dirty.notifyAll();
+ }
+ }
+ }));
+ synchronized (dirty) {
+ dirty[0] = write_commands.size();
+ }
+ done(this);
+ }
+ }.getIO();
+ offset += len;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (closed) return;
+ flush();
+ synchronized (dirty) {
+ while (dirty[0] > 0) {
+ try {
+ dirty.wait();
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ new TCFTask<Object>() {
+ public void run() {
+ IFileSystem fs = handle.getService();
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(this);
+ }
+ });
+ }
+ }.getIO();
+ closed = true;
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java
new file mode 100644
index 000000000..abda52d02
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * 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.util;
+
+import java.io.IOException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class TCFTask<V> implements Runnable, Future<V> {
+
+ private V result;
+ private Throwable error;
+ private boolean canceled;
+
+ public TCFTask() {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ TCFTask.this.run();
+ }
+ catch (Throwable x) {
+ if (result == null && error == null) error(x);
+ }
+ }
+ });
+ }
+
+ public synchronized void done(V result) {
+ if (canceled) return;
+ assert Protocol.isDispatchThread();
+ assert this.error == null;
+ assert this.result == null;
+ this.result = result;
+ notifyAll();
+ }
+
+ public synchronized void error(Throwable error) {
+ assert Protocol.isDispatchThread();
+ if (canceled) return;
+ assert this.error == null;
+ assert this.result == null;
+ this.error = error;
+ //System.err.print("TCFTask exception: ");
+ //error.printStackTrace();
+ notifyAll();
+ }
+
+ public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+ if (isDone()) return false;
+ canceled = true;
+ error = new CancellationException();
+ notifyAll();
+ return true;
+ }
+
+ public V get() throws InterruptedException, ExecutionException {
+ assert !Protocol.isDispatchThread();
+ synchronized (this) {
+ if (!isDone()) wait();
+ if (error instanceof ExecutionException) throw (ExecutionException)error;
+ if (error instanceof InterruptedException) throw (InterruptedException)error;
+ if (error != null) throw new ExecutionException(error);
+ return result;
+ }
+ }
+
+ public V getE() {
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof Error) throw (Error)e;
+ throw new Error(e);
+ }
+ }
+
+ public V getIO() throws IOException {
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof IOException) throw (IOException)e;
+ IOException y = new IOException();
+ y.initCause(e);
+ throw y;
+ }
+ }
+
+ public synchronized V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ unit.toNanos(timeout);
+ // TODO Auto-generated method stub
+ assert false;
+ return null;
+ }
+
+ public synchronized boolean isCancelled() {
+ return canceled;
+ }
+
+ public synchronized boolean isDone() {
+ return canceled || error != null || result != null;
+ }
+}

Back to the top