Revision: 7834
Author: j...@google.com
Date: Wed Mar 31 20:30:31 2010
Log: Initial work on adding pluggable transports on the Java side, adding
prebuilt binaries for Linux JNI code, build changes.

http://code.google.com/p/google-web-toolkit/source/detail?r=7834

Added:
/changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/DefaultTransport.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransport.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransportTestServer.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/SocketTransport.java
 /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/Transport.java
/changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/TransportFactory.java
 /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86.so
 /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86_64.so
Modified:
/changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java
 /changes/jat/csproto/distro-source/build.xml
 /changes/jat/csproto/jni/build.xml
 /changes/jat/csproto/jni/linux/Makefile

=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/DefaultTransport.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.util.tools.Utility;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Default transport implementation over regular streams, which it buffers.
+ */
+public class DefaultTransport implements Transport {
+
+  private final InputStream istr;
+  private final OutputStream ostr;
+
+  public DefaultTransport(InputStream istr, OutputStream ostr) {
+    this.istr = new BufferedInputStream(istr);
+    this.ostr = new BufferedOutputStream(ostr);
+  }
+
+  public boolean beginReadMessage() {
+    return true;
+  }
+
+  public boolean beginWriteMessage() {
+    return true;
+  }
+
+  public void closeChannel() {
+    Utility.close(istr);
+    Utility.close(ostr);
+  }
+
+  public void endReadMessage() {
+  }
+
+  public void endWriteMessage() {
+    try {
+      getOutputStream().flush();
+    } catch (IOException e) {
+      // silently ignore, will get caught later
+    }
+  }
+
+  public InputStream getInputStream() {
+    return istr;
+  }
+
+  public OutputStream getOutputStream() {
+    return ostr;
+  }
+}
=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransport.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.MappedByteBuffer;
+
+/**
+ * Transport that uses shared memory and Futexes for communication between the
+ * browser and the server.
+ */
+public class ShmFutexTransport implements Transport {
+
+  /**
+   * InputStream for the server side of the shm+futex transport.
+   */
+  private class ShmFutexInputStream extends InputStream {
+
+    public boolean beginRead() {
+      boolean success = false;
+      // HACK: retry for a while, need to handle fragmentation
+      for (int i = 0; i < 100; ++i) {
+        success = nativeBeginServerRead(shmFutexAddr);
+        if (success) {
+          break;
+        }
+      }
+      if (success) {
+        clientToServerBuf.position(0);
+      } else {
+        // make sure any accesses fail if we didn't lock the buffer
+        clientToServerBuf.limit(0);
+      }
+      return success;
+    }
+
+    public void endRead() {
+      nativeEndServerRead(shmFutexAddr);
+      if (!readMessage) {
+        readMessage = true;
+        removeKey();
+      }
+    }
+
+    @Override
+    public int read() {
+      try {
+        return clientToServerBuf.get();
+      } catch (BufferUnderflowException e) {
+        return -1;
+      }
+    }
+  }
+
+  /**
+   * OutputStream for the server side of the shm+futex transport.
+   */
+  private class ShmFutexOutputStream extends OutputStream {
+
+    public boolean beginWrite() {
+      boolean success = false;
+      // HACK: retry for a while, need to handle fragmentation
+      for (int i = 0; i < 100; ++i) {
+        success = nativeBeginServerWrite(shmFutexAddr);
+        if (success) {
+          break;
+        }
+      }
+      if (success) {
+        serverToClientBuf.position(0);
+      } else {
+        // make sure any accesses fail if we didn't lock the buffer
+        serverToClientBuf.limit(0);
+      }
+      return success;
+    }
+
+    public void endWrite() {
+      try {
+        flush();
+      } catch (IOException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+        throw new RuntimeException(e);
+      }
+      nativeEndServerWrite(shmFutexAddr);
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+      try {
+        serverToClientBuf.put((byte) b);
+      } catch (BufferOverflowException e) {
+        throw new IOException(e);
+      }
+    }
+  }
+
+  /**
+   * Connect to an existing ShmFutex channel.
+   *
+   * @param key shm key of segment, provided by a previous
+   *     {...@link #createNewChannel} call
+   * @return a ShmFutexTransport instance, or null on an error
+   */
+  public static ShmFutexTransport connectToChannel(String key) {
+    long shmFutexAddr = nativeConnect(key);
+    if (shmFutexAddr == 0) {
+      return null;
+    }
+    return new ShmFutexTransport(shmFutexAddr, key);
+  }
+
+  /**
+   * Connect to an existing ShmFutex channel.
+   *
+ * @param outputKey output array of a single String element, which will get
+   *     the shm key of segment to be used with a later
+   *     {...@link #connectToChannel} call
+   * @return a ShmFutexTransport instance, or null on an error
+   */
+  public static ShmFutexTransport createNewChannel(String[] outputKey) {
+    if (outputKey.length != 1) {
+      throw new IllegalArgumentException(
+          "Expected 1-element array for returned argument value");
+    }
+    long shmFutexAddr = nativeCreate(outputKey);
+    if (shmFutexAddr == 0) {
+      return null;
+    }
+ ShmFutexTransport shm = new ShmFutexTransport(shmFutexAddr, outputKey[0]);
+    shm.ownsShm = true;
+    return shm;
+  }
+
+  /**
+   * Wait until we have a full server->client buffer.
+   *
+   * @return true on success
+   */
+  @SuppressWarnings("unused")
+  private static native boolean nativeBeginClientRead(long shmFutexAddr);
+
+  /**
+   * Wait until we have an empty client->server buffer.
+   *
+   * @return true on success
+   */
+  @SuppressWarnings("unused")
+  private static native boolean nativeBeginClientWrite(long shmFutexAddr);
+
+  /**
+   * Wait until we have a full client->server buffer.
+   *
+   * @return true on success
+   */
+  private static native boolean nativeBeginServerRead(long shmFutexAddr);
+
+  /**
+   * Wait until we have an empty server->client buffer.
+   *
+   * @return true on success
+   */
+  private static native boolean nativeBeginServerWrite(long shmFutexAddr);
+
+  /**
+   * Initialize Shm + Futex channel, setting all the fields.
+   *
+   * @param key SHM key of existing shared memory segment
+   * @return the address of a native object, or 0 on error
+   */
+  private static native long nativeConnect(String key);
+
+  /**
+   * Initialize Shm + Futex channel, setting all the fields.
+   *
+ * @param outputKey an array used to return the argument to use for a later
+   *     nativeConnect call in another process/thread
+   * @return the address of a native object, or 0 on error
+   */
+  private static native long nativeCreate(String[] outputKey);
+
+  /**
+   * Indicate we are done with the server->client buffer contents.
+   */
+  @SuppressWarnings("unused")
+  private static native void nativeEndClientRead(long shmFutexAddr);
+
+  /**
+   * Indicate we have filled the client->server buffer contents.
+   */
+  @SuppressWarnings("unused")
+  private static native void nativeEndClientWrite(long shmFutexAddr);
+
+  /**
+   * Indicate we are done with the client->server buffer contents.
+   */
+  private static native void nativeEndServerRead(long shmFutexAddr);
+
+  /**
+   * Indicate we have filled the server->client buffer contents.
+   */
+  private static native void nativeEndServerWrite(long shmFutexAddr);
+
+  private static native MappedByteBuffer nativeGetClientToServerBuf(
+      long shmFutexAddr);
+
+  private static native MappedByteBuffer nativeGetServerToClientBuf(
+      long shmFutexAddr);
+
+  /**
+   * Remove the shm key (existing mappings will keep the segment around
+   * until they are detached).
+   *
+   * @param key
+   */
+  private static native void nativeRemoveKey(String key);
+
+  /**
+   * Free the native objects.
+   *
+   * @param ownsShm true if this instance owns the shm segment
+   */
+ private static native void nativeShutdown(long shmFutexAddr, boolean ownsShm);
+
+  private boolean readMessage = false;
+
+  /**
+   * Address of the underlying native object, 0 when it has been freed.
+   */
+  private long shmFutexAddr;
+
+  private final ShmFutexInputStream istr;
+
+  private final ShmFutexOutputStream ostr;
+
+  private final MappedByteBuffer serverToClientBuf;
+
+  private final MappedByteBuffer clientToServerBuf;
+
+  private boolean ownsShm;
+
+  private final String key;
+
+  private ShmFutexTransport(long shmFutexAddr, String key) {
+    this.shmFutexAddr = shmFutexAddr;
+    this.key = key;
+    serverToClientBuf = nativeGetServerToClientBuf(shmFutexAddr);
+    clientToServerBuf = nativeGetClientToServerBuf(shmFutexAddr);
+    istr = new ShmFutexInputStream();
+    ostr = new ShmFutexOutputStream();
+  }
+
+  public boolean beginReadMessage() {
+    return istr.beginRead();
+  }
+
+  public boolean beginWriteMessage() {
+    return ostr.beginWrite();
+  }
+
+  public void closeChannel() {
+    try {
+      istr.close();
+    } catch (IOException ignored) {
+    }
+    try {
+      ostr.close();
+    } catch (IOException ignored) {
+    }
+    if (shmFutexAddr != 0) {
+      nativeShutdown(shmFutexAddr, ownsShm);
+      shmFutexAddr = 0;
+    }
+  }
+
+  public void endReadMessage() {
+    istr.endRead();
+  }
+
+  public void endWriteMessage() {
+    ostr.endWrite();
+  }
+
+  public InputStream getInputStream() {
+    return istr;
+  }
+
+  public OutputStream getOutputStream() {
+    return ostr;
+  }
+
+  @Override
+  protected void finalize() throws Throwable {
+    if (shmFutexAddr != 0) {
+      nativeShutdown(shmFutexAddr, ownsShm);
+      shmFutexAddr = 0;
+    }
+  }
+
+  protected void removeKey() {
+    nativeRemoveKey(key);
+  }
+}
=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/ShmFutexTransportTestServer.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class ShmFutexTransportTestServer {
+
+  private static final int NUM_PACKETS = 800000;
+  private static final int PACKET_SIZE_CS = 96;
+  private static final int PACKET_SIZE_SC = 151;
+
+  /**
+   * @param args
+   */
+  public static void main(String[] args) {
+    String os = System.getProperty("os.name");
+    String arch = System.getProperty("os.arch");
+    if (arch.matches("i?\\d86")) {
+      arch = "x86";
+    } else if ("amd64".equals(arch)) {
+      arch = "x86_64";
+    }
+    String library = "ShmFutex_" + os + "_" + arch;
+    String platformLibrary = System.mapLibraryName(library);
+    System.out.println("Mapped name = " + platformLibrary);
+    System.load("/tmp/" + platformLibrary);
+    String[] outputKey = new String[1];
+    ShmFutexTransport shm = ShmFutexTransport.createNewChannel(outputKey);
+    if (shm == null) {
+      System.err.println("Unable to create shared memory segment");
+    }
+    System.out.println("Connect to key " + outputKey[0]);
+    try {
+      runServer(shm);
+    } finally {
+      shm.closeChannel();
+    }
+  }
+
+  private static void runServer(Transport shm) {
+    InputStream istr = shm.getInputStream();
+    OutputStream ostr = shm.getOutputStream();
+    for (int i = 0; i < NUM_PACKETS; ++i) {
+      shm.beginReadMessage();
+      readPacket(istr, PACKET_SIZE_CS);
+      shm.endReadMessage();
+      shm.beginWriteMessage();
+      writePacket(ostr, PACKET_SIZE_SC);
+      shm.endWriteMessage();
+    }
+  }
+
+  private static void writePacket(OutputStream ostr, int len) {
+    while (len-- > 0) {
+      try {
+        ostr.write((byte) len);
+      } catch (IOException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private static void readPacket(InputStream istr, int len) {
+    while (len-- > 0) {
+      try {
+        int b = istr.read();
+        if ((byte) b != (byte) len) {
+ throw new IllegalStateException("Expected " + (byte) len + ", got "
+              + (byte) b);
+        }
+      } catch (IOException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+  }
+}
=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/SocketTransport.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import com.google.gwt.util.tools.Utility;
+
+import java.io.IOException;
+import java.net.Socket;
+
+/**
+ * Transport implementation using TCP sockets.
+ */
+public class SocketTransport extends DefaultTransport {
+
+  private final Socket socket;
+
+  public SocketTransport(Socket socket) throws IOException {
+    super(socket.getInputStream(), socket.getOutputStream());
+    this.socket = socket;
+  }
+
+  @Override
+  public void closeChannel() {
+    Utility.close(socket);
+  }
+
+  public String getRemoteEndpoint() {
+    return socket.getInetAddress().getCanonicalHostName() + ":"
+        + socket.getPort();
+  }
+}
=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/Transport.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Describes alternate transports that can be used for the code server protocol.
+ */
+public interface Transport {
+
+  /**
+ * @return the InputStream for this transport (only valid after createChannel
+   * has been called).
+   */
+  InputStream getInputStream();
+
+  /**
+ * @return the OutputStream for this transport (only valid after createChannel
+   * has been called).
+   */
+  OutputStream getOutputStream();
+
+  /**
+ * Close this transport channel. Must be called to free up held resources.
+   */
+  void closeChannel();
+
+  /**
+ * Begin reading a message. Must be called before reading any bytes from the
+   * input stream for a message.
+   *
+   * @return true on success
+   */
+  boolean beginReadMessage();
+
+  /**
+ * Begin writing a message. Must be called before writing any bytes to the
+   * input stream for a message.
+   *
+   * @return true on success
+   */
+  boolean beginWriteMessage();
+
+  /**
+   * Finishes reading a message.  Must be called after the last byte of a
+ * message is read and before the next call to {...@link #beginReadMessage()}.
+   */
+  void endReadMessage();
+
+  /**
+   * Finishes writing a message.  Must be called after the last byte of a
+   * message is written and before the next call to
+   * {...@link #beginWriteMessage()}.
+   */
+  void endWriteMessage();
+}
=======================================
--- /dev/null
+++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/TransportFactory.java Wed Mar 31 20:30:31 2010
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+public interface TransportFactory {
+
+  public class TransportArgs {
+    public String transportArgs;
+  }
+
+  Transport connectTransport(String args);
+
+  Transport createTransport(TransportArgs args);
+
+  String getName();
+
+  boolean isAvailable();
+}
=======================================
--- /dev/null   
+++ /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86.so Wed Mar 31 20:30:31 2010
Binary file, no diff available.
=======================================
--- /dev/null   
+++ /changes/jat/csproto/jni/linux/prebuilt/libShmFutex_Linux_x86_64.so Wed Mar 31 20:30:31 2010
Binary file, no diff available.
=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Fri Feb 19 06:35:15 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannel.java Wed Mar 31 20:30:31 2010
@@ -20,8 +20,6 @@
 import com.google.gwt.dev.shell.BrowserChannel.Value.ValueType;
 import com.google.gwt.util.tools.Utility;

-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -35,17 +33,6 @@
  *
  */
 public abstract class BrowserChannel {
-
-  /**
-   * An error indicating that the remote side died and we should unroll the
-   * call stack as painlessly as possible to allow cleanup.
-   */
-  public static class RemoteDeathError extends Error {
-
-    public RemoteDeathError(Throwable cause) {
-      super("Remote connection lost", cause);
-    }
-  }

   /**
    * Class representing a reference to a Java object.
@@ -181,6 +168,17 @@
       return id;
     }
   }
+
+  /**
+   * An error indicating that the remote side died and we should unroll the
+   * call stack as painlessly as possible to allow cleanup.
+   */
+  public static class RemoteDeathError extends Error {
+
+    public RemoteDeathError(Throwable cause) {
+      super("Remote connection lost", cause);
+    }
+  }

   /**
* Represents an object on the other side of the channel, known to this side
@@ -616,6 +614,7 @@
       int minVersion = stream.readInt();
       int maxVersion = stream.readInt();
       String hostedHtmlVersion = readUtf8String(stream);
+      channel.endReadMessage();
       return new CheckVersionsMessage(channel, minVersion, maxVersion,
           hostedHtmlVersion);
     }
@@ -649,11 +648,13 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.CHECK_VERSIONS.getId());
       stream.writeInt(minVersion);
       stream.writeInt(maxVersion);
       writeUtf8String(stream, hostedHtmlVersion);
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -671,6 +672,7 @@
       for (int i = 0; i < n; ++i) {
         transports[i] = readUtf8String(stream);
       }
+      channel.endReadMessage();
       return new ChooseTransportMessage(channel, transports);
     }

@@ -689,11 +691,13 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.CHOOSE_TRANSPORT.getId());
       stream.writeInt(transports.length);
       for (String transport : transports) {
         writeUtf8String(stream, transport);
       }
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -707,6 +711,7 @@
       DataInputStream stream = channel.getStreamFromOtherSide();
       // NOTE: Tag has already been read.
       String error = readUtf8String(stream);
+      channel.endReadMessage();
       return new FatalErrorMessage(channel, error);
     }

@@ -724,8 +729,10 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.FATAL_ERROR.getId());
       writeUtf8String(stream, error);
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -744,18 +751,21 @@
       for (int i = 0; i < numIds; ++i) {
         ids[i] = stream.readInt();
       }
+      channel.endReadMessage();
       return new FreeMessage(channel, ids);
     }

     public static void send(BrowserChannel channel, int[] ids)
         throws IOException {
       DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.FREE_VALUE.getId());
       stream.writeInt(ids.length);
       for (int id : ids) {
         stream.writeInt(id);
       }
       stream.flush();
+      channel.endWriteMessage();
     }

     private final int ids[];
@@ -800,6 +810,7 @@
       for (int i = 0; i < argLen; i++) {
         args[i] = channel.readValue(stream);
       }
+      channel.endReadMessage();
       return new InvokeOnClientMessage(channel, methodName, thisRef, args);
     }

@@ -830,7 +841,7 @@
     @Override
     public void send() throws IOException {
final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.INVOKE.getId());
       writeUtf8String(stream, methodName);
       getBrowserChannel().writeValue(stream, thisRef);
@@ -839,6 +850,7 @@
         getBrowserChannel().writeValue(stream, args[i]);
       }
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -862,6 +874,7 @@
       for (int i = 0; i < argLen; i++) {
         args[i] = channel.readValue(stream);
       }
+      channel.endReadMessage();
       return new InvokeOnServerMessage(channel, methodDispatchId, thisRef,
           args);
     }
@@ -893,7 +906,7 @@
     @Override
     public void send() throws IOException {
final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
-
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.INVOKE.getId());
       stream.writeInt(methodDispatchId);
       getBrowserChannel().writeValue(stream, thisRef);
@@ -902,6 +915,7 @@
         getBrowserChannel().writeValue(stream, args[i]);
       }
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -925,6 +939,7 @@
       for (int i = 0; i < argLen; i++) {
         args[i] = channel.readValue(stream);
       }
+      channel.endReadMessage();
       return new InvokeSpecialMessage(channel, dispatchId, args);
     }

@@ -950,6 +965,7 @@
     public void send() throws IOException {
final DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();

+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.INVOKE_SPECIAL.getId());
       stream.writeByte(dispatchId.getId());
       stream.writeInt(args.length);
@@ -957,6 +973,7 @@
         getBrowserChannel().writeValue(stream, args[i]);
       }
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -970,15 +987,18 @@
         throws IOException {
       DataInputStream stream = channel.getStreamFromOtherSide();
       String js = readUtf8String(stream);
+      channel.endReadMessage();
       return new LoadJsniMessage(channel, js);
     }

     public static void send(BrowserChannel channel, String js)
         throws IOException {
       DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.write(MessageType.LOAD_JSNI.getId());
       writeUtf8String(stream, js);
       stream.flush();
+      channel.endWriteMessage();
     }

     private final String js;
@@ -1016,6 +1036,7 @@
       String sessionKey = readUtf8String(stream);
       String moduleName = readUtf8String(stream);
       String userAgent = readUtf8String(stream);
+      channel.endReadMessage();
return new LoadModuleMessage(channel, url, tabKey, sessionKey, moduleName,
           userAgent);
     }
@@ -1080,6 +1101,7 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.LOAD_MODULE.getId());
       writeUtf8String(stream, url);
       writeUtf8String(stream, tabKey);
@@ -1087,6 +1109,7 @@
       writeUtf8String(stream, moduleName);
       writeUtf8String(stream, userAgent);
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -1158,6 +1181,7 @@
       int protoVersion = stream.readInt();
       String moduleName = readUtf8String(stream);
       String userAgent = readUtf8String(stream);
+      channel.endReadMessage();
       return new OldLoadModuleMessage(channel, protoVersion, moduleName,
           userAgent);
     }
@@ -1191,11 +1215,13 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.OLD_LOAD_MODULE.getId());
       stream.writeInt(protoVersion);
       writeUtf8String(stream, moduleName);
       writeUtf8String(stream, userAgent);
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -1208,6 +1234,7 @@
         throws IOException {
       DataInputStream stream = channel.getStreamFromOtherSide();
       int protocolVersion = stream.readInt();
+      channel.endReadMessage();
       return new ProtocolVersionMessage(channel, protocolVersion);
     }

@@ -1225,9 +1252,11 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.PROTOCOL_VERSION.getId());
       stream.writeInt(protocolVersion);
       stream.flush();
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -1236,13 +1265,16 @@
    */
   protected static class QuitMessage extends Message {
     public static QuitMessage receive(BrowserChannel channel) {
+      channel.endReadMessage();
       return new QuitMessage(channel);
     }

     public static void send(BrowserChannel channel) throws IOException {
       final DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.QUIT.getId());
       stream.flush();
+      channel.endWriteMessage();
     }

     public QuitMessage(BrowserChannel channel) {
@@ -1269,14 +1301,17 @@
      */
     public static RequestIconMessage receive(BrowserChannel channel)
         throws IOException {
+      channel.endReadMessage();
       return new RequestIconMessage(channel);
     }

     public static void send(BrowserChannel channel)
         throws IOException {
       DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.REQUEST_ICON.getId());
       stream.flush();
+      channel.endWriteMessage();
     }

     public RequestIconMessage(BrowserChannel channel) {
@@ -1298,15 +1333,18 @@
       final DataInputStream stream = channel.getStreamFromOtherSide();
       final boolean isException = stream.readBoolean();
       final Value returnValue = channel.readValue(stream);
+      channel.endReadMessage();
       return new ReturnMessage(channel, isException, returnValue);
     }

     public static void send(BrowserChannel channel, boolean isException,
         Value returnValue) throws IOException {
       final DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.RETURN.getId());
       stream.writeBoolean(isException);
       channel.writeValue(stream, returnValue);
+      channel.endWriteMessage();
       stream.flush();
     }

@@ -1351,6 +1389,7 @@
       DataInputStream stream = channel.getStreamFromOtherSide();
       String transport = readUtf8String(stream);
       String transportArgs = readUtf8String(stream);
+      channel.endReadMessage();
       return new SwitchTransportMessage(channel, transport, transportArgs);
     }

@@ -1383,9 +1422,11 @@
     @Override
     public void send() throws IOException {
       DataOutputStream stream = getBrowserChannel().getStreamToOtherSide();
+      getBrowserChannel().beginWriteMessage();
       stream.writeByte(MessageType.SWITCH_TRANSPORT.getId());
       writeUtf8String(stream, transport);
       writeUtf8String(stream, transportArgs);
+      getBrowserChannel().endWriteMessage();
     }
   }

@@ -1406,12 +1447,14 @@
           iconBytes[i] = stream.readByte();
         }
       }
+      channel.endReadMessage();
       return new UserAgentIconMessage(channel, iconBytes);
     }

     public static void send(BrowserChannel channel, byte[] iconBytes)
         throws IOException {
       DataOutputStream stream = channel.getStreamToOtherSide();
+      channel.beginWriteMessage();
       stream.writeByte(MessageType.USER_AGENT_ICON.getId());
       if (iconBytes == null) {
         stream.writeInt(0);
@@ -1421,6 +1464,7 @@
           stream.writeByte(b);
         }
       }
+      channel.endWriteMessage();
       stream.flush();
     }

@@ -1450,14 +1494,14 @@
    * The oldest protocol version supported by this code.
    */
   public static final int PROTOCOL_VERSION_OLDEST = 2;
-
+
   /**
    * The protocol version that added the GetIcon message.
    */
   public static final int PROTOCOL_VERSION_GET_ICON = 3;

   public static final int SPECIAL_CLIENTMETHODS_OBJECT = 0;
-
+
   public static final int SPECIAL_SERVERMETHODS_OBJECT = 0;

   protected static JavaObjectRef getJavaObjectRef(int refId) {
@@ -1565,32 +1609,58 @@

   private final ObjectRefFactory objectRefFactory;

-  private Socket socket;
-
-  private final DataInputStream streamFromOtherSide;
-
-  private final DataOutputStream streamToOtherSide;
+  private DataInputStream streamFromOtherSide;
+
+  private DataOutputStream streamToOtherSide;
+
+  private SocketTransport socketTransport;
+
+  private Transport transport;

   public BrowserChannel(Socket socket, ObjectRefFactory objectRefFactory)
       throws IOException {
-    this(new BufferedInputStream(socket.getInputStream()),
-        new BufferedOutputStream(socket.getOutputStream()),
-        objectRefFactory);
-    this.socket = socket;
+    this(new SocketTransport(socket), objectRefFactory);
+    socketTransport = (SocketTransport) transport;
+  }
+
+ public BrowserChannel(Transport transport, ObjectRefFactory objectRefFactory) {
+    streamFromOtherSide = new DataInputStream(transport.getInputStream());
+    streamToOtherSide = new DataOutputStream(transport.getOutputStream());
+    this.transport = transport;
+    this.objectRefFactory = objectRefFactory;
+    if (transport instanceof SocketTransport) {
+      this.socketTransport = (SocketTransport) transport;
+    }
   }

protected BrowserChannel(InputStream inputStream, OutputStream outputStream,
       ObjectRefFactory objectRefFactory) {
-    streamFromOtherSide = new DataInputStream(inputStream);
-    streamToOtherSide = new DataOutputStream(outputStream);
-    socket = null;
-    this.objectRefFactory = objectRefFactory;
+ this(new DefaultTransport(inputStream, outputStream), objectRefFactory);
+  }
+
+  public void beginReadMessage() {
+    transport.beginReadMessage();
+  }
+
+  public void beginWriteMessage() {
+    transport.beginWriteMessage();
+  }
+
+  public void endReadMessage() {
+    transport.endReadMessage();
   }

   public void endSession() {
     Utility.close(streamFromOtherSide);
     Utility.close(streamToOtherSide);
-    Utility.close(socket);
+    transport.closeChannel();
+    if (socketTransport != null) {
+      socketTransport.closeChannel();
+    }
+  }
+
+  public void endWriteMessage() {
+    transport.endWriteMessage();
   }

   /**
@@ -1601,11 +1671,28 @@
   }

   public String getRemoteEndpoint() {
-    if (socket == null) {
+    if (socketTransport == null) {
       return "";
     }
-    return socket.getInetAddress().getCanonicalHostName() + ":"
-        + socket.getPort();
+    return socketTransport.getRemoteEndpoint();
+  }
+
+  protected void changeTransport(Transport transport) {
+    this.transport = transport;
+    try {
+      streamToOtherSide.flush();
+    } catch (IOException e) {
+      // silently ignore
+    }
+    streamFromOtherSide = new DataInputStream(transport.getInputStream());
+    streamToOtherSide = new DataOutputStream(transport.getOutputStream());
+  }
+
+  protected void closeTransports() {
+    transport.closeChannel();
+    if (socketTransport != null) {
+      socketTransport.closeChannel();
+    }
   }

   protected DataInputStream getStreamFromOtherSide() {
=======================================
--- /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Fri Feb 19 06:35:15 2010 +++ /changes/jat/csproto/dev/core/src/com/google/gwt/dev/shell/BrowserChannelServer.java Wed Mar 31 20:30:31 2010
@@ -19,6 +19,7 @@
 import com.google.gwt.core.ext.TreeLogger.HelpInfo;
import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.ExceptionOrReturnValue;
 import com.google.gwt.dev.shell.JsValue.DispatchObject;
+import com.google.gwt.dev.shell.TransportFactory.TransportArgs;

 import java.io.IOException;
 import java.io.InputStream;
@@ -268,7 +269,7 @@
   public void reactToMessages(SessionHandlerServer handler) {
     do {
       try {
-        getStreamToOtherSide().flush();
+        beginReadMessage();
         MessageType messageType = Message.readMessageType(
             getStreamFromOtherSide());
         switch (messageType) {
@@ -312,6 +313,7 @@
     do {
       try {
         getStreamToOtherSide().flush();
+        beginReadMessage();
         MessageType messageType = Message.readMessageType(
             getStreamFromOtherSide());
         switch (messageType) {
@@ -451,12 +453,23 @@
         // the client to stay in this channel.
         if (type == MessageType.CHOOSE_TRANSPORT) {
ChooseTransportMessage chooseTransport = ChooseTransportMessage.receive(this); - String transport = selectTransport(chooseTransport.getTransports());
+          TransportFactory factory = selectTransport(
+              chooseTransport.getTransports());
+          String transportName = null;
           String transportArgs = null;
-          if (transport != null) {
-            transportArgs = createTransport(transport);
-          }
- new SwitchTransportMessage(this, transport, transportArgs).send();
+          Transport newTransport = null;
+          if (factory != null) {
+            TransportArgs args = new TransportArgs();
+            newTransport = factory.createTransport(args);
+            if (newTransport != null) {
+              transportName = factory.getName();
+              transportArgs = args.transportArgs;
+            }
+          }
+ new SwitchTransportMessage(this, transportName, transportArgs).send();
+          if (newTransport != null) {
+            changeTransport(newTransport);
+          }
           type = Message.readMessageType(getStreamFromOtherSide());
         }

@@ -535,6 +548,7 @@
       }
     } finally {
       handler.unloadModule(this, moduleName);
+      closeTransports();
     }
   }

@@ -631,20 +645,6 @@
         break;
     }
   }
-
-  /**
- * Create the requested transport and return the appropriate information so
-   * the client can connect to the same transport.
-   *
-   * @param transport transport name to create
- * @return transport-specific arguments for the client to use in attaching
-   *     to this transport
-   */
-  private String createTransport(String transport) {
-    // TODO(jat): implement support for additional transports
-    throw new UnsupportedOperationException(
-        "No alternate transports supported");
-  }

private void handleInvokeSpecial(SessionHandlerServer handler) throws IOException,
       BrowserChannelException {
@@ -682,7 +682,7 @@
    * @param transports array of supported transports
    * @return null to continue in-band, or a transport type
    */
-  private String selectTransport(String[] transports) {
+  private TransportFactory selectTransport(String[] transports) {
     // TODO(jat): add support for shared memory, others
     return null;
   }
=======================================
--- /changes/jat/csproto/distro-source/build.xml        Fri Oct 30 12:00:05 2009
+++ /changes/jat/csproto/distro-source/build.xml        Wed Mar 31 20:30:31 2010
@@ -28,6 +28,7 @@

       <!-- jni libs-->
<zipfileset dir="${gwt.build.jni}/windows" prefix="${project.distname}" /> + <zipfileset dir="${gwt.build.jni}/linux" prefix="${project.distname}" />

       <!-- raw files -->
       <zipfileset dir="${dist.resources}" prefix="${project.distname}" />
=======================================
--- /changes/jat/csproto/jni/build.xml  Fri Oct 16 07:16:57 2009
+++ /changes/jat/csproto/jni/build.xml  Wed Mar 31 20:30:31 2010
@@ -5,5 +5,6 @@

   <target name="build" description="Build each platforms">
     <gwt.ant dir="windows" target="build"/>
+    <gwt.ant dir="linux" target="build"/>
   </target>
 </project>
=======================================
--- /changes/jat/csproto/jni/linux/Makefile     Wed Mar 31 18:19:25 2010
+++ /changes/jat/csproto/jni/linux/Makefile     Wed Mar 31 20:30:31 2010
@@ -18,8 +18,10 @@
 #JAVA_HOME
 #JAVA_HOME=/usr/lib/j2sdk1.5-sun

-ARCH = -m32 -march=i686
-ARCHNAME = x86
+#ARCH = -m32 -march=i686
+#ARCHNAME = x86
+ARCH = -m64
+ARCHNAME = x86_64

 # set GWT_TOOLS only if it is not already defined
 GWT_TOOLS ?= ../../../tools

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

To unsubscribe, reply using "remove me" as the subject.

Reply via email to