summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2007-02-15 14:28:02 (EST)
committerEike Stepper2007-02-15 14:28:02 (EST)
commitb727d39bfdfdd597107910027a979f2be0221798 (patch)
treea6d443ac75c5a33fa5513a2c14b0434436db5efe
parentf649f5c71635a524992d733a29c68fc0f2d3223b (diff)
downloadcdo-b727d39bfdfdd597107910027a979f2be0221798.zip
cdo-b727d39bfdfdd597107910027a979f2be0221798.tar.gz
cdo-b727d39bfdfdd597107910027a979f2be0221798.tar.bz2
Initial provisioning
-rw-r--r--plugins/org.eclipse.net4j.tcp/.classpath7
-rw-r--r--plugins/org.eclipse.net4j.tcp/.cvsignore2
-rw-r--r--plugins/org.eclipse.net4j.tcp/.options1
-rw-r--r--plugins/org.eclipse.net4j.tcp/.project28
-rw-r--r--plugins/org.eclipse.net4j.tcp/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--plugins/org.eclipse.net4j.tcp/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.net4j.tcp/build.properties6
-rw-r--r--plugins/org.eclipse.net4j.tcp/plugin.properties33
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/AbstractTCPConnector.java345
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ClientTCPConnectorImpl.java77
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ControlChannelImpl.java188
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/SelectorUtil.java115
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ServerTCPConnectorImpl.java52
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorFactoryImpl.java30
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorImpl.java142
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPConnectorFactoryImpl.java30
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterFactoryImpl.java33
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterImpl.java77
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPSelectorImpl.java372
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/Activator.java30
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/TCP.java34
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPAcceptorFactory.java21
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPConnectorFactory.java21
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPContainerAdapter.java23
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelector.java36
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelectorListener.java43
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPUtil.java64
-rw-r--r--plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/package.html43
28 files changed, 1874 insertions, 0 deletions
diff --git a/plugins/org.eclipse.net4j.tcp/.classpath b/plugins/org.eclipse.net4j.tcp/.classpath
new file mode 100644
index 0000000..304e861
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.net4j.tcp/.cvsignore b/plugins/org.eclipse.net4j.tcp/.cvsignore
new file mode 100644
index 0000000..6938697
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/.cvsignore
@@ -0,0 +1,2 @@
+bin
+doc
diff --git a/plugins/org.eclipse.net4j.tcp/.options b/plugins/org.eclipse.net4j.tcp/.options
new file mode 100644
index 0000000..1ba22f9
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/.options
@@ -0,0 +1 @@
+org.eclipse.net4j.tcp/debug = true
diff --git a/plugins/org.eclipse.net4j.tcp/.project b/plugins/org.eclipse.net4j.tcp/.project
new file mode 100644
index 0000000..43df6e8
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.net4j.tcp</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.net4j.tcp/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.net4j.tcp/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..7709eca
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Wed Feb 14 18:44:49 CET 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/plugins/org.eclipse.net4j.tcp/META-INF/MANIFEST.MF b/plugins/org.eclipse.net4j.tcp/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..962d92b
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.net4j.tcp
+Bundle-Version: 0.8.0.qualifier
+Bundle-Activator: org.eclipse.net4j.internal.tcp.bundle.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.net4j
+Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Import-Package: org.osgi.framework;version="1.3.0";resolution:=optional
+Export-Package: org.eclipse.net4j.internal.tcp;version="0.8.0",
+ org.eclipse.net4j.internal.tcp.bundle;version="0.8.0",
+ org.eclipse.net4j.tcp;version="0.8.0"
diff --git a/plugins/org.eclipse.net4j.tcp/build.properties b/plugins/org.eclipse.net4j.tcp/build.properties
new file mode 100644
index 0000000..d801b47
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ .options,\
+ plugin.properties
diff --git a/plugins/org.eclipse.net4j.tcp/plugin.properties b/plugins/org.eclipse.net4j.tcp/plugin.properties
new file mode 100644
index 0000000..b430287
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/plugin.properties
@@ -0,0 +1,33 @@
+# /**
+# * <copyright>
+# *
+# * Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany.
+# * 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:
+# * Eike Stepper - Initial API and implementation
+# *
+# * </copyright>
+# *
+# * $Id$
+# */
+
+# NLS_MESSAGEFORMAT_VAR
+
+# ==============================================================================
+# Do not change the properties between this line and the last line containing:
+# %%% END OF TRANSLATED PROPERTIES %%%
+# Instead, either redefine an existing property, or create a new property,
+# append it to the end of the file, and change the code to use the new name.
+# ==============================================================================
+
+pluginName=Net4j TCP Support
+providerName=Eclipse.org
+
+# ==============================================================================
+# %%% END OF TRANSLATED PROPERTIES %%%
+# The above properties have been shipped for translation.
+# ==============================================================================
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/AbstractTCPConnector.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/AbstractTCPConnector.java
new file mode 100644
index 0000000..a8adbc4
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/AbstractTCPConnector.java
@@ -0,0 +1,345 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPSelector;
+import org.eclipse.net4j.tcp.TCPSelectorListener;
+import org.eclipse.net4j.transport.Buffer;
+import org.eclipse.net4j.transport.Channel;
+import org.eclipse.net4j.transport.ConnectorException;
+import org.eclipse.net4j.transport.ConnectorState;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+import org.eclipse.internal.net4j.transport.AbstractConnector;
+import org.eclipse.internal.net4j.transport.ChannelImpl;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * @author Eike Stepper
+ */
+public abstract class AbstractTCPConnector extends AbstractConnector implements TCPSelectorListener.Active
+{
+ private static final ContextTracer TRACER = new ContextTracer(Net4j.DEBUG_CONNECTOR, AbstractTCPConnector.class);
+
+ private SocketChannel socketChannel;
+
+ private TCPSelector selector;
+
+ private SelectionKey selectionKey;
+
+ private Buffer inputBuffer;
+
+ private ControlChannelImpl controlChannel;
+
+ public AbstractTCPConnector()
+ {
+ }
+
+ public TCPSelector getSelector()
+ {
+ return selector;
+ }
+
+ public void setSelector(TCPSelector selector)
+ {
+ this.selector = selector;
+ }
+
+ public SocketChannel getSocketChannel()
+ {
+ return socketChannel;
+ }
+
+ /**
+ * SocketChannel must already be non-blocking!
+ */
+ public void setSocketChannel(SocketChannel socketChannel)
+ {
+ this.socketChannel = socketChannel;
+ }
+
+ /**
+ * Called by {@link ChannelImpl} each time a new buffer is available for
+ * multiplexing. This or another buffer can be dequeued from the outputQueue
+ * of the {@link ChannelImpl}.
+ */
+ public void multiplexBuffer(Channel channel)
+ {
+ checkSelectionKey();
+ selector.setWriteInterest(selectionKey, true);
+ }
+
+ public void registered(SelectionKey selectionKey)
+ {
+ this.selectionKey = selectionKey;
+ if (isServer())
+ {
+ selector.setConnectInterest(selectionKey, false);
+ }
+ }
+
+ public void handleConnect(TCPSelector selector, SocketChannel channel)
+ {
+ try
+ {
+ if (!channel.finishConnect())
+ {
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ return;
+ }
+
+ try
+ {
+ checkSelectionKey();
+ selector.setConnectInterest(selectionKey, false);
+ setState(ConnectorState.NEGOTIATING);
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ deactivate();
+ }
+ }
+
+ public void handleRead(TCPSelector selector, SocketChannel socketChannel)
+ {
+ try
+ {
+ if (inputBuffer == null)
+ {
+ inputBuffer = getBufferProvider().provideBuffer();
+ }
+
+ ByteBuffer byteBuffer = inputBuffer.startGetting(socketChannel);
+ if (byteBuffer != null)
+ {
+ short channelIndex = inputBuffer.getChannelIndex();
+ ChannelImpl channel = channelIndex == ControlChannelImpl.CONTROL_CHANNEL_ID ? controlChannel
+ : getChannel(channelIndex);
+ if (channel != null)
+ {
+ channel.handleBufferFromMultiplexer(inputBuffer);
+ }
+ else
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Discarding buffer from unknown channel"); //$NON-NLS-1$
+ }
+
+ inputBuffer.release();
+ }
+
+ inputBuffer = null;
+ }
+ }
+ catch (ClosedChannelException ex)
+ {
+ deactivate();
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ deactivate();
+ }
+ }
+
+ public void handleWrite(TCPSelector selector, SocketChannel socketChannel)
+ {
+ try
+ {
+ boolean moreToWrite = false;
+ for (Queue<Buffer> bufferQueue : getChannelBufferQueues())
+ {
+ Buffer buffer = bufferQueue.peek();
+ if (buffer != null)
+ {
+ if (buffer.write(socketChannel))
+ {
+ bufferQueue.poll();
+ buffer.release();
+
+ if (!moreToWrite)
+ {
+ moreToWrite = !bufferQueue.isEmpty();
+ }
+ }
+ else
+ {
+ moreToWrite = true;
+ break;
+ }
+ }
+ }
+
+ if (!moreToWrite)
+ {
+ checkSelectionKey();
+ selector.setWriteInterest(selectionKey, false);
+ }
+ }
+ catch (NullPointerException ignore)
+ {
+ ;
+ }
+ catch (ClosedChannelException ex)
+ {
+ deactivate();
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ deactivate();
+ }
+ }
+
+ @Override
+ protected List<Queue<Buffer>> getChannelBufferQueues()
+ {
+ List<Queue<Buffer>> queues = super.getChannelBufferQueues();
+ Queue<Buffer> controlQueue = controlChannel.getSendQueue();
+ if (!controlQueue.isEmpty())
+ {
+ queues.add(controlQueue);
+ }
+
+ return queues;
+ }
+
+ @Override
+ protected void registerChannelWithPeer(short channelIndex, String protocolID) throws ConnectorException
+ {
+ try
+ {
+ if (!controlChannel.registerChannel(channelIndex, protocolID))
+ {
+ throw new ConnectorException("Failed to register channel with peer"); //$NON-NLS-1$
+ }
+ }
+ catch (ConnectorException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new ConnectorException(ex);
+ }
+ }
+
+ @Override
+ protected void removeChannel(ChannelImpl channel)
+ {
+ if (isConnected())
+ {
+ controlChannel.deregisterChannel(channel.getChannelIndex());
+ }
+
+ super.removeChannel(channel);
+ }
+
+ @Override
+ protected void onAboutToActivate() throws Exception
+ {
+ super.onAboutToActivate();
+ if (socketChannel == null)
+ {
+ throw new IllegalStateException("socketChannel == null");
+ }
+
+ if (selector == null)
+ {
+ throw new IllegalStateException("selector == null");
+ }
+ }
+
+ @Override
+ protected void onActivate() throws Exception
+ {
+ super.onActivate();
+ controlChannel = new ControlChannelImpl(this);
+ controlChannel.activate();
+ selector.registerAsync(socketChannel, this);
+ }
+
+ @Override
+ protected void onDeactivate() throws Exception
+ {
+ Exception exception = null;
+
+ try
+ {
+ controlChannel.deactivate();
+ }
+ catch (Exception ex)
+ {
+ if (exception == null)
+ {
+ exception = ex;
+ }
+ }
+ finally
+ {
+ controlChannel = null;
+ }
+
+ try
+ {
+ socketChannel.close();
+ }
+ catch (Exception ex)
+ {
+ if (exception == null)
+ {
+ exception = ex;
+ }
+ }
+ finally
+ {
+ socketChannel = null;
+ }
+
+ try
+ {
+ super.onDeactivate();
+ }
+ catch (Exception ex)
+ {
+ if (exception == null)
+ {
+ exception = ex;
+ }
+ }
+
+ if (exception != null)
+ {
+ throw exception;
+ }
+ }
+
+ private void checkSelectionKey()
+ {
+ if (selectionKey == null)
+ {
+ throw new IllegalStateException("selectionKey == null");
+ }
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ClientTCPConnectorImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ClientTCPConnectorImpl.java
new file mode 100644
index 0000000..0d8d7c1
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ClientTCPConnectorImpl.java
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.transport.ConnectorLocation;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+import org.eclipse.internal.net4j.transport.DescriptionUtil;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.channels.SocketChannel;
+import java.text.MessageFormat;
+
+/**
+ * @author Eike Stepper
+ */
+public class ClientTCPConnectorImpl extends AbstractTCPConnector
+{
+ public ClientTCPConnectorImpl()
+ {
+ try
+ {
+ SocketChannel socketChannel = SocketChannel.open();
+ socketChannel.configureBlocking(false);
+ setSocketChannel(socketChannel);
+ }
+ catch (IOException ex)
+ {
+ Net4j.LOG.error(ex);
+ }
+ }
+
+ public ConnectorLocation getLocation()
+ {
+ return ConnectorLocation.CLIENT;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("ClientTCPConnector[{0}]", getDescription()); //$NON-NLS-1$
+ }
+
+ @Override
+ protected void onAboutToActivate() throws Exception
+ {
+ super.onAboutToActivate();
+ if (getDescription() == null)
+ {
+ throw new IllegalStateException("getDescription() == null"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ protected void onActivate() throws Exception
+ {
+ super.onActivate();
+
+ String[] elements = DescriptionUtil.getElements(getDescription());
+ String host = elements[1];
+ int port = Integer.parseInt(elements[2]);
+
+ InetAddress addr = InetAddress.getByName(host);
+ InetSocketAddress sAddr = new InetSocketAddress(addr, port);
+ getSocketChannel().connect(sAddr);
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ControlChannelImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ControlChannelImpl.java
new file mode 100644
index 0000000..afbc06f
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ControlChannelImpl.java
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.transport.Buffer;
+import org.eclipse.net4j.util.concurrent.ISynchronizer;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+import org.eclipse.internal.net4j.transport.BufferUtil;
+import org.eclipse.internal.net4j.transport.ChannelImpl;
+import org.eclipse.internal.net4j.util.concurrent.SynchronizingCorrelator;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @author Eike Stepper
+ */
+public final class ControlChannelImpl extends ChannelImpl
+{
+ public static final short CONTROL_CHANNEL_ID = -1;
+
+ public static final long REGISTRATION_TIMEOUT = 500000;
+
+ public static final byte OPCODE_REGISTRATION = 1;
+
+ public static final byte OPCODE_REGISTRATION_ACK = 2;
+
+ public static final byte OPCODE_DEREGISTRATION = 3;
+
+ public static final byte SUCCESS = 1;
+
+ public static final byte FAILURE = 0;
+
+ private static final ContextTracer TRACER = new ContextTracer(Net4j.DEBUG_CHANNEL, ControlChannelImpl.class);
+
+ private SynchronizingCorrelator<Short, Boolean> registrations = new SynchronizingCorrelator();
+
+ public ControlChannelImpl(AbstractTCPConnector connector)
+ {
+ super(connector.getReceiveExecutor());
+ setChannelIndex(CONTROL_CHANNEL_ID);
+ setConnector(connector);
+ }
+
+ @Override
+ public boolean isInternal()
+ {
+ return true;
+ }
+
+ public boolean registerChannel(short channelIndex, String protocolID)
+ {
+ assertValidChannelIndex(channelIndex);
+ ISynchronizer<Boolean> registration = registrations.correlate(channelIndex);
+
+ Buffer buffer = provideBuffer();
+ ByteBuffer byteBuffer = buffer.startPutting(CONTROL_CHANNEL_ID);
+ byteBuffer.put(OPCODE_REGISTRATION);
+ byteBuffer.putShort(channelIndex);
+ BufferUtil.putUTF8(byteBuffer, protocolID);
+ handleBuffer(buffer);
+
+ return registration.get(REGISTRATION_TIMEOUT);
+ }
+
+ public void deregisterChannel(short channelIndex)
+ {
+ assertValidChannelIndex(channelIndex);
+
+ Buffer buffer = provideBuffer();
+ ByteBuffer byteBuffer = buffer.startPutting(CONTROL_CHANNEL_ID);
+ byteBuffer.put(OPCODE_DEREGISTRATION);
+ byteBuffer.putShort(channelIndex);
+ handleBuffer(buffer);
+ }
+
+ public void handleBufferFromMultiplexer(Buffer buffer)
+ {
+ try
+ {
+ ByteBuffer byteBuffer = buffer.getByteBuffer();
+ byte opcode = byteBuffer.get();
+ switch (opcode)
+ {
+ case OPCODE_REGISTRATION:
+ {
+ short channelIndex = byteBuffer.getShort();
+ assertValidChannelIndex(channelIndex);
+ boolean success = true;
+
+ try
+ {
+ byte[] handlerFactoryUTF8 = BufferUtil.getByteArray(byteBuffer);
+ String protocolID = BufferUtil.fromUTF8(handlerFactoryUTF8);
+ ChannelImpl channel = ((AbstractTCPConnector)getConnector()).createChannel(channelIndex, protocolID, null);
+ if (channel != null)
+ {
+ channel.activate();
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ success = false;
+ }
+
+ sendStatus(OPCODE_REGISTRATION_ACK, channelIndex, success);
+ break;
+ }
+
+ case OPCODE_REGISTRATION_ACK:
+ {
+ short channelIndex = byteBuffer.getShort();
+ boolean success = byteBuffer.get() == SUCCESS;
+ registrations.put(channelIndex, success);
+ break;
+ }
+
+ case OPCODE_DEREGISTRATION:
+ {
+ short channelIndex = byteBuffer.getShort();
+ assertValidChannelIndex(channelIndex);
+
+ try
+ {
+ ChannelImpl channel = ((AbstractTCPConnector)getConnector()).getChannel(channelIndex);
+ if (channel != null)
+ {
+ channel.deactivate();
+ }
+ else
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Invalid channel id: " + channelIndex); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ }
+
+ break;
+ }
+
+ default:
+ Net4j.LOG.error("Invalid opcode: " + opcode); //$NON-NLS-1$
+ ((AbstractTCPConnector)getConnector()).deactivate();
+ }
+ }
+ finally
+ {
+ buffer.release();
+ }
+ }
+
+ private void sendStatus(byte opcode, short channelIndex, boolean status)
+ {
+ Buffer buffer = provideBuffer();
+ ByteBuffer byteBuffer = buffer.startPutting(CONTROL_CHANNEL_ID);
+ byteBuffer.put(opcode);
+ byteBuffer.putShort(channelIndex);
+ byteBuffer.put(status ? SUCCESS : FAILURE);
+ handleBuffer(buffer);
+ }
+
+ private void assertValidChannelIndex(short channelIndex)
+ {
+ if (channelIndex <= CONTROL_CHANNEL_ID)
+ {
+ throw new IllegalArgumentException("channelIndex <= CONTROL_CHANNEL_ID"); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/SelectorUtil.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/SelectorUtil.java
new file mode 100644
index 0000000..fdb1685
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/SelectorUtil.java
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+
+import java.nio.channels.SelectionKey;
+
+/**
+ * @author Eike Stepper
+ */
+public final class SelectorUtil
+{
+ private static final ContextTracer TRACER = new ContextTracer(Net4j.DEBUG_SELECTOR, SelectorUtil.class);
+
+ private SelectorUtil()
+ {
+ }
+
+ public static String formatInterestOps(int newOps)
+ {
+ StringBuilder builder = new StringBuilder();
+ if ((newOps & SelectionKey.OP_ACCEPT) != 0)
+ {
+ addInterestOp(builder, "ACCEPT"); //$NON-NLS-1$
+ }
+
+ if ((newOps & SelectionKey.OP_CONNECT) != 0)
+ {
+ addInterestOp(builder, "CONNECT"); //$NON-NLS-1$
+ }
+
+ if ((newOps & SelectionKey.OP_READ) != 0)
+ {
+ addInterestOp(builder, "READ"); //$NON-NLS-1$
+ }
+
+ if ((newOps & SelectionKey.OP_WRITE) != 0)
+ {
+ addInterestOp(builder, "WRITE"); //$NON-NLS-1$
+ }
+
+ return builder.toString();
+ }
+
+ public static void setInterest(SelectionKey selectionKey, int operation, boolean interested)
+ {
+ if (selectionKey == null || !selectionKey.isValid())
+ {
+ return;
+ }
+
+ int newOps;
+ int oldOps = selectionKey.interestOps();
+ if (interested)
+ {
+ newOps = oldOps | operation;
+ }
+ else
+ {
+ newOps = oldOps & ~operation;
+ }
+
+ if (oldOps != newOps)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Setting interest " //$NON-NLS-1$
+ + formatInterestOps(newOps) + " (was " + formatInterestOps(oldOps).toLowerCase() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ selectionKey.interestOps(newOps);
+ }
+ }
+
+ public static void setAcceptInterest(SelectionKey selectionKey, boolean interested)
+ {
+ setInterest(selectionKey, SelectionKey.OP_ACCEPT, interested);
+ }
+
+ public static void setConnectInterest(SelectionKey selectionKey, boolean interested)
+ {
+ setInterest(selectionKey, SelectionKey.OP_CONNECT, interested);
+ }
+
+ public static void setReadInterest(SelectionKey selectionKey, boolean interested)
+ {
+ setInterest(selectionKey, SelectionKey.OP_READ, interested);
+ }
+
+ public static void setWriteInterest(SelectionKey selectionKey, boolean interested)
+ {
+ setInterest(selectionKey, SelectionKey.OP_WRITE, interested);
+ }
+
+ private static void addInterestOp(StringBuilder builder, String op)
+ {
+ if (builder.length() != 0)
+ {
+ builder.append("|"); //$NON-NLS-1$
+ }
+
+ builder.append(op);
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ServerTCPConnectorImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ServerTCPConnectorImpl.java
new file mode 100644
index 0000000..8bf1fca
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ServerTCPConnectorImpl.java
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.transport.ConnectorLocation;
+
+import java.text.MessageFormat;
+
+/**
+ * @author Eike Stepper
+ */
+public class ServerTCPConnectorImpl extends AbstractTCPConnector
+{
+ public ServerTCPConnectorImpl()
+ {
+ }
+
+ public ConnectorLocation getLocation()
+ {
+ return ConnectorLocation.SERVER;
+ }
+
+ public String getHost()
+ {
+ return getSocketChannel().socket().getInetAddress().getHostAddress();
+ }
+
+ public int getPort()
+ {
+ return getSocketChannel().socket().getPort();
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("ServerTCPConnector[{0}]", getDescription()); //$NON-NLS-1$
+ }
+
+ @Override
+ protected void onDeactivate() throws Exception
+ {
+ super.onDeactivate();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorFactoryImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorFactoryImpl.java
new file mode 100644
index 0000000..cbf482f
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorFactoryImpl.java
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPAcceptorFactory;
+import org.eclipse.net4j.transport.Acceptor;
+
+/**
+ * @author Eike Stepper
+ */
+public class TCPAcceptorFactoryImpl implements TCPAcceptorFactory
+{
+ public String getType()
+ {
+ return TYPE;
+ }
+
+ public Acceptor createAcceptor()
+ {
+ return new TCPAcceptorImpl();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorImpl.java
new file mode 100644
index 0000000..7e94c26
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPAcceptorImpl.java
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPSelector;
+import org.eclipse.net4j.tcp.TCPSelectorListener;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+import org.eclipse.internal.net4j.transport.AbstractAcceptor;
+import org.eclipse.internal.net4j.transport.DescriptionUtil;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.text.MessageFormat;
+
+/**
+ * @author Eike Stepper
+ */
+public class TCPAcceptorImpl extends AbstractAcceptor implements TCPSelectorListener.Passive
+{
+ private static final ContextTracer TRACER = new ContextTracer(Net4j.DEBUG_ACCEPTOR, TCPAcceptorImpl.class);
+
+ private TCPSelector selector;
+
+ private ServerSocketChannel serverSocketChannel;
+
+ public TCPAcceptorImpl()
+ {
+ }
+
+ public TCPSelector getSelector()
+ {
+ return selector;
+ }
+
+ public void setSelector(TCPSelector selector)
+ {
+ this.selector = selector;
+ }
+
+ public void handleAccept(TCPSelector selector, ServerSocketChannel serverSocketChannel)
+ {
+ try
+ {
+ SocketChannel socketChannel = serverSocketChannel.accept();
+ if (socketChannel != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Accepted socketChannel " + socketChannel); //$NON-NLS-1$
+ }
+
+ socketChannel.configureBlocking(false);
+ ServerTCPConnectorImpl connector = createConnector(socketChannel);
+ addConnector(connector);
+ }
+ }
+ catch (ClosedChannelException ex)
+ {
+ deactivate();
+ }
+ catch (Exception ex)
+ {
+ if (isActive())
+ {
+ Net4j.LOG.error(ex);
+ }
+
+ deactivate();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("TCPAcceptor[{0}]", getDescription()); //$NON-NLS-1$
+ }
+
+ protected ServerTCPConnectorImpl createConnector(SocketChannel socketChannel)
+ {
+ ServerTCPConnectorImpl connector = new ServerTCPConnectorImpl();
+ connector.setSocketChannel(socketChannel);
+ connector.setReceiveExecutor(getReceiveExecutor());
+ connector.setProtocolFactoryRegistry(getProtocolFactoryRegistry());
+ connector.setBufferProvider(getBufferProvider());
+ connector.setSelector(selector);
+ return connector;
+ }
+
+ @Override
+ protected void onAboutToActivate() throws Exception
+ {
+ super.onAboutToActivate();
+ if (getDescription() == null)
+ {
+ throw new IllegalStateException("getDescription() == null"); //$NON-NLS-1$
+ }
+
+ if (selector == null)
+ {
+ throw new IllegalStateException("selector == null");
+ }
+ }
+
+ @Override
+ protected void onActivate() throws Exception
+ {
+ super.onActivate();
+
+ String[] elements = DescriptionUtil.getElements(getDescription());
+ String address = elements[1];
+ int port = Integer.parseInt(elements[2]);
+
+ InetAddress addr = InetAddress.getByName(address);
+ InetSocketAddress sAddr = new InetSocketAddress(addr, port);
+
+ serverSocketChannel = ServerSocketChannel.open();
+ serverSocketChannel.configureBlocking(false);
+ serverSocketChannel.socket().bind(sAddr);
+
+ selector.registerAsync(serverSocketChannel, this);
+ }
+
+ @Override
+ protected void onDeactivate() throws Exception
+ {
+ serverSocketChannel.close();
+ super.onDeactivate();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPConnectorFactoryImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPConnectorFactoryImpl.java
new file mode 100644
index 0000000..31bc98b
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPConnectorFactoryImpl.java
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPConnectorFactory;
+import org.eclipse.net4j.transport.Connector;
+
+/**
+ * @author Eike Stepper
+ */
+public class TCPConnectorFactoryImpl implements TCPConnectorFactory
+{
+ public String getType()
+ {
+ return TYPE;
+ }
+
+ public Connector createConnector()
+ {
+ return new ClientTCPConnectorImpl();
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterFactoryImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterFactoryImpl.java
new file mode 100644
index 0000000..a60876f
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterFactoryImpl.java
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPContainerAdapter;
+import org.eclipse.net4j.transport.container.Container;
+import org.eclipse.net4j.transport.container.ContainerAdapter;
+import org.eclipse.net4j.transport.container.ContainerAdapterFactory;
+
+public final class TCPContainerAdapterFactoryImpl implements ContainerAdapterFactory
+{
+ public TCPContainerAdapterFactoryImpl()
+ {
+ }
+
+ public String getType()
+ {
+ return TCPContainerAdapter.TYPE;
+ }
+
+ public ContainerAdapter createAdapter(Container container)
+ {
+ return new TCPContainerAdapterImpl(container);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterImpl.java
new file mode 100644
index 0000000..8fc8fd8
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPContainerAdapterImpl.java
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPContainerAdapter;
+import org.eclipse.net4j.tcp.TCPSelector;
+import org.eclipse.net4j.transport.Acceptor;
+import org.eclipse.net4j.transport.AcceptorFactory;
+import org.eclipse.net4j.transport.Connector;
+import org.eclipse.net4j.transport.ConnectorFactory;
+import org.eclipse.net4j.transport.container.Container;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+
+import org.eclipse.internal.net4j.transport.container.TransportContainerAdapter;
+
+/**
+ * @author Eike Stepper
+ */
+public class TCPContainerAdapterImpl extends TransportContainerAdapter implements TCPContainerAdapter
+{
+ private TCPSelector selector;
+
+ public TCPContainerAdapterImpl(Container container)
+ {
+ super(container, TYPE);
+ selector = new TCPSelectorImpl();
+ }
+
+ public TCPSelector getSelector()
+ {
+ return selector;
+ }
+
+ @Override
+ protected void onActivate() throws Exception
+ {
+ super.onActivate();
+ LifecycleUtil.activate(selector);
+ }
+
+ @Override
+ protected void onDeactivate() throws Exception
+ {
+ LifecycleUtil.deactivate(selector);
+ super.onDeactivate();
+ }
+
+ protected AcceptorFactory createAcceptorFactory()
+ {
+ return new TCPAcceptorFactoryImpl();
+ }
+
+ protected ConnectorFactory createConnectorFactory()
+ {
+ return new TCPConnectorFactoryImpl();
+ }
+
+ public void initAcceptor(Acceptor acceptor)
+ {
+ TCPAcceptorImpl tcpAcceptor = (TCPAcceptorImpl)acceptor;
+ tcpAcceptor.setSelector(getSelector());
+ }
+
+ public void initConnector(Connector connector)
+ {
+ AbstractTCPConnector tcpConnector = (AbstractTCPConnector)connector;
+ tcpConnector.setSelector(getSelector());
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPSelectorImpl.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPSelectorImpl.java
new file mode 100644
index 0000000..ffcdb37
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/TCPSelectorImpl.java
@@ -0,0 +1,372 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp;
+
+import org.eclipse.net4j.tcp.TCPSelector;
+import org.eclipse.net4j.tcp.TCPSelectorListener;
+import org.eclipse.net4j.tcp.TCPSelectorListener.Active;
+import org.eclipse.net4j.tcp.TCPSelectorListener.Passive;
+import org.eclipse.net4j.util.lifecycle.LifecycleImpl;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.internal.net4j.bundle.Net4j;
+
+import java.io.IOException;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * @author Eike Stepper
+ */
+public class TCPSelectorImpl extends LifecycleImpl implements TCPSelector, Runnable
+{
+ private static final ContextTracer TRACER = new ContextTracer(Net4j.DEBUG_SELECTOR, TCPSelectorImpl.class);
+
+ private Selector selector;
+
+ private Queue<Runnable> pendingOperations = new ConcurrentLinkedQueue();
+
+ private Thread thread;
+
+ public TCPSelectorImpl()
+ {
+ }
+
+ public void invokeAsync(final Runnable operation)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Pending operation " + operation);
+ }
+
+ pendingOperations.add(operation);
+ selector.wakeup();
+ }
+
+ public void registerAsync(final ServerSocketChannel channel, final Passive listener)
+ {
+ assertValidListener(listener);
+ invokeAsync(new Runnable()
+ {
+ public void run()
+ {
+ doRegister(channel, listener);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "REGISTER " + channel;
+ }
+ });
+ }
+
+ public void registerAsync(final SocketChannel channel, final Active listener)
+ {
+ assertValidListener(listener);
+ invokeAsync(new Runnable()
+ {
+ public void run()
+ {
+ doRegister(channel, listener);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "REGISTER " + channel;
+ }
+ });
+ }
+
+ public void setConnectInterest(final SelectionKey selectionKey, final boolean on)
+ {
+ invokeAsync(new Runnable()
+ {
+ public void run()
+ {
+ SelectorUtil.setConnectInterest(selectionKey, on);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "INTEREST CONNECT " + selectionKey + " = " + on;
+ }
+ });
+ }
+
+ public void setReadInterest(final SelectionKey selectionKey, final boolean on)
+ {
+ invokeAsync(new Runnable()
+ {
+ public void run()
+ {
+ SelectorUtil.setReadInterest(selectionKey, on);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "INTEREST READ " + selectionKey + " = " + on;
+ }
+ });
+ }
+
+ public void setWriteInterest(final SelectionKey selectionKey, final boolean on)
+ {
+ invokeAsync(new Runnable()
+ {
+ public void run()
+ {
+ SelectorUtil.setWriteInterest(selectionKey, on);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "INTEREST WRITE " + selectionKey + " = " + on;
+ }
+
+ });
+ }
+
+ public void run()
+ {
+ while (isActive())
+ {
+ if (Thread.interrupted())
+ {
+ deactivate();
+ break;
+ }
+
+ try
+ {
+ Runnable operation;
+ while ((operation = pendingOperations.poll()) != null)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Executing operation " + operation);
+ }
+
+ operation.run();
+ }
+
+ if (selector.select() > 0)
+ {
+ Iterator<SelectionKey> it = selector.selectedKeys().iterator();
+ while (it.hasNext())
+ {
+ SelectionKey selKey = it.next();
+ it.remove();
+
+ try
+ {
+ handleSelection(selKey);
+ }
+ catch (CancelledKeyException ignore)
+ {
+ ; // Do nothing
+ }
+ catch (NullPointerException ignore)
+ {
+ ; // Do nothing
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ selKey.cancel();
+ }
+ }
+ }
+ }
+ catch (ClosedSelectorException ex)
+ {
+ break;
+ }
+ catch (Exception ex)
+ {
+ Net4j.LOG.error(ex);
+ deactivate();
+ break;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TCPSelector"; //$NON-NLS-1$
+ }
+
+ protected void handleSelection(SelectionKey selKey) throws IOException
+ {
+ SelectableChannel channel = selKey.channel();
+ if (channel instanceof ServerSocketChannel)
+ {
+ ServerSocketChannel ssChannel = (ServerSocketChannel)selKey.channel();
+ TCPSelectorListener.Passive listener = (TCPSelectorListener.Passive)selKey.attachment();
+
+ if (selKey.isAcceptable())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Accepting " + ssChannel); //$NON-NLS-1$
+ }
+
+ listener.handleAccept(this, ssChannel);
+ }
+ }
+ else if (channel instanceof SocketChannel)
+ {
+ SocketChannel sChannel = (SocketChannel)channel;
+ TCPSelectorListener.Active listener = (TCPSelectorListener.Active)selKey.attachment();
+
+ if (selKey.isConnectable())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Connecting " + sChannel); //$NON-NLS-1$
+ }
+
+ listener.handleConnect(this, sChannel);
+ }
+
+ if (selKey.isReadable())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Reading " + sChannel); //$NON-NLS-1$
+ }
+
+ listener.handleRead(this, sChannel);
+ }
+
+ if (selKey.isWritable())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Writing " + sChannel); //$NON-NLS-1$
+ }
+
+ listener.handleWrite(this, sChannel);
+ }
+ }
+ }
+
+ @Override
+ protected void onActivate() throws Exception
+ {
+ selector = Selector.open();
+ thread = new Thread(this, "selector"); //$NON-NLS-1$
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ @Override
+ protected void onDeactivate() throws Exception
+ {
+ selector.wakeup();
+ Exception exception = null;
+
+ try
+ {
+ thread.join(200);
+ }
+ catch (RuntimeException ex)
+ {
+ if (exception == null)
+ {
+ exception = ex;
+ }
+ }
+ finally
+ {
+ thread = null;
+ }
+
+ try
+ {
+ selector.close();
+ }
+ catch (Exception ex)
+ {
+ if (exception == null)
+ {
+ exception = ex;
+ }
+ }
+ finally
+ {
+ selector = null;
+ }
+
+ if (exception != null)
+ {
+ throw exception;
+ }
+ }
+
+ private void assertValidListener(Object listener)
+ {
+ if (listener == null)
+ {
+ throw new IllegalArgumentException("listener == null"); //$NON-NLS-1$
+ }
+ }
+
+ private void doRegister(final ServerSocketChannel channel, final TCPSelectorListener.Passive listener)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Registering " + channel); //$NON-NLS-1$
+ }
+
+ try
+ {
+ channel.register(selector, SelectionKey.OP_ACCEPT, listener);
+ }
+ catch (ClosedChannelException ignore)
+ {
+ ;
+ }
+ }
+
+ private void doRegister(final SocketChannel channel, final TCPSelectorListener.Active listener)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("Registering " + channel); //$NON-NLS-1$
+ }
+
+ try
+ {
+ int interest = SelectionKey.OP_CONNECT | SelectionKey.OP_READ;
+ SelectionKey selectionKey = channel.register(selector, interest, listener);
+ listener.registered(selectionKey);
+ }
+ catch (ClosedChannelException ignore)
+ {
+ ;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/Activator.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/Activator.java
new file mode 100644
index 0000000..40e631d
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/Activator.java
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp.bundle;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @author Eike Stepper
+ */
+public class Activator implements BundleActivator
+{
+ public void start(BundleContext context) throws Exception
+ {
+ TCP.BUNDLE.setBundleContext(context);
+ }
+
+ public void stop(BundleContext context) throws Exception
+ {
+ TCP.BUNDLE.setBundleContext(null);
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/TCP.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/TCP.java
new file mode 100644
index 0000000..0f9dfb1
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/bundle/TCP.java
@@ -0,0 +1,34 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.internal.tcp.bundle;
+
+import org.eclipse.net4j.util.om.OMBundle;
+import org.eclipse.net4j.util.om.OMLogger;
+import org.eclipse.net4j.util.om.OMPlatform;
+import org.eclipse.net4j.util.om.OMTracer;
+
+/**
+ * @author Eike Stepper
+ */
+public final class TCP
+{
+ public static final String BUNDLE_ID = "org.eclipse.net4j.tcp"; //$NON-NLS-1$
+
+ public static final OMBundle BUNDLE = OMPlatform.INSTANCE.bundle(BUNDLE_ID, TCP.class);
+
+ public static final OMTracer DEBUG = BUNDLE.tracer("debug"); //$NON-NLS-1$
+
+ public static final OMLogger LOG = BUNDLE.logger();
+
+ private TCP()
+ {
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPAcceptorFactory.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPAcceptorFactory.java
new file mode 100644
index 0000000..4b0cb68
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPAcceptorFactory.java
@@ -0,0 +1,21 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import org.eclipse.net4j.transport.AcceptorFactory;
+
+/**
+ * @author Eike Stepper
+ */
+public interface TCPAcceptorFactory extends AcceptorFactory
+{
+ public static final String TYPE = TCPContainerAdapter.TYPE;
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPConnectorFactory.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPConnectorFactory.java
new file mode 100644
index 0000000..412b44d
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPConnectorFactory.java
@@ -0,0 +1,21 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import org.eclipse.net4j.transport.ConnectorFactory;
+
+/**
+ * @author Eike Stepper
+ */
+public interface TCPConnectorFactory extends ConnectorFactory
+{
+ public static final String TYPE = TCPContainerAdapter.TYPE;
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPContainerAdapter.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPContainerAdapter.java
new file mode 100644
index 0000000..b24d621
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPContainerAdapter.java
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import org.eclipse.net4j.transport.container.ContainerAdapter;
+
+/**
+ * @author Eike Stepper
+ */
+public interface TCPContainerAdapter extends ContainerAdapter
+{
+ public static final String TYPE = "TCP";
+
+ public TCPSelector getSelector();
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelector.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelector.java
new file mode 100644
index 0000000..493eead
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelector.java
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import org.eclipse.net4j.tcp.TCPSelectorListener.Active;
+import org.eclipse.net4j.tcp.TCPSelectorListener.Passive;
+
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+/**
+ * @author Eike Stepper
+ */
+public interface TCPSelector
+{
+ public void invokeAsync(Runnable operation);
+
+ public void registerAsync(ServerSocketChannel channel, Passive listener);
+
+ public void registerAsync(SocketChannel channel, Active listener);
+
+ public void setConnectInterest(SelectionKey selectionKey, boolean on);
+
+ public void setReadInterest(SelectionKey selectionKey, boolean on);
+
+ public void setWriteInterest(SelectionKey selectionKey, boolean on);
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelectorListener.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelectorListener.java
new file mode 100644
index 0000000..a83835f
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPSelectorListener.java
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+/**
+ * @author Eike Stepper
+ */
+public interface TCPSelectorListener
+{
+ /**
+ * @author Eike Stepper
+ */
+ public interface Passive
+ {
+ public void handleAccept(TCPSelector selector, ServerSocketChannel serverSocketChannel);
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public interface Active
+ {
+ public void registered(SelectionKey selectionKey);
+
+ public void handleConnect(TCPSelector selector, SocketChannel channel);
+
+ public void handleRead(TCPSelector selector, SocketChannel socketChannel);
+
+ public void handleWrite(TCPSelector selector, SocketChannel socketChannel);
+ }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPUtil.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPUtil.java
new file mode 100644
index 0000000..a7cccdd
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/TCPUtil.java
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * Copyright (c) 2004-2007 Eike Stepper, Germany.
+ * 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.net4j.tcp;
+
+import org.eclipse.internal.net4j.transport.DescriptionUtil;
+
+/**
+ * @author Eike Stepper
+ */
+public final class TCPUtil
+{
+ public static final String DEFAULT_ADDRESS = "0.0.0.0"; //$NON-NLS-1$
+
+ public static final int DEFAULT_PORT = 2036;
+
+ private TCPUtil()
+ {
+ }
+
+ public static String createAcceptorDescription()
+ {
+ return createAcceptorDescription(DEFAULT_ADDRESS);
+ }
+
+ public static String createAcceptorDescription(String address)
+ {
+ return createAcceptorDescription(address, DEFAULT_PORT);
+ }
+
+ public static String createAcceptorDescription(String address, int port)
+ {
+ Object[] elements = { address, port };
+ return DescriptionUtil.getDescription(TCPContainerAdapter.TYPE, elements);
+ }
+
+ public static String createConnectorDescription(String host)
+ {
+ return createConnectorDescription(host, null);
+ }
+
+ public static String createConnectorDescription(String host, int port)
+ {
+ return createConnectorDescription(host, port, null);
+ }
+
+ public static String createConnectorDescription(String host, String userName)
+ {
+ return createConnectorDescription(host, DEFAULT_PORT, userName);
+ }
+
+ public static String createConnectorDescription(String host, int port, String userName)
+ {
+ Object[] elements = { host, port, userName };
+ return DescriptionUtil.getDescription(TCPContainerAdapter.TYPE, elements);
+ }
+}
diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/package.html b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/package.html
new file mode 100644
index 0000000..b2f6093
--- /dev/null
+++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/package.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+
+ Copyright (c) 2004, 2005, 2006 Eike Stepper, Germany.
+ 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:
+ Eike Stepper - Initial API and implementation
+
+-->
+</head>
+<body bgcolor="white">
+
+Interfaces for the transport layer specialized for TCP socket connections.
+<p>
+
+<!--
+
+<h2>Package Specification</h2>
+
+##### FILL IN ANY SPECS NEEDED BY JAVA COMPATIBILITY KIT #####
+<ul>
+ <li><a href="">##### REFER TO ANY FRAMEMAKER SPECIFICATION HERE #####</a>
+</ul>
+
+<h2>Related Documentation</h2>
+
+For overviews, tutorials, examples, guides, and tool documentation, please see:
+<ul>
+ <li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a>
+</ul>
+
+-->
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>