summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2007-11-27 11:58:35 +0100
committerBenoit Foucher <benoit@zeroc.com>2007-11-27 11:58:35 +0100
commit47f800495093fd7679a315e2d730fea22f6135b7 (patch)
treea7b8d3488f3841367dd03d10cae293f36fd10481 /java/src
parentFixed SystemException to no longer derive from LocalException (diff)
downloadice-47f800495093fd7679a315e2d730fea22f6135b7.tar.bz2
ice-47f800495093fd7679a315e2d730fea22f6135b7.tar.xz
ice-47f800495093fd7679a315e2d730fea22f6135b7.zip
- Added support for non-blocking AMI/batch requests, connection
creation. - Added support for AMI oneway requests. - Changed collocation optimization to not perform any DNS lookups.
Diffstat (limited to 'java/src')
-rw-r--r--java/src/Freeze/ObjectStore.java28
-rw-r--r--java/src/Ice/AMI_Object_ice_flushBatchRequests.java35
-rw-r--r--java/src/Ice/ConnectionI.java2461
-rw-r--r--java/src/Ice/InputStreamI.java8
-rw-r--r--java/src/Ice/ObjectAdapterI.java49
-rw-r--r--java/src/Ice/ObjectPrx.java3
-rw-r--r--java/src/Ice/ObjectPrxHelperBase.java85
-rw-r--r--java/src/Ice/OutputStreamI.java6
-rw-r--r--java/src/Ice/_ObjectDel.java6
-rw-r--r--java/src/Ice/_ObjectDelD.java16
-rw-r--r--java/src/Ice/_ObjectDelM.java95
-rw-r--r--java/src/IceInternal/BasicStream.java303
-rw-r--r--java/src/IceInternal/BatchOutgoing.java92
-rw-r--r--java/src/IceInternal/BatchOutgoingAsync.java106
-rw-r--r--java/src/IceInternal/Buffer.java183
-rw-r--r--java/src/IceInternal/ConnectRequestHandler.java480
-rw-r--r--java/src/IceInternal/ConnectionMonitor.java2
-rw-r--r--java/src/IceInternal/ConnectionRequestHandler.java134
-rw-r--r--java/src/IceInternal/Connector.java1
-rw-r--r--java/src/IceInternal/DirectReference.java59
-rw-r--r--java/src/IceInternal/EndpointFactoryManager.java7
-rw-r--r--java/src/IceInternal/EndpointHostResolver.java166
-rw-r--r--java/src/IceInternal/EndpointI.java20
-rw-r--r--java/src/IceInternal/EndpointI_connectors.java16
-rw-r--r--java/src/IceInternal/EventHandler.java16
-rw-r--r--java/src/IceInternal/FixedReference.java14
-rw-r--r--java/src/IceInternal/IncomingConnectionFactory.java244
-rw-r--r--java/src/IceInternal/IndirectReference.java167
-rw-r--r--java/src/IceInternal/Instance.java76
-rw-r--r--java/src/IceInternal/LocatorInfo.java373
-rw-r--r--java/src/IceInternal/Network.java103
-rw-r--r--java/src/IceInternal/Outgoing.java217
-rw-r--r--java/src/IceInternal/OutgoingAsync.java328
-rw-r--r--java/src/IceInternal/OutgoingAsyncMessageCallback.java16
-rw-r--r--java/src/IceInternal/OutgoingConnectionFactory.java1199
-rw-r--r--java/src/IceInternal/OutgoingMessageCallback.java16
-rw-r--r--java/src/IceInternal/PropertyNames.java2
-rw-r--r--java/src/IceInternal/ProtocolPluginFacade.java10
-rw-r--r--java/src/IceInternal/ProtocolPluginFacadeI.java18
-rw-r--r--java/src/IceInternal/Reference.java7
-rw-r--r--java/src/IceInternal/ReferenceFactory.java2
-rw-r--r--java/src/IceInternal/RequestHandler.java34
-rw-r--r--java/src/IceInternal/RoutableReference.java171
-rw-r--r--java/src/IceInternal/RouterInfo.java223
-rw-r--r--java/src/IceInternal/RouterManager.java5
-rw-r--r--java/src/IceInternal/SelectorThread.java511
-rw-r--r--java/src/IceInternal/SocketStatus.java39
-rw-r--r--java/src/IceInternal/TcpAcceptor.java2
-rw-r--r--java/src/IceInternal/TcpConnector.java41
-rw-r--r--java/src/IceInternal/TcpEndpointI.java41
-rw-r--r--java/src/IceInternal/TcpTransceiver.java234
-rw-r--r--java/src/IceInternal/ThreadPool.java173
-rw-r--r--java/src/IceInternal/ThreadPoolWorkItem.java15
-rw-r--r--java/src/IceInternal/Time.java2
-rw-r--r--java/src/IceInternal/Timer.java6
-rw-r--r--java/src/IceInternal/TraceUtil.java418
-rw-r--r--java/src/IceInternal/Transceiver.java47
-rw-r--r--java/src/IceInternal/UdpConnector.java26
-rw-r--r--java/src/IceInternal/UdpEndpointI.java45
-rw-r--r--java/src/IceInternal/UdpTransceiver.java186
-rw-r--r--java/src/IceInternal/UnknownEndpointI.java14
-rw-r--r--java/src/IceSSL/AcceptorI.java63
-rw-r--r--java/src/IceSSL/ConnectorI.java81
-rw-r--r--java/src/IceSSL/EndpointI.java39
-rw-r--r--java/src/IceSSL/Instance.java7
-rw-r--r--java/src/IceSSL/TransceiverI.java825
66 files changed, 7367 insertions, 3050 deletions
diff --git a/java/src/Freeze/ObjectStore.java b/java/src/Freeze/ObjectStore.java
index bf176a36dff..df7593db2c2 100644
--- a/java/src/Freeze/ObjectStore.java
+++ b/java/src/Freeze/ObjectStore.java
@@ -313,9 +313,9 @@ class ObjectStore implements IceUtil.Store
{
IceInternal.BasicStream os = new IceInternal.BasicStream(Ice.Util.getInstance(communicator));
v.__write(os);
- java.nio.ByteBuffer buf = os.prepareWrite();
- byte[] r = new byte[buf.limit()];
- buf.get(r);
+ IceInternal.Buffer buf = os.prepareWrite();
+ byte[] r = new byte[buf.size()];
+ buf.b.get(r);
return r;
}
@@ -324,10 +324,10 @@ class ObjectStore implements IceUtil.Store
{
IceInternal.BasicStream is = new IceInternal.BasicStream(Ice.Util.getInstance(communicator));
is.resize(b.length, true);
- java.nio.ByteBuffer buf = is.prepareRead();
- buf.position(0);
- buf.put(b);
- buf.position(0);
+ IceInternal.Buffer buf = is.getBuffer();
+ buf.b.position(0);
+ buf.b.put(b);
+ buf.b.position(0);
Ice.Identity key = new Ice.Identity();
key.__read(is);
return key;
@@ -341,9 +341,9 @@ class ObjectStore implements IceUtil.Store
v.__write(os);
os.writePendingObjects();
os.endWriteEncaps();
- java.nio.ByteBuffer buf = os.prepareWrite();
- byte[] r = new byte[buf.limit()];
- buf.get(r);
+ IceInternal.Buffer buf = os.prepareWrite();
+ byte[] r = new byte[buf.size()];
+ buf.b.get(r);
return r;
}
@@ -353,10 +353,10 @@ class ObjectStore implements IceUtil.Store
IceInternal.BasicStream is = new IceInternal.BasicStream(Ice.Util.getInstance(communicator));
is.sliceObjects(false);
is.resize(b.length, true);
- java.nio.ByteBuffer buf = is.prepareRead();
- buf.position(0);
- buf.put(b);
- buf.position(0);
+ IceInternal.Buffer buf = is.getBuffer();
+ buf.b.position(0);
+ buf.b.put(b);
+ buf.b.position(0);
ObjectRecord rec= new ObjectRecord();
is.startReadEncaps();
rec.__read(is);
diff --git a/java/src/Ice/AMI_Object_ice_flushBatchRequests.java b/java/src/Ice/AMI_Object_ice_flushBatchRequests.java
new file mode 100644
index 00000000000..ca68d1c2382
--- /dev/null
+++ b/java/src/Ice/AMI_Object_ice_flushBatchRequests.java
@@ -0,0 +1,35 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package Ice;
+
+public abstract class AMI_Object_ice_flushBatchRequests extends IceInternal.BatchOutgoingAsync
+{
+ public abstract void ice_exception(LocalException ex);
+
+ public final void __invoke(Ice.ObjectPrx prx)
+ {
+ Ice._ObjectDel delegate;
+ IceInternal.RequestHandler handler;
+ try
+ {
+ Ice.ObjectPrxHelperBase proxy = (Ice.ObjectPrxHelperBase)prx;
+ __prepare(proxy.__reference().getInstance());
+ delegate = proxy.__getDelegate(true);
+ handler = delegate.__getRequestHandler();
+ }
+ catch(Ice.LocalException ex)
+ {
+ __finished(ex);
+ return;
+ }
+
+ handler.flushAsyncBatchRequests(this);
+ }
+}
diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java
index e1990c041a7..efdb68da8c1 100644
--- a/java/src/Ice/ConnectionI.java
+++ b/java/src/Ice/ConnectionI.java
@@ -9,68 +9,118 @@
package Ice;
-public final class ConnectionI extends IceInternal.EventHandler implements Connection
+public final class ConnectionI extends IceInternal.EventHandler
+ implements Connection, IceInternal.SelectorThread.SocketReadyCallback
{
+ public interface StartCallback
+ {
+ void connectionStartCompleted(ConnectionI connection);
+ void connectionStartFailed(ConnectionI connection, Ice.LocalException ex);
+ }
+
public void
- validate()
+ start(StartCallback callback)
{
- if(!_endpoint.datagram()) // Datagram connections are always implicitly validated.
+ try
{
- boolean active;
-
synchronized(this)
{
- if(_thread != null && _thread != Thread.currentThread())
+ _startCallback = callback;
+
+ //
+ // The connection might already be closed if the communicator was destroyed.
+ //
+ if(_state == StateClosed)
{
- //
- // In thread per connection mode, this connection's thread
- // will take care of connection validation. Therefore all we
- // have to do here is to wait until this thread has completed
- // validation.
- //
- while(_state == StateNotValidated)
+ assert(_exception != null);
+ throw _exception;
+ }
+
+ //
+ // In thread per connection mode, we create the thread for the connection. The
+ // intialization and validation of the connection is taken care of by the thread
+ // per connection. If a callback is given, no need to wait, the thread will notify
+ // the callback, otherwise wait until the connection is validated.
+ //
+ if(_threadPerConnection)
+ {
+ try
{
- try
+ _thread = new ThreadPerConnection();
+ _thread.start();
+ }
+ catch(java.lang.Exception ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ _logger.error("cannot create thread for connection:\n" + sw.toString());
+
+ //
+ // Clean up.
+ //
+ _thread = null;
+ _state = StateClosed;
+
+ Ice.SyscallException e = new Ice.SyscallException();
+ e.initCause(ex);
+ throw e;
+ }
+
+ if(callback == null) // Wait for the connection to be validated.
+ {
+ while(_state <= StateNotValidated)
{
- wait();
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException ex)
+ {
+ }
}
- catch(InterruptedException ex)
+
+ if(_state >= StateClosing)
{
+ assert(_exception != null);
+ throw _exception;
}
}
-
- if(_state >= StateClosing)
- {
- assert(_exception != null);
- throw _exception;
- }
-
- return;
+ return; // We're done.
}
+ }
- //
- // The connection might already be closed (e.g.: the communicator
- // was destroyed or object adapter deactivated.)
- //
- assert(_state == StateNotValidated || _state == StateClosed);
+ assert(!_threadPerConnection);
+
+ //
+ // Initialize the connection transceiver and then validate the connection.
+ //
+ IceInternal.SocketStatus status = initialize();
+ if(status == IceInternal.SocketStatus.Finished)
+ {
+ status = validate();
+ }
+
+ if(status == IceInternal.SocketStatus.Finished)
+ {
+ finishStart(null);
+ return; // We're done!
+ }
+
+ //
+ // If the initialization or validation couldn't be completed without potentially
+ // blocking, we register the connection with the selector thread and return.
+ //
+
+ synchronized(this)
+ {
if(_state == StateClosed)
{
assert(_exception != null);
throw _exception;
}
-
- if(_adapter != null)
- {
- active = true; // The server side has the active role for connection validation.
- }
- else
- {
- active = false; // The client side has the passive role for connection validation.
- }
- }
- try
- {
int timeout;
IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
if(defaultsAndOverrides.overrideConnectTimeout)
@@ -81,159 +131,76 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
timeout = _endpoint.timeout();
}
+
+ _sendInProgress = true;
+ _selectorThread._register(_transceiver.fd(), this, status, timeout);
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ synchronized(this)
+ {
+ setState(StateClosed, ex);
- if(active)
+ //
+ // If start is called with a callback, the callback is notified either by the
+ // thread per conncetion or the thread pool.
+ //
+ if(callback != null)
{
- synchronized(_sendMutex)
+ if(!_threadPerConnection)
{
- if(_transceiver == null) // Has the transceiver already been closed?
- {
- assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
- }
-
- IceInternal.BasicStream os = new IceInternal.BasicStream(_instance);
- os.writeBlob(IceInternal.Protocol.magic);
- os.writeByte(IceInternal.Protocol.protocolMajor);
- os.writeByte(IceInternal.Protocol.protocolMinor);
- os.writeByte(IceInternal.Protocol.encodingMajor);
- os.writeByte(IceInternal.Protocol.encodingMinor);
- os.writeByte(IceInternal.Protocol.validateConnectionMsg);
- os.writeByte((byte)0); // Compression status (always zero for validate connection).
- os.writeInt(IceInternal.Protocol.headerSize); // Message size.
- IceInternal.TraceUtil.traceHeader("sending validate connection", os, _logger, _traceLevels);
- try
- {
- _transceiver.write(os, timeout);
- }
- catch(Ice.TimeoutException ex)
- {
- throw new Ice.ConnectTimeoutException();
- }
+ registerWithPool();
+ unregisterWithPool(); // Let finished() do the close.
}
+ return;
}
- else
+
+ //
+ // Close the transceiver if there's no thread per connection. Otherwise, wait
+ // for the thread per connection to take care of it.
+ //
+ if(_thread == null && _transceiver != null)
{
- IceInternal.BasicStream is = new IceInternal.BasicStream(_instance);
- is.resize(IceInternal.Protocol.headerSize, true);
- is.pos(0);
try
{
- _transceiver.read(is, timeout);
- }
- catch(Ice.TimeoutException ex)
- {
- throw new Ice.ConnectTimeoutException();
- }
- assert(is.pos() == IceInternal.Protocol.headerSize);
- is.pos(0);
- byte[] m = is.readBlob(4);
- if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] ||
- m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3])
- {
- BadMagicException ex = new BadMagicException();
- ex.badMagic = m;
- throw ex;
- }
- byte pMajor = is.readByte();
- byte pMinor = is.readByte();
- if(pMajor != IceInternal.Protocol.protocolMajor)
- {
- UnsupportedProtocolException e = new UnsupportedProtocolException();
- e.badMajor = pMajor < 0 ? pMajor + 255 : pMajor;
- e.badMinor = pMinor < 0 ? pMinor + 255 : pMinor;
- e.major = IceInternal.Protocol.protocolMajor;
- e.minor = IceInternal.Protocol.protocolMinor;
- throw e;
- }
- byte eMajor = is.readByte();
- byte eMinor = is.readByte();
- if(eMajor != IceInternal.Protocol.encodingMajor)
- {
- UnsupportedEncodingException e = new UnsupportedEncodingException();
- e.badMajor = eMajor < 0 ? eMajor + 255 : eMajor;
- e.badMinor = eMinor < 0 ? eMinor + 255 : eMinor;
- e.major = IceInternal.Protocol.encodingMajor;
- e.minor = IceInternal.Protocol.encodingMinor;
- throw e;
- }
- byte messageType = is.readByte();
- if(messageType != IceInternal.Protocol.validateConnectionMsg)
- {
- throw new ConnectionNotValidatedException();
+ _transceiver.close();
}
- byte compress = is.readByte(); // Ignore compression status for validate connection.
- int size = is.readInt();
- if(size != IceInternal.Protocol.headerSize)
+ catch(LocalException e)
{
- throw new IllegalMessageSizeException();
+ // Here we ignore any exceptions in close().
}
- IceInternal.TraceUtil.traceHeader("received validate connection", is, _logger, _traceLevels);
- }
- }
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- synchronized(this)
- {
- setState(StateClosed, ex.get());
- assert(_exception != null);
- throw _exception;
- }
- }
- catch(LocalException ex)
- {
- synchronized(this)
- {
- setState(StateClosed, ex);
- assert(_exception != null);
- throw _exception;
+ _transceiver = null;
}
}
- }
-
- synchronized(this)
- {
- if(_acmTimeout > 0)
- {
- _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
- }
-
- //
- // We start out in holding state.
- //
- setState(StateHolding);
+
+ waitUntilFinished();
+ throw ex;
}
}
public synchronized void
activate()
{
- while(_state == StateNotValidated)
+ if(_state <= StateNotValidated)
{
- try
- {
- wait();
- }
- catch(InterruptedException ex)
- {
- }
+ return;
}
+ if(_acmTimeout > 0)
+ {
+ _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ }
+
setState(StateActive);
}
public synchronized void
hold()
{
- while(_state == StateNotValidated)
+ if(_state <= StateNotValidated)
{
- try
- {
- wait();
- }
- catch(InterruptedException ex)
- {
- }
+ return;
}
setState(StateHolding);
@@ -243,60 +210,92 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public final static int ObjectAdapterDeactivated = 0;
public final static int CommunicatorDestroyed = 1;
- public synchronized void
+ public void
destroy(int reason)
{
- switch(reason)
+ boolean send = false;
+ synchronized(this)
{
- case ObjectAdapterDeactivated:
+ switch(reason)
{
- setState(StateClosing, new ObjectAdapterDeactivatedException());
- break;
+ case ObjectAdapterDeactivated:
+ {
+ send = setState(StateClosing, new ObjectAdapterDeactivatedException());
+ break;
+ }
+
+ case CommunicatorDestroyed:
+ {
+ send = setState(StateClosing, new CommunicatorDestroyedException());
+ break;
+ }
}
-
- case CommunicatorDestroyed:
+ }
+
+ if(send)
+ {
+ try
{
- setState(StateClosing, new CommunicatorDestroyedException());
- break;
+ finishSendMessage();
+ }
+ catch(Ice.LocalException ex)
+ {
+ // Ignore.
}
}
}
- public synchronized void
+ public void
close(boolean force)
{
- if(force)
- {
- setState(StateClosed, new ForcedCloseConnectionException());
- }
- else
+ boolean send = false;
+ synchronized(this)
{
- //
- // If we do a graceful shutdown, then we wait until all
- // outstanding requests have been completed. Otherwise,
- // the CloseConnectionException will cause all outstanding
- // requests to be retried, regardless of whether the
- // server has processed them or not.
- //
- while(!_requests.isEmpty() || !_asyncRequests.isEmpty())
+ if(force)
{
- try
- {
- wait();
- }
- catch(InterruptedException ex)
+ setState(StateClosed, new ForcedCloseConnectionException());
+ }
+ else
+ {
+ //
+ // If we do a graceful shutdown, then we wait until all
+ // outstanding requests have been completed. Otherwise,
+ // the CloseConnectionException will cause all outstanding
+ // requests to be retried, regardless of whether the
+ // server has processed them or not.
+ //
+ while(!_requests.isEmpty() || !_asyncRequests.isEmpty())
{
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException ex)
+ {
+ }
}
+
+ send = setState(StateClosing, new CloseConnectionException());
}
+ }
- setState(StateClosing, new CloseConnectionException());
+ if(send)
+ {
+ try
+ {
+ finishSendMessage();
+ }
+ catch(Ice.LocalException ex)
+ {
+ // Ignore.
+ }
}
}
public synchronized boolean
- isDestroyed()
+ isActiveOrHolding()
{
- return _state >= StateClosing;
+ return _state > StateNotValidated && _state < StateClosing;
}
public boolean
@@ -461,56 +460,57 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
}
- public synchronized void
+ public void
monitor()
{
- if(_state != StateActive)
+ boolean send = false;
+ synchronized(this)
{
- return;
- }
+ if(_state != StateActive)
+ {
+ return;
+ }
- //
- // Check for timed out async requests.
- //
- java.util.Iterator i = _asyncRequests.entryIterator();
- while(i.hasNext())
- {
- IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
- IceInternal.OutgoingAsync out = (IceInternal.OutgoingAsync)e.getValue();
- if(out.__timedOut())
+ //
+ // Active connection management for idle connections.
+ //
+ if(_acmTimeout <= 0 ||
+ !_requests.isEmpty() || !_asyncRequests.isEmpty() ||
+ _batchStreamInUse || !_batchStream.isEmpty() ||
+ _sendInProgress || _dispatchCount > 0)
{
- setState(StateClosed, new TimeoutException());
return;
}
+
+ if(IceInternal.Time.currentMonotonicTimeMillis() >= _acmAbsoluteTimeoutMillis)
+ {
+ send = setState(StateClosing, new ConnectionTimeoutException());
+ }
}
- //
- // Active connection management for idle connections.
- //
- if(_acmTimeout > 0 &&
- _requests.isEmpty() && _asyncRequests.isEmpty() &&
- !_batchStreamInUse && _batchStream.isEmpty() &&
- _dispatchCount == 0)
+ if(send)
{
- if(IceInternal.Time.currentMonotonicTimeMillis() >= _acmAbsoluteTimeoutMillis)
+ try
{
- setState(StateClosing, new ConnectionTimeoutException());
- return;
+ finishSendMessage();
}
- }
+ catch(Ice.LocalException ex)
+ {
+ // Ignore.
+ }
+ }
}
- public void
- sendRequest(IceInternal.BasicStream os, IceInternal.Outgoing out, boolean compress)
+ public boolean
+ sendRequest(IceInternal.Outgoing out, boolean compress, boolean response)
throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
- IceInternal.BasicStream stream = null;
+ final IceInternal.BasicStream os = out.os();
+ boolean send = false;
synchronized(this)
{
- assert(!(out != null && _endpoint.datagram())); // Twoway requests cannot be datagrams.
-
if(_exception != null)
{
//
@@ -524,10 +524,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
assert(_state > StateNotValidated);
assert(_state < StateClosing);
- //
- // Only add to the request map if this is a twoway call.
- //
- if(out != null)
+ if(response)
{
//
// Create a new unique request ID.
@@ -544,127 +541,67 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
os.pos(IceInternal.Protocol.headerSize);
os.writeInt(requestId);
+ }
+
+ //
+ // Send the message. If it can't be sent without blocking the message is added
+ // to _sendStreams and it will be sent by the selector thread or by this thread
+ // if flush is true.
+ //
+ try
+ {
+ send = sendMessage(new OutgoingMessage(out, out.os(), compress, response), false);
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ assert(_exception != null);
+ throw _exception;
+ }
+ if(response)
+ {
//
// Add to the requests map.
//
_requests.put(requestId, out);
}
- stream = doCompress(os, _overrideCompress ? _overrideCompressValue : compress);
-
- if(_acmTimeout > 0)
+ if(!send)
{
- _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ return !_sendInProgress && _queuedStreams.isEmpty(); // The request was sent if it's not queued!
}
}
- try
+ if(send)
{
- synchronized(_sendMutex)
- {
- if(_transceiver == null) // Has the transceiver already been closed?
- {
- assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
- }
-
- //
- // Send the request.
- //
- IceInternal.TraceUtil.traceRequest("sending request", os, _logger, _traceLevels);
- _transceiver.write(stream, _endpoint.timeout());
- }
- }
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- synchronized(this)
+ try
{
- setState(StateClosed, ex.get());
- assert(_exception != null);
-
- if(out != null)
- {
- //
- // If the request has already been removed from
- // the request map, we are out of luck. It would
- // mean that finished() has been called already,
- // and therefore the exception has been set using
- // the Outgoing::finished() callback. In this
- // case, we cannot throw the exception here,
- // because we must not both raise an exception and
- // have Outgoing::finished() called with an
- // exception. This means that in some rare cases,
- // a request will not be retried even though it
- // could. But I honestly don't know how I could
- // avoid this, without a very elaborate and
- // complex design, which would be bad for
- // performance.
- //
- IceInternal.Outgoing o = (IceInternal.Outgoing)_requests.remove(requestId);
- if(o != null)
- {
- assert(o == out);
- throw new IceInternal.LocalExceptionWrapper(_exception, ex.retry());
- }
- }
- else
- {
- throw new IceInternal.LocalExceptionWrapper(_exception, ex.retry());
- }
+ finishSendMessage();
}
- }
- catch(LocalException ex)
- {
- synchronized(this)
+ catch(Ice.LocalException ex)
{
- setState(StateClosed, ex);
assert(_exception != null);
-
- if(out != null)
- {
- //
- // If the request has already been removed from
- // the request map, we are out of luck. It would
- // mean that finished() has been called already,
- // and therefore the exception has been set using
- // the Outgoing::finished() callback. In this
- // case, we cannot throw the exception here,
- // because we must not both raise an exception and
- // have Outgoing::finished() called with an
- // exception. This means that in some rare cases,
- // a request will not be retried even though it
- // could. But I honestly don't know how I could
- // avoid this, without a very elaborate and
- // complex design, which would be bad for
- // performance.
- //
- IceInternal.Outgoing o = (IceInternal.Outgoing)_requests.remove(requestId);
- if(o != null)
- {
- assert(o == out);
- throw _exception;
- }
- }
- else
+ if(!response) // Twoway calls are notified through finished()
{
- throw _exception;
+ throw ex;
}
}
}
+
+ return true; // The request was sent.
}
public void
- sendAsyncRequest(IceInternal.BasicStream os, IceInternal.OutgoingAsync out, boolean compress)
+ sendAsyncRequest(IceInternal.OutgoingAsync out, boolean compress, boolean response)
throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
- IceInternal.BasicStream stream = null;
+ final IceInternal.BasicStream os = out.__os();
+ boolean send;
synchronized(this)
{
- assert(!_endpoint.datagram()); // Twoway requests cannot be datagrams, and async implies twoway.
-
if(_exception != null)
{
//
@@ -678,109 +615,57 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
assert(_state > StateNotValidated);
assert(_state < StateClosing);
- //
- // Create a new unique request ID.
- //
- requestId = _nextRequestId++;
- if(requestId <= 0)
+ if(response)
{
- _nextRequestId = 1;
+ //
+ // Create a new unique request ID.
+ //
requestId = _nextRequestId++;
+ if(requestId <= 0)
+ {
+ _nextRequestId = 1;
+ requestId = _nextRequestId++;
+ }
+
+ //
+ // Fill in the request ID.
+ //
+ os.pos(IceInternal.Protocol.headerSize);
+ os.writeInt(requestId);
}
-
- //
- // Fill in the request ID.
- //
- os.pos(IceInternal.Protocol.headerSize);
- os.writeInt(requestId);
-
- //
- // Add to the async requests map.
- //
- _asyncRequests.put(requestId, out);
-
- stream = doCompress(os, _overrideCompress ? _overrideCompressValue : compress);
- if(_acmTimeout > 0)
+ try
{
- _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ send = sendMessage(new OutgoingMessage(out, out.__os(), compress, response), false);
}
- }
-
- try
- {
- synchronized(_sendMutex)
+ catch(Ice.LocalException ex)
{
- if(_transceiver == null) // Has the transceiver already been closed?
- {
- assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
- }
+ setState(StateClosed, ex);
+ assert(_exception != null);
+ throw _exception;
+ }
+ if(response)
+ {
//
- // Send the request.
+ // Add to the async requests map.
//
- IceInternal.TraceUtil.traceRequest("sending asynchronous request", os, _logger, _traceLevels);
- _transceiver.write(stream, _endpoint.timeout());
+ _asyncRequests.put(requestId, out);
}
}
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
+
+ if(send)
{
- synchronized(this)
+ try
{
- setState(StateClosed, ex.get());
- assert(_exception != null);
-
- //
- // If the request has already been removed from the
- // async request map, we are out of luck. It would
- // mean that finished() has been called already, and
- // therefore the exception has been set using the
- // OutgoingAsync::__finished() callback. In this case,
- // we cannot throw the exception here, because we must
- // not both raise an exception and have
- // OutgoingAsync::__finished() called with an
- // exception. This means that in some rare cases, a
- // request will not be retried even though it
- // could. But I honestly don't know how I could avoid
- // this, without a very elaborate and complex design,
- // which would be bad for performance.
- //
- IceInternal.OutgoingAsync o = (IceInternal.OutgoingAsync)_asyncRequests.remove(requestId);
- if(o != null)
- {
- assert(o == out);
- throw new IceInternal.LocalExceptionWrapper(_exception, ex.retry());
- }
+ finishSendMessage();
}
- }
- catch(LocalException ex)
- {
- synchronized(this)
+ catch(Ice.LocalException ex)
{
- setState(StateClosed, ex);
assert(_exception != null);
-
- //
- // If the request has already been removed from the
- // async request map, we are out of luck. It would
- // mean that finished() has been called already, and
- // therefore the exception has been set using the
- // OutgoingAsync::__finished() callback. In this case,
- // we cannot throw the exception here, because we must
- // not both raise an exception and have
- // OutgoingAsync::__finished() called with an
- // exception. This means that in some rare cases, a
- // request will not be retried even though it
- // could. But I honestly don't know how I could avoid
- // this, without a very elaborate and complex design,
- // which would be bad for performance.
- //
- IceInternal.OutgoingAsync o = (IceInternal.OutgoingAsync)_asyncRequests.remove(requestId);
- if(o != null)
+ if(!response) // Twoway calls are notified through finished()
{
- assert(o == out);
- throw _exception;
+ throw ex;
}
}
}
@@ -789,6 +674,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public synchronized void
prepareBatchRequest(IceInternal.BasicStream os)
{
+ //
+ // Wait if flushing is currently in progress.
+ //
while(_batchStreamInUse && _exception == null)
{
try
@@ -834,60 +722,110 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public void
finishBatchRequest(IceInternal.BasicStream os, boolean compress)
{
- boolean autoflush = false;
- byte[] lastRequest = null;
-
- synchronized(this)
+ boolean send = false;
+ try
{
- //
- // Get the batch stream back.
- //
- _batchStream.swap(os);
-
- if(_batchAutoFlush)
+ synchronized(this)
{
- synchronized(_sendMutex)
+ //
+ // Get the batch stream back.
+ //
+ _batchStream.swap(os);
+
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+
+ boolean flush = false;
+ if(_batchAutoFlush)
{
- if(_transceiver == null)
- {
- assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
- }
//
- // Throw memory limit exception if the first
- // message added causes us to go over
- // limit. Otherwise put aside the marshalled
- // message that caused limit to be exceeded and
- // rollback stream to the marker.
+ // Throw memory limit exception if the first message added causes us to go over
+ // limit. Otherwise put aside the marshalled message that caused limit to be
+ // exceeded and rollback stream to the marker.
try
{
- _transceiver.checkSendSize(_batchStream, _instance.messageSizeMax());
+ _transceiver.checkSendSize(_batchStream.getBuffer(), _instance.messageSizeMax());
}
catch(Ice.LocalException ex)
{
- if(_batchRequestNum == 0)
+ if(_batchRequestNum > 0)
+ {
+ flush = true;
+ }
+ else
{
- resetBatch(true);
throw ex;
}
+ }
+ }
+
+ if(flush)
+ {
+ //
+ // Temporarily save the last request.
+ //
+ byte[] lastRequest = new byte[_batchStream.size() - _batchMarker];
+ IceInternal.Buffer buffer = _batchStream.getBuffer();
+ buffer.b.position(_batchMarker);
+ buffer.b.get(lastRequest);
+ _batchStream.resize(_batchMarker, false);
- lastRequest = new byte[_batchStream.size() - _batchMarker];
- java.nio.ByteBuffer buffer = _batchStream.prepareRead();
- buffer.position(_batchMarker);
- buffer.get(lastRequest);
- _batchStream.resize(_batchMarker, false);
- autoflush = true;
+ try
+ {
+ //
+ // Fill in the number of requests in the batch.
+ //
+ _batchStream.pos(IceInternal.Protocol.headerSize);
+ _batchStream.writeInt(_batchRequestNum);
+
+ OutgoingMessage message = new OutgoingMessage(_batchStream, _batchRequestCompress, true);
+ send = sendMessage(message, false);
+ if(send)
+ {
+ //
+ // If the request can't be sent immediately and this is a foreground send,
+ // we adopt the stream to be able to re-use _batchStream immediately.
+ //
+ message.adopt();
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ assert(_exception != null);
+ throw _exception;
}
+
+ //
+ // Reset the batch stream.
+ //
+ _batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
+ _batchRequestNum = 0;
+ _batchRequestCompress = false;
+ _batchMarker = 0;
+
+ //
+ // Check again if the last request doesn't exceed the maximum message size.
+ //
+ if(IceInternal.Protocol.requestBatchHdr.length + lastRequest.length > _instance.messageSizeMax())
+ {
+ throw new MemoryLimitException();
+ }
+
+ //
+ // Start a new batch with the last message that caused us to go over the limit.
+ //
+ _batchStream.writeBlob(IceInternal.Protocol.requestBatchHdr);
+ _batchStream.writeBlob(lastRequest);
}
- }
- if(!autoflush)
- {
//
// Increment the number of requests in the batch.
//
++_batchRequestNum;
-
+
//
// We compress the whole batch if there is at least one compressed
// message.
@@ -905,258 +843,247 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
notifyAll();
}
}
-
- if(autoflush)
+ catch(Ice.LocalException ex)
{
- //
- // We have to keep _batchStreamInUse set until after we insert the
- // saved marshalled data into a new stream.
- //
- flushBatchRequestsInternal(true);
-
- synchronized(this)
+ abortBatchRequest();
+ if(send)
{
- //
- // Throw memory limit exception if the message that caused us to go over
- // limit causes us to exceed the limit by itself.
- //
- if(IceInternal.Protocol.requestBatchHdr.length + lastRequest.length > _instance.messageSizeMax())
- {
- resetBatch(true);
- throw new MemoryLimitException();
- }
-
- //
- // Start a new batch with the last message that caused us to
- // go over the limit.
- //
- try
- {
- _batchStream.writeBlob(IceInternal.Protocol.requestBatchHdr);
- _batchStream.writeBlob(lastRequest);
- }
- catch(LocalException ex)
- {
- setState(StateClosed, ex);
- throw ex;
- }
-
- if(compress)
- {
- _batchRequestCompress = true;
- }
-
- //
- // Notify that the batch stream not in use anymore.
- //
- ++_batchRequestNum;
- _batchStreamInUse = false;
- notifyAll();
+ finishSendMessage(); // Let exceptions go through to report auto-flush failures to the caller.
}
+ throw ex;
+ }
+
+ if(send)
+ {
+ finishSendMessage(); // Let exceptions go through to report auto-flush failures to the caller.
}
}
public synchronized void
abortBatchRequest()
{
- //
- // Reset the batch stream. We cannot save old requests
- // in the batch stream, as they might be corrupted due to
- // incomplete marshaling.
- //
- resetBatch(true);
+ _batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
+ _batchRequestNum = 0;
+ _batchRequestCompress = false;
+ _batchMarker = 0;
+
+ assert(_batchStreamInUse);
+ _batchStreamInUse = false;
+ notifyAll();
}
public void
flushBatchRequests()
{
- flushBatchRequestsInternal(false);
+ IceInternal.BatchOutgoing out = new IceInternal.BatchOutgoing(this, _instance);
+ out.invoke();
}
- private void
- flushBatchRequestsInternal(boolean ignoreInUse)
+ public boolean
+ flushBatchRequests(IceInternal.BatchOutgoing out)
{
- IceInternal.BasicStream stream = null;
-
+ boolean send = false;
synchronized(this)
{
- if(!ignoreInUse)
+ while(_batchStreamInUse && _exception == null)
{
- while(_batchStreamInUse && _exception == null)
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException ex)
{
- try
- {
- wait();
- }
- catch(InterruptedException ex)
- {
- }
}
}
-
+
if(_exception != null)
{
throw _exception;
}
- if(_batchStream.isEmpty())
+ if(_batchRequestNum == 0)
{
- return; // Nothing to do.
+ return true;
}
- assert(_state > StateNotValidated);
- assert(_state < StateClosing);
-
- //
- // Fill in the message size.
- //
- _batchStream.pos(10);
- _batchStream.writeInt(_batchStream.size());
-
//
// Fill in the number of requests in the batch.
//
+ _batchStream.pos(IceInternal.Protocol.headerSize);
_batchStream.writeInt(_batchRequestNum);
+
+ _batchStream.swap(out.os());
- stream = doCompress(_batchStream, _overrideCompress ? _overrideCompressValue : _batchRequestCompress);
-
- if(_acmTimeout > 0)
+ try
{
- _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ OutgoingMessage message = new OutgoingMessage(out, out.os(), _batchRequestCompress, false);
+ send = sendMessage(message, false);
}
-
+ catch(Ice.LocalException ex)
+ {
+ setState(StateClosed, ex);
+ assert(_exception != null);
+ throw _exception;
+ }
+
//
- // Prevent that new batch requests are added while we are
- // flushing.
+ // Reset the batch stream.
//
- _batchStreamInUse = true;
+ _batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
+ _batchRequestNum = 0;
+ _batchRequestCompress = false;
+ _batchMarker = 0;
+
+ if(!send)
+ {
+ return !_sendInProgress && _queuedStreams.isEmpty(); // The request was sent if it's not queued!
+ }
}
- try
+ if(send)
{
- synchronized(_sendMutex)
+ finishSendMessage();
+ }
+ return true;
+ }
+
+ public void
+ flushAsyncBatchRequests(IceInternal.BatchOutgoingAsync outAsync)
+ {
+ boolean send = false;
+ synchronized(this)
+ {
+ while(_batchStreamInUse && _exception == null)
{
- if(_transceiver == null) // Has the transceiver already been closed?
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException ex)
{
- assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
}
-
- //
- // Send the batch request.
- //
- IceInternal.TraceUtil.traceBatchRequest("sending batch request", _batchStream, _logger, _traceLevels);
- _transceiver.write(stream, _endpoint.timeout());
}
- }
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- synchronized(this)
+
+ if(_exception != null)
{
- setState(StateClosed, ex.get());
- assert(_exception != null);
-
- //
- // Since batch requests are all oneways (or datagrams), we
- // must report the exception to the caller.
- //
throw _exception;
}
- }
- catch(LocalException ex)
- {
- synchronized(this)
+
+ if(_batchRequestNum == 0)
+ {
+ return;
+ }
+
+ //
+ // Fill in the number of requests in the batch.
+ //
+ _batchStream.pos(IceInternal.Protocol.headerSize);
+ _batchStream.writeInt(_batchRequestNum);
+
+ _batchStream.swap(outAsync.__os());
+
+ try
+ {
+ OutgoingMessage message = new OutgoingMessage(outAsync, outAsync.__os(), _batchRequestCompress, false);
+ send = sendMessage(message, false);
+ }
+ catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
-
- //
- // Since batch requests are all oneways (or datagrams), we
- // must report the exception to the caller.
- //
throw _exception;
}
- }
-
- synchronized(this)
- {
+
//
- // Reset the batch stream, and notify that flushing is over.
+ // Reset the batch stream.
//
- resetBatch(!ignoreInUse);
+ _batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
+ _batchRequestNum = 0;
+ _batchRequestCompress = false;
+ _batchMarker = 0;
}
- }
- private void
- resetBatch(boolean resetInUse)
- {
- _batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
- _batchRequestNum = 0;
- _batchRequestCompress = false;
-
- //
- // Notify about the batch stream not being in use anymore.
- //
- if(resetInUse)
+ if(send)
{
- assert(_batchStreamInUse);
- _batchStreamInUse = false;
- notifyAll();
+ finishSendMessage();
}
}
public void
sendResponse(IceInternal.BasicStream os, byte compressFlag)
{
- IceInternal.BasicStream stream = null;
- try
+ boolean send = false;
+ synchronized(this)
{
- synchronized(_sendMutex)
+ assert(_state > StateNotValidated);
+
+ try
{
- if(_transceiver == null) // Has the transceiver already been closed?
+ if(--_dispatchCount == 0)
+ {
+ notifyAll();
+ }
+
+ if(_state == StateClosed)
{
assert(_exception != null);
- throw _exception; // The exception is immutable at this point.
+ throw _exception;
}
- stream = doCompress(os, compressFlag != 0);
+ send = sendMessage(new OutgoingMessage(os, compressFlag != 0, true), false);
+
+ if(_state == StateClosing && _dispatchCount == 0)
+ {
+ initiateShutdown(true);
+ }
- //
- // Send the reply.
- //
- IceInternal.TraceUtil.traceReply("sending reply", os, _logger, _traceLevels);
- _transceiver.write(stream, _endpoint.timeout());
+ if(_acmTimeout > 0)
+ {
+ _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ }
}
- }
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- synchronized(this)
+ catch(LocalException ex)
{
- setState(StateClosed, ex.get());
+ setState(StateClosed, ex);
}
}
- catch(LocalException ex)
+
+ if(send)
{
- synchronized(this)
+ try
{
- setState(StateClosed, ex);
+ finishSendMessage();
+ }
+ catch(Ice.LocalException ex)
+ {
+ // Ignore.
}
}
+ }
+ public void
+ sendNoResponse()
+ {
+ boolean send = false;
synchronized(this)
{
assert(_state > StateNotValidated);
-
try
{
if(--_dispatchCount == 0)
{
notifyAll();
}
-
+
+ if(_state == StateClosed)
+ {
+ assert(_exception != null);
+ throw _exception;
+ }
+
if(_state == StateClosing && _dispatchCount == 0)
{
- initiateShutdown();
+ send = initiateShutdown(false);
}
if(_acmTimeout > 0)
@@ -1164,49 +1091,29 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
_acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
}
}
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- setState(StateClosed, ex.get());
- }
catch(LocalException ex)
{
setState(StateClosed, ex);
}
}
- }
- public synchronized void
- sendNoResponse()
- {
- assert(_state > StateNotValidated);
-
- try
+ if(send)
{
- if(--_dispatchCount == 0)
+ try
{
- notifyAll();
+ finishSendMessage();
}
-
- if(_state == StateClosing && _dispatchCount == 0)
+ catch(Ice.LocalException ex)
{
- initiateShutdown();
+ // Ignore.
}
}
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- setState(StateClosed, ex.get());
- }
- catch(LocalException ex)
- {
- setState(StateClosed, ex);
- }
}
public IceInternal.EndpointI
endpoint()
{
- // No mutex protection necessary, _endpoint is immutable.
- return _endpoint;
+ return _endpoint; // No mutex protection necessary, _endpoint is immutable.
}
public boolean
@@ -1218,11 +1125,15 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public synchronized void
setAdapter(ObjectAdapter adapter)
{
- if(_exception != null)
+ if(_state == StateClosing || _state == StateClosed)
{
+ assert(_exception != null);
throw _exception;
}
-
+ else if(_state <= StateNotValidated)
+ {
+ return;
+ }
assert(_state < StateClosing);
_adapter = adapter;
@@ -1253,7 +1164,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
return _adapter;
}
- public synchronized ObjectPrx
+ public ObjectPrx
createProxy(Identity ident)
{
//
@@ -1262,9 +1173,8 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
ConnectionI[] connections = new ConnectionI[1];
connections[0] = this;
- IceInternal.Reference ref =
- _instance.referenceFactory().create(ident, _instance.getDefaultContext(), "",
- IceInternal.Reference.ModeTwoway, connections);
+ IceInternal.Reference ref = _instance.referenceFactory().create(ident, _instance.getDefaultContext(), "",
+ IceInternal.Reference.ModeTwoway, connections);
return _instance.proxyFactory().referenceToProxy(ref);
}
@@ -1291,7 +1201,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
assert(!_threadPerConnection); // Only for use with a thread pool.
- return _transceiver.read(stream, 0);
+ return _transceiver.read(stream.getBuffer(), 0, _hasMoreData);
//
// Updating _acmAbsoluteTimeoutMillis is too expensive here,
@@ -1301,6 +1211,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
}
+ public boolean
+ hasMoreData()
+ {
+ return _hasMoreData.value;
+ }
+
public void
message(IceInternal.BasicStream stream, IceInternal.ThreadPool threadPool)
{
@@ -1355,69 +1271,58 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
assert(!_threadPerConnection); // Only for use with a thread pool.
threadPool.promoteFollower();
-
- LocalException localEx = null;
-
- IceInternal.IntMap requests = null;
- IceInternal.IntMap asyncRequests = null;
+
+ Ice.LocalException localEx = null;
synchronized(this)
{
--_finishedCount;
- if(_finishedCount == 0 && _state == StateClosed)
+ if(_finishedCount > 0 || _state != StateClosed || _sendInProgress)
{
- //
- // We must make sure that nobody is sending when we
- // close the transceiver.
- //
- synchronized(_sendMutex)
- {
- try
- {
- _transceiver.close();
- }
- catch(LocalException ex)
- {
- localEx = ex;
- }
-
- _transceiver = null;
- notifyAll();
- }
+ return;
}
-
- if(_state == StateClosed || _state == StateClosing)
+
+ try
{
- requests = _requests;
- _requests = new IceInternal.IntMap();
-
- asyncRequests = _asyncRequests;
- _asyncRequests = new IceInternal.IntMap();
+ _transceiver.close();
}
+ catch(LocalException ex)
+ {
+ localEx = ex;
+ }
+
+ _transceiver = null;
+ notifyAll();
}
+
+ finishStart(_exception);
- if(requests != null)
+ java.util.Iterator i = _queuedStreams.iterator();
+ while(i.hasNext())
{
- java.util.Iterator i = requests.entryIterator();
- while(i.hasNext())
- {
- IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
- IceInternal.Outgoing out = (IceInternal.Outgoing)e.getValue();
- out.finished(_exception); // The exception is immutable at this point.
- }
+ OutgoingMessage message = (OutgoingMessage)i.next();
+ message.finished(_exception);
}
+ _queuedStreams.clear();
- if(asyncRequests != null)
+ i = _requests.entryIterator(); // _requests is immutable at this point.
+ while(i.hasNext())
{
- java.util.Iterator i = asyncRequests.entryIterator();
- while(i.hasNext())
- {
- IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
- IceInternal.OutgoingAsync out = (IceInternal.OutgoingAsync)e.getValue();
- out.__finished(_exception); // The exception is immutable at this point.
- }
+ IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
+ IceInternal.Outgoing out = (IceInternal.Outgoing)e.getValue();
+ out.finished(_exception); // The exception is immutable at this point.
}
+ _requests.clear();
+ i = _asyncRequests.entryIterator(); // _asyncRequests is immutable at this point.
+ while(i.hasNext())
+ {
+ IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
+ IceInternal.OutgoingAsync out = (IceInternal.OutgoingAsync)e.getValue();
+ out.__finished(_exception); // The exception is immutable at this point.
+ }
+ _asyncRequests.clear();
+
if(localEx != null)
{
throw localEx;
@@ -1477,6 +1382,147 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
//
+ // Operations from SocketReadyCallback
+ //
+ public IceInternal.SocketStatus
+ socketReady(boolean finished)
+ {
+ if(!finished)
+ {
+ try
+ {
+ //
+ // First, we check if there's something to send. If that's the case, the connection
+ // must be active and the only thing to do is send the queued streams.
+ //
+ if(!_sendStreams.isEmpty())
+ {
+ if(!send(0))
+ {
+ return IceInternal.SocketStatus.NeedWrite;
+ }
+ assert(_sendStreams.isEmpty());
+ }
+ else
+ {
+ //
+ // If there's nothing to send, we're still validating the connection.
+ //
+ int state;
+ synchronized(this)
+ {
+ assert(_state == StateClosed || _state <= StateNotValidated);
+
+ if(_state == StateClosed)
+ {
+ assert(_exception != null);
+ throw _exception;
+ }
+
+ state = _state;
+ }
+
+ if(state == StateNotInitialized)
+ {
+ IceInternal.SocketStatus status = initialize();
+ if(status != IceInternal.SocketStatus.Finished)
+ {
+ return status;
+ }
+ }
+
+ if(state <= StateNotValidated)
+ {
+ IceInternal.SocketStatus status = validate();
+ if(status != IceInternal.SocketStatus.Finished)
+ {
+ return status;
+ }
+ }
+
+ finishStart(null);
+ }
+ }
+ catch(Ice.LocalException ex)
+ {
+ synchronized(this)
+ {
+ setState(StateClosed, ex);
+ }
+ }
+ }
+
+ //
+ // If there's no more data to send or if connection validation is finished, we checkout
+ // the connection state to figure out whether or not it's time to unregister with the
+ // selector thread.
+ //
+
+ synchronized(this)
+ {
+ assert(_sendInProgress);
+ if(_state == StateClosed)
+ {
+ assert(_startCallback == null || (!_threadPerConnection && !_registeredWithPool));
+
+ _queuedStreams.addAll(0, _sendStreams);
+ _sendInProgress = false;
+
+ if(_threadPerConnection)
+ {
+ _transceiver.shutdownReadWrite();
+ }
+ else
+ {
+ registerWithPool();
+ unregisterWithPool(); // Let finished() do the close.
+ }
+
+ notifyAll();
+ return IceInternal.SocketStatus.Finished;
+ }
+ else if(_waitingForSend > 0)
+ {
+ _sendInProgress = false;
+ notifyAll();
+ return IceInternal.SocketStatus.Finished;
+ }
+ else if(_queuedStreams.isEmpty())
+ {
+ _sendInProgress = false;
+ if(_acmTimeout > 0)
+ {
+ _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ }
+ return IceInternal.SocketStatus.Finished;
+ }
+ else
+ {
+ java.util.LinkedList streams = _queuedStreams;
+ _queuedStreams = _sendStreams;
+ _sendStreams = streams;
+ return IceInternal.SocketStatus.NeedWrite; // We're not finished yet, there's more data to send!
+ }
+ }
+ }
+
+ public void
+ socketTimeout()
+ {
+ synchronized(this)
+ {
+ if(_state <= StateNotValidated)
+ {
+ setState(StateClosed, new ConnectTimeoutException());
+ }
+ else if(_state <= StateClosing)
+ {
+ setState(StateClosed, new TimeoutException());
+ }
+ }
+ }
+
+ //
// Only used by the SSL plug-in.
//
// The external party has to synchronize the connection, since the
@@ -1492,29 +1538,32 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
IceInternal.EndpointI endpoint, ObjectAdapter adapter, boolean threadPerConnection)
{
super(instance);
+
+ final Ice.InitializationData initData = instance.initializationData();
_threadPerConnection = threadPerConnection;
_transceiver = transceiver;
_desc = transceiver.toString();
_type = transceiver.type();
_endpoint = endpoint;
_adapter = adapter;
- _logger = instance.initializationData().logger; // Cached for better performance.
+ _logger = initData.logger; // Cached for better performance.
_traceLevels = instance.traceLevels(); // Cached for better performance.
_registeredWithPool = false;
_finishedCount = 0;
- _warn = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Connections") > 0 ? true : false;
- _cacheBuffers = _instance.initializationData().properties.getPropertyAsIntWithDefault(
- "Ice.CacheMessageBuffers", 1) == 1;
+ _warn = initData.properties.getPropertyAsInt("Ice.Warn.Connections") > 0 ? true : false;
+ _cacheBuffers = initData.properties.getPropertyAsIntWithDefault("Ice.CacheMessageBuffers", 1) == 1;
_acmAbsoluteTimeoutMillis = 0;
_nextRequestId = 1;
- _batchAutoFlush = _instance.initializationData().properties.getPropertyAsIntWithDefault(
- "Ice.BatchAutoFlush", 1) > 0 ? true : false;
+ _batchAutoFlush = initData.properties.getPropertyAsIntWithDefault("Ice.BatchAutoFlush", 1) > 0 ? true : false;
_batchStream = new IceInternal.BasicStream(instance, _batchAutoFlush);
_batchStreamInUse = false;
_batchRequestNum = 0;
_batchRequestCompress = false;
+ _batchMarker = 0;
+ _sendInProgress = false;
+ _waitingForSend = 0;
_dispatchCount = 0;
- _state = StateNotValidated;
+ _state = StateNotInitialized;
_stateTime = IceInternal.Time.currentMonotonicTimeMillis();
if(_endpoint.datagram())
@@ -1533,8 +1582,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
}
- int compressionLevel =
- _instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Compression.Level", 1);
+ int compressionLevel = initData.properties.getPropertyAsIntWithDefault("Ice.Compression.Level", 1);
if(compressionLevel < 1)
{
compressionLevel = 1;
@@ -1553,17 +1601,17 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
_servantManager = null;
}
-
- if(!threadPerConnection)
+
+ try
{
- //
- // Only set _threadPool if we really need it, i.e., if we are
- // not in thread per connection mode. Thread pools have lazy
- // initialization in Instance, and we don't want them to be
- // created if they are not needed.
- //
- try
+ if(!threadPerConnection)
{
+ //
+ // Only set _threadPool if we really need it, i.e., if we are
+ // not in thread per connection mode. Thread pools have lazy
+ // initialization in Instance, and we don't want them to be
+ // created if they are not needed.
+ //
if(_adapter != null)
{
_threadPool = ((ObjectAdapterI)_adapter).getThreadPool();
@@ -1573,94 +1621,52 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
_threadPool = _instance.clientThreadPool();
}
}
- catch(java.lang.Exception ex)
+ else
{
- try
- {
- _transceiver.close();
- }
- catch(LocalException e)
- {
- // Here we ignore any exceptions in close().
- }
-
- Ice.SyscallException e = new Ice.SyscallException();
- e.initCause(ex);
- throw e;
+ _threadPool = null; // To satisfy the compiler.
}
+
+ _selectorThread = _instance.selectorThread();
+
+ _overrideCompress = _instance.defaultsAndOverrides().overrideCompress;
+ _overrideCompressValue = _instance.defaultsAndOverrides().overrideCompressValue;
}
- else
+ catch(Ice.LocalException ex)
{
- _threadPool = null; // To satisfy the compiler.
+ throw ex;
+ }
+ catch(java.lang.Exception ex)
+ {
+ Ice.SyscallException e = new Ice.SyscallException();
+ e.initCause(ex);
+ throw e;
}
-
- _overrideCompress = _instance.defaultsAndOverrides().overrideCompress;
- _overrideCompressValue = _instance.defaultsAndOverrides().overrideCompressValue;
}
protected synchronized void
finalize()
throws Throwable
{
+ IceUtil.Assert.FinalizerAssert(_startCallback == null);
IceUtil.Assert.FinalizerAssert(_state == StateClosed);
IceUtil.Assert.FinalizerAssert(_transceiver == null);
IceUtil.Assert.FinalizerAssert(_dispatchCount == 0);
IceUtil.Assert.FinalizerAssert(_thread == null);
+ IceUtil.Assert.FinalizerAssert(_queuedStreams.isEmpty());
+ IceUtil.Assert.FinalizerAssert(_requests.isEmpty());
+ IceUtil.Assert.FinalizerAssert(_asyncRequests.isEmpty());
super.finalize();
}
- public void
- start()
- {
- //
- // If we are in thread per connection mode, create the thread for this connection.
- //
- if(_threadPerConnection)
- {
- try
- {
- _thread = new ThreadPerConnection();
- _thread.start();
- }
- catch(java.lang.Exception ex)
- {
- java.io.StringWriter sw = new java.io.StringWriter();
- java.io.PrintWriter pw = new java.io.PrintWriter(sw);
- ex.printStackTrace(pw);
- pw.flush();
- _logger.error("cannot create thread for connection:\n" + sw.toString());
+ private static final int StateNotInitialized = 0;
+ private static final int StateNotValidated = 1;
+ private static final int StateActive = 2;
+ private static final int StateHolding = 3;
+ private static final int StateClosing = 4;
+ private static final int StateClosed = 5;
- try
- {
- _transceiver.close();
- }
- catch(LocalException e)
- {
- // Here we ignore any exceptions in close().
- }
-
- //
- // Clean up.
- //
- _transceiver = null;
- _thread = null;
- _state = StateClosed;
-
- Ice.SyscallException e = new Ice.SyscallException();
- e.initCause(ex);
- throw e;
- }
- }
- }
-
- private static final int StateNotValidated = 0;
- private static final int StateActive = 1;
- private static final int StateHolding = 2;
- private static final int StateClosing = 3;
- private static final int StateClosed = 4;
-
- private void
+ private boolean
setState(int state, LocalException ex)
{
//
@@ -1671,7 +1677,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
if(_state == state) // Don't switch twice.
{
- return;
+ return false;
}
if(_exception == null)
@@ -1706,10 +1712,10 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
// exceptions. Otherwise new requests may retry on a
// connection that is not yet marked as closed or closing.
//
- setState(state);
+ return setState(state);
}
- private void
+ private boolean
setState(int state)
{
//
@@ -1724,24 +1730,34 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
// Skip graceful shutdown if we are destroyed before validation.
//
- if(_state == StateNotValidated && state == StateClosing)
+ if(_state <= StateNotValidated && state == StateClosing)
{
state = StateClosed;
}
if(_state == state) // Don't switch twice.
{
- return;
+ return false;
}
switch(state)
{
- case StateNotValidated:
+ case StateNotInitialized:
{
assert(false);
break;
}
+ case StateNotValidated:
+ {
+ if(_state != StateNotInitialized)
+ {
+ assert(_state == StateClosed);
+ return false;
+ }
+ break;
+ }
+
case StateActive:
{
//
@@ -1750,7 +1766,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
if(_state != StateHolding && _state != StateNotValidated)
{
- return;
+ return false;
}
if(!_threadPerConnection)
{
@@ -1767,7 +1783,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
if(_state != StateActive && _state != StateNotValidated)
{
- return;
+ return false;
}
if(!_threadPerConnection)
{
@@ -1783,7 +1799,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
if(_state == StateClosed)
{
- return;
+ return false;
}
if(!_threadPerConnection)
{
@@ -1794,60 +1810,43 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
case StateClosed:
{
- if(_threadPerConnection)
- {
- //
- // If we are in thread per connection mode, we
- // shutdown both for reading and writing. This will
- // unblock and read call with an exception. The thread
- // per connection then closes the transceiver.
- //
- _transceiver.shutdownReadWrite();
- }
- else if(_state == StateNotValidated)
+ if(_sendInProgress)
{
//
- // If we change from not validated, we can close right
- // away.
- //
- assert(!_registeredWithPool);
-
+ // Unregister with both the pool and the selector thread. We unregister with
+ // the pool to ensure that it stops reading on the socket (otherwise, if the
+ // socket is closed the thread pool would spin always reading 0 from the FD).
+ // The selector thread will register again the FD with the pool once it's
+ // done.
//
- // We must make sure that nobody is sending when we
- // close the transceiver.
- //
- synchronized(_sendMutex)
+ _selectorThread.unregister(_transceiver.fd());
+ if(!_threadPerConnection)
{
- try
- {
- _transceiver.close();
- }
- catch(LocalException ex)
- {
- // Here we ignore any exceptions in close().
- }
+ unregisterWithPool();
+ }
- _transceiver = null;
- //notifyAll(); // We notify already below.
+ if(_state >= StateNotValidated)
+ {
+ _transceiver.shutdownWrite();
}
}
- else
+ else if(_startCallback == null && _state <= StateNotValidated || _threadPerConnection)
{
//
- // Otherwise we first must make sure that we are
- // registered, then we unregister, and let finished()
- // do the close.
+ // If we are in thread per connection mode and the thread is started, we
+ // shutdown both for reading and writing. This will unblock the read call
+ // with an exception. The thread per connection closes the transceiver.
//
+ _transceiver.shutdownReadWrite();
+ }
+ else
+ {
registerWithPool();
- unregisterWithPool();
-
- //
- // We must prevent any further writes when _state == StateClosed.
- // However, functions such as sendResponse cannot acquire the main
- // mutex in order to check _state. Therefore we shut down the write
- // end of the transceiver, which causes subsequent write attempts
- // to fail with an exception.
+ unregisterWithPool(); // Let finished() do the close.
+
//
+ // Prevent further writes.
+ //
_transceiver.shutdownWrite();
}
break;
@@ -1882,58 +1881,536 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
try
{
- initiateShutdown();
- }
- catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
- {
- setState(StateClosed, ex.get());
+ return initiateShutdown(false);
}
catch(LocalException ex)
{
setState(StateClosed, ex);
}
}
+
+ return false;
}
- private void
- initiateShutdown()
- throws IceInternal.LocalExceptionWrapper // Java-specific workaround in Transceiver.write().
+ private boolean
+ initiateShutdown(boolean queue)
{
assert(_state == StateClosing);
assert(_dispatchCount == 0);
if(!_endpoint.datagram())
{
- synchronized(_sendMutex)
+ //
+ // Before we shut down, we send a close connection
+ // message.
+ //
+ IceInternal.BasicStream os = new IceInternal.BasicStream(_instance);
+ os.writeBlob(IceInternal.Protocol.magic);
+ os.writeByte(IceInternal.Protocol.protocolMajor);
+ os.writeByte(IceInternal.Protocol.protocolMinor);
+ os.writeByte(IceInternal.Protocol.encodingMajor);
+ os.writeByte(IceInternal.Protocol.encodingMinor);
+ os.writeByte(IceInternal.Protocol.closeConnectionMsg);
+ os.writeByte(_compressionSupported ? (byte)1 : (byte)0);
+ os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+
+ return sendMessage(new OutgoingMessage(os, false, false), queue);
+
+ //
+ // The CloseConnection message should be sufficient. Closing the write
+ // end of the socket is probably an artifact of how things were done
+ // in IIOP. In fact, shutting down the write end of the socket causes
+ // problems on Windows by preventing the peer from using the socket.
+ // For example, the peer is no longer able to continue writing a large
+ // message after the socket is shutdown.
+ //
+ //_transceiver.shutdownWrite();
+ }
+
+ return false;
+ }
+
+ private IceInternal.SocketStatus
+ initialize()
+ {
+ int timeout = 0;
+ if(_startCallback == null || _threadPerConnection)
+ {
+ IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideConnectTimeout)
{
- //
- // Before we shut down, we send a close connection
- // message.
- //
- IceInternal.BasicStream os = new IceInternal.BasicStream(_instance);
- os.writeBlob(IceInternal.Protocol.magic);
- os.writeByte(IceInternal.Protocol.protocolMajor);
- os.writeByte(IceInternal.Protocol.protocolMinor);
- os.writeByte(IceInternal.Protocol.encodingMajor);
- os.writeByte(IceInternal.Protocol.encodingMinor);
- os.writeByte(IceInternal.Protocol.closeConnectionMsg);
- os.writeByte(_compressionSupported ? (byte)1 : (byte)0);
- os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+ timeout = defaultsAndOverrides.overrideConnectTimeoutValue;
+ }
+ else
+ {
+ timeout = _endpoint.timeout();
+ }
+ }
+
+ try
+ {
+ IceInternal.SocketStatus status = _transceiver.initialize(timeout);
+ if(status != IceInternal.SocketStatus.Finished)
+ {
+ if(_startCallback == null || _threadPerConnection)
+ {
+ throw new Ice.TimeoutException();
+ }
+ return status;
+ }
+ }
+ catch(Ice.TimeoutException ex)
+ {
+ throw new Ice.ConnectTimeoutException();
+ }
+
+ synchronized(this)
+ {
+ if(_state == StateClosed)
+ {
+ assert(_exception != null);
+ throw _exception;
+ }
+
+ //
+ // Update the connection description once the transceiver is initialized.
+ //
+ _desc = _transceiver.toString();
+
+ setState(StateNotValidated);
+ }
+
+ return IceInternal.SocketStatus.Finished;
+ }
+
+ private IceInternal.SocketStatus
+ validate()
+ {
+ if(!_endpoint.datagram()) // Datagram connections are always implicitly validated.
+ {
+ int timeout = 0;
+ if(_startCallback == null || _threadPerConnection)
+ {
+ IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideConnectTimeout)
+ {
+ timeout = defaultsAndOverrides.overrideConnectTimeoutValue;
+ }
+ else
+ {
+ timeout = _endpoint.timeout();
+ }
+ }
+
+ if(_adapter != null) // The server side has the active role for connection validation.
+ {
+ IceInternal.BasicStream os = _stream;
+ if(os.size() == 0)
+ {
+ os.writeBlob(IceInternal.Protocol.magic);
+ os.writeByte(IceInternal.Protocol.protocolMajor);
+ os.writeByte(IceInternal.Protocol.protocolMinor);
+ os.writeByte(IceInternal.Protocol.encodingMajor);
+ os.writeByte(IceInternal.Protocol.encodingMinor);
+ os.writeByte(IceInternal.Protocol.validateConnectionMsg);
+ os.writeByte((byte)0); // Compression status (always zero for validate connection).
+ os.writeInt(IceInternal.Protocol.headerSize); // Message size.
+ IceInternal.TraceUtil.traceSend(os, _logger, _traceLevels);
+ os.prepareWrite();
+ }
+ else
+ {
+ // The stream can only be non-empty if we're doing a non-blocking connection validation.
+ assert(_startCallback != null && !_threadPerConnection);
+ }
+ try
+ {
+ if(!_transceiver.write(os.getBuffer(), timeout))
+ {
+ if(_startCallback == null || _threadPerConnection)
+ {
+ throw new Ice.TimeoutException();
+ }
+ return IceInternal.SocketStatus.NeedWrite;
+ }
+ }
+ catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
+ {
+ throw ex.get();
+ }
+ catch(Ice.TimeoutException ex)
+ {
+ throw new Ice.ConnectTimeoutException();
+ }
+ }
+ else // The client side has the passive role for connection validation.
+ {
+ IceInternal.BasicStream is = _stream;
+ if(is.size() == 0)
+ {
+ is.resize(IceInternal.Protocol.headerSize, true);
+ is.pos(0);
+ }
+ else
+ {
+ // The stream can only be non-empty if we're doing a non-blocking connection validation.
+ assert(_startCallback != null && !_threadPerConnection);
+ }
+
+ try
+ {
+ if(!_transceiver.read(is.getBuffer(), timeout, _hasMoreData))
+ {
+ if(_startCallback == null || _threadPerConnection)
+ {
+ throw new Ice.TimeoutException();
+ }
+ return IceInternal.SocketStatus.NeedRead;
+ }
+ }
+ catch(Ice.TimeoutException ex)
+ {
+ throw new Ice.ConnectTimeoutException();
+ }
+
+ assert(is.pos() == IceInternal.Protocol.headerSize);
+ is.pos(0);
+ byte[] m = is.readBlob(4);
+ if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] ||
+ m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3])
+ {
+ BadMagicException ex = new BadMagicException();
+ ex.badMagic = m;
+ throw ex;
+ }
+ byte pMajor = is.readByte();
+ byte pMinor = is.readByte();
+ if(pMajor != IceInternal.Protocol.protocolMajor)
+ {
+ UnsupportedProtocolException e = new UnsupportedProtocolException();
+ e.badMajor = pMajor < 0 ? pMajor + 255 : pMajor;
+ e.badMinor = pMinor < 0 ? pMinor + 255 : pMinor;
+ e.major = IceInternal.Protocol.protocolMajor;
+ e.minor = IceInternal.Protocol.protocolMinor;
+ throw e;
+ }
+ byte eMajor = is.readByte();
+ byte eMinor = is.readByte();
+ if(eMajor != IceInternal.Protocol.encodingMajor)
+ {
+ UnsupportedEncodingException e = new UnsupportedEncodingException();
+ e.badMajor = eMajor < 0 ? eMajor + 255 : eMajor;
+ e.badMinor = eMinor < 0 ? eMinor + 255 : eMinor;
+ e.major = IceInternal.Protocol.encodingMajor;
+ e.minor = IceInternal.Protocol.encodingMinor;
+ throw e;
+ }
+ byte messageType = is.readByte();
+ if(messageType != IceInternal.Protocol.validateConnectionMsg)
+ {
+ throw new ConnectionNotValidatedException();
+ }
+ byte compress = is.readByte(); // Ignore compression status for validate connection.
+ int size = is.readInt();
+ if(size != IceInternal.Protocol.headerSize)
+ {
+ throw new IllegalMessageSizeException();
+ }
+ IceInternal.TraceUtil.traceRecv(is, _logger, _traceLevels);
+ }
+ }
+
+ synchronized(this)
+ {
+ _stream.reset();
+
+ if(_state == StateClosed)
+ {
+ assert(_exception != null);
+ throw _exception;
+ }
+
+ //
+ // We start out in holding state.
+ //
+ setState(StateHolding);
+ }
+
+ return IceInternal.SocketStatus.Finished;
+ }
+
+ private boolean
+ send(int timeout)
+ {
+ assert(_transceiver != null);
+ assert(!_sendStreams.isEmpty());
+
+ while(!_sendStreams.isEmpty())
+ {
+ OutgoingMessage message = (OutgoingMessage)_sendStreams.getFirst();
+ if(!message.prepared)
+ {
+ IceInternal.BasicStream stream = message.stream;
+
+ boolean compress = _overrideCompress ? _overrideCompressValue : message.compress;
+ message.stream = doCompress(stream, compress);
+ message.stream.prepareWrite();
+ message.prepared = true;
+
+ if(message.outAsync != null)
+ {
+ IceInternal.TraceUtil.trace("sending asynchronous request", stream, _logger, _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels);
+ }
+
+ }
+
+ try
+ {
+ if(!_transceiver.write(message.stream.getBuffer(), timeout))
+ {
+ assert(timeout == 0);
+ return false;
+ }
+ }
+ catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
+ {
+ if(!ex.retry())
+ {
+ message.sent(this, timeout == 0);
+ }
+ throw ex.get();
+ }
+
+ message.sent(this, timeout == 0); // timeout == 0 indicates that this is called by the selector thread.
+ _sendStreams.removeFirst();
+ }
+
+ return true;
+ }
+
+ private boolean
+ sendMessage(OutgoingMessage message, boolean queue)
+ {
+ assert(_state != StateClosed);
+
+ //
+ // TODO: Remove support for foreground send? If set to true, messages are sent
+ // by the calling thread. Foreground send might still be useful for transports
+ // that don't support non-blocking send.
+ //
+ boolean foreground = false;
+
+ //
+ // If another thread is currently sending messages, we queue the message in _queuedStreams
+ // if we're not required to send the message in the foreground. If we're required to send
+ // the request in the foreground we wait until no more threads send messages.
+ //
+ if(_sendInProgress)
+ {
+ if(!foreground)
+ {
+ message.adopt();
+ _queuedStreams.addLast(message);
+ return false;
+ }
+ else if(queue)
+ {
//
- // Send the message.
- //
- IceInternal.TraceUtil.traceHeader("sending close connection", os, _logger, _traceLevels);
- _transceiver.write(os, _endpoint.timeout());
- //
- // The CloseConnection message should be sufficient. Closing the write
- // end of the socket is probably an artifact of how things were done
- // in IIOP. In fact, shutting down the write end of the socket causes
- // problems on Windows by preventing the peer from using the socket.
- // For example, the peer is no longer able to continue writing a large
- // message after the socket is shutdown.
+ // Add the message to _sendStreams if requested, this is useful for sendResponse() to
+ // send the close connection message after sending the response.
//
- //_transceiver.shutdownWrite();
+ _sendStreams.addLast(message);
+ return true; // The calling thread must send the messages by calling finishSendMessage()
+ }
+ else
+ {
+ ++_waitingForSend;
+ while(_sendInProgress)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+ --_waitingForSend;
+
+ if(_state == StateClosed)
+ {
+ assert(_exception != null);
+ throw _exception;
+ }
+ }
+ }
+
+ assert(!_sendInProgress);
+
+ //
+ // Attempt to send the message without blocking. If the send blocks, we register
+ // the connection with the selector thread or we request the caller to call
+ // finishSendMessage() outside the synchronization.
+ //
+
+ assert(!message.prepared);
+
+ IceInternal.BasicStream stream = message.stream;
+
+ boolean compress = _overrideCompress ? _overrideCompressValue : message.compress;
+ message.stream = doCompress(stream, compress);
+ message.stream.prepareWrite();
+ message.prepared = true;
+
+ if(message.outAsync != null)
+ {
+ IceInternal.TraceUtil.trace("sending asynchronous request", stream, _logger, _traceLevels);
+ }
+ else
+ {
+ IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels);
+ }
+
+ try
+ {
+ if(!foreground && _transceiver.write(message.stream.getBuffer(), 0))
+ {
+ message.sent(this, false);
+ if(_acmTimeout > 0)
+ {
+ _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ }
+ return false;
+ }
+ }
+ catch(IceInternal.LocalExceptionWrapper ex) // Java-specific workaround in Transceiver.write().
+ {
+ if(!ex.retry())
+ {
+ message.sent(this, false);
+ }
+ throw ex.get();
+ }
+
+ _sendStreams.addLast(message);
+ _sendInProgress = true;
+ if(!foreground)
+ {
+ message.adopt();
+ _selectorThread._register(_transceiver.fd(), this, IceInternal.SocketStatus.NeedWrite, _endpoint.timeout());
+ return false; // The selector thread will send the message.
+ }
+ else
+ {
+ return true; // The calling thread must send the message by calling finishSendMessage()
+ }
+ }
+
+ private void
+ finishSendMessage()
+ {
+ try
+ {
+ //
+ // Send the queued messages with a blocking write().
+ //
+ boolean finished = send(_endpoint.timeout());
+ assert(finished);
+ }
+ catch(Ice.LocalException ex)
+ {
+ synchronized(this)
+ {
+ setState(StateClosed, ex);
+
+ _sendStreams.clear();
+ _sendInProgress = false;
+
+ if(_threadPerConnection)
+ {
+ _transceiver.shutdownReadWrite();
+ }
+ else
+ {
+ registerWithPool();
+ unregisterWithPool(); // Let finished() do the close.
+ }
+
+ notifyAll();
+
+ assert(_exception != null);
+ throw _exception;
+ }
+ }
+
+ synchronized(this)
+ {
+ assert(_sendStreams.isEmpty());
+ if(_state == StateClosed)
+ {
+ _sendInProgress = false;
+ if(_threadPerConnection)
+ {
+ _transceiver.shutdownReadWrite();
+ }
+ else
+ {
+ registerWithPool();
+ unregisterWithPool(); // Let finished() do the close.
+ }
+ notifyAll();
+ }
+ if(_waitingForSend > 0)
+ {
+ _sendInProgress = false;
+ notifyAll();
+ }
+ else if(_queuedStreams.isEmpty())
+ {
+ if(_acmTimeout > 0)
+ {
+ _acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
+ }
+ _sendInProgress = false;
+ }
+ else
+ {
+ _selectorThread._register(_transceiver.fd(), this, IceInternal.SocketStatus.NeedWrite,
+ _endpoint.timeout());
+ }
+ }
+ }
+
+ private void
+ finishStart(Ice.LocalException ex)
+ {
+ //
+ // We set _startCallback to null to break potential cyclic reference count
+ // and because the finalizer checks for it to ensure that we always invoke
+ // on the callback.
+ //
+
+ StartCallback callback = null;
+ synchronized(this)
+ {
+ callback = _startCallback;
+ _startCallback = null;
+ }
+
+ if(callback != null)
+ {
+ if(ex == null)
+ {
+ callback.connectionStartCompleted(this);
+ }
+ else
+ {
+ callback.connectionStartFailed(this, ex);
}
}
}
@@ -2075,7 +2552,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
case IceInternal.Protocol.closeConnectionMsg:
{
- IceInternal.TraceUtil.traceHeader("received close connection", info.stream, _logger, _traceLevels);
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
if(_endpoint.datagram())
{
if(_warn)
@@ -2094,13 +2571,13 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
if(_state == StateClosing)
{
- IceInternal.TraceUtil.traceRequest("received request during closing\n" +
- "(ignored by server, client will retry)",
- info.stream, _logger, _traceLevels);
+ IceInternal.TraceUtil.trace("received request during closing\n" +
+ "(ignored by server, client will retry)",
+ info.stream, _logger, _traceLevels);
}
else
{
- IceInternal.TraceUtil.traceRequest("received request", info.stream, _logger, _traceLevels);
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.requestId = info.stream.readInt();
info.invokeNum = 1;
info.servantManager = _servantManager;
@@ -2114,14 +2591,13 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
if(_state == StateClosing)
{
- IceInternal.TraceUtil.traceBatchRequest("received batch request during closing\n" +
- "(ignored by server, client will retry)",
- info.stream, _logger, _traceLevels);
+ IceInternal.TraceUtil.trace("received batch request during closing\n" +
+ "(ignored by server, client will retry)",
+ info.stream, _logger, _traceLevels);
}
else
{
- IceInternal.TraceUtil.traceBatchRequest("received batch request", info.stream, _logger,
- _traceLevels);
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.invokeNum = info.stream.readInt();
if(info.invokeNum < 0)
{
@@ -2137,7 +2613,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
case IceInternal.Protocol.replyMsg:
{
- IceInternal.TraceUtil.traceReply("received reply", info.stream, _logger, _traceLevels);
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.requestId = info.stream.readInt();
IceInternal.Outgoing out = (IceInternal.Outgoing)_requests.remove(info.requestId);
if(out != null)
@@ -2157,8 +2633,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
case IceInternal.Protocol.validateConnectionMsg:
{
- IceInternal.TraceUtil.traceHeader("received validate connection", info.stream, _logger,
- _traceLevels);
+ IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
if(_warn)
{
_logger.warning("ignoring unexpected validate connection message:\n" + _desc);
@@ -2168,9 +2643,8 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
default:
{
- IceInternal.TraceUtil.traceHeader("received unknown message\n" +
- "(invalid, closing connection)", info.stream, _logger,
- _traceLevels);
+ IceInternal.TraceUtil.trace("received unknown message\n(invalid, closing connection)",
+ info.stream, _logger, _traceLevels);
throw new UnknownMessageException();
}
}
@@ -2274,63 +2748,58 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
private void
run()
{
- //
- // For non-datagram connections, the thread-per-connection
- // must validate and activate this connection, and not in the
- // connection factory. Please see the comments in the
- // connection factory for details.
- //
- if(!_endpoint.datagram())
+ try
{
- try
- {
- validate();
- }
- catch(LocalException ex)
+ //
+ // Initialize the connection transceiver and validate the connection using
+ // blocking operations.
+ //
+
+ IceInternal.SocketStatus status;
+
+ status = initialize();
+ assert(status == IceInternal.SocketStatus.Finished);
+
+ status = validate();
+ assert(status == IceInternal.SocketStatus.Finished);
+ }
+ catch(LocalException ex)
+ {
+ synchronized(this)
{
- synchronized(this)
+ setState(StateClosed, ex);
+
+ if(_transceiver != null)
{
- assert(_state == StateClosed);
-
- //
- // We must make sure that nobody is sending when
- // we close the transceiver.
- //
- synchronized(_sendMutex)
+ try
{
- if(_transceiver != null)
- {
- try
- {
- _transceiver.close();
- }
- catch(LocalException e)
- {
- // Here we ignore any exceptions in close().
- }
-
- _transceiver = null;
- }
- notifyAll();
+ _transceiver.close();
+ }
+ catch(LocalException e)
+ {
+ // Here we ignore any exceptions in close().
}
+
+ _transceiver = null;
}
- return;
+ notifyAll();
}
-
- activate();
+
+ finishStart(_exception);
+ return;
}
+ finishStart(null);
+
boolean warnUdp = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0;
boolean closed = false;
IceInternal.BasicStream stream = new IceInternal.BasicStream(_instance);
-
while(!closed)
{
//
- // We must accept new connections outside the thread
- // synchronization, because we use blocking accept.
+ // We must read new messages outside the thread synchronization because we use blocking reads.
//
try
@@ -2339,7 +2808,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
stream.resize(IceInternal.Protocol.headerSize, true);
stream.pos(0);
- _transceiver.read(stream, -1);
+ _transceiver.read(stream.getBuffer(), -1, _hasMoreData);
int pos = stream.pos();
if(pos < IceInternal.Protocol.headerSize)
@@ -2409,7 +2878,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
else
{
- _transceiver.read(stream, -1);
+ _transceiver.read(stream.getBuffer(), -1, _hasMoreData);
assert(stream.pos() == stream.size());
}
}
@@ -2442,9 +2911,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
LocalException localEx = null;
- IceInternal.IntMap requests = null;
- IceInternal.IntMap asyncRequests = null;
-
synchronized(this)
{
while(_state == StateHolding)
@@ -2469,25 +2935,38 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
if(_state == StateClosed)
{
+ if(_sendInProgress)
+ {
+ _selectorThread.unregister(_transceiver.fd());
+ }
+
//
- // We must make sure that nobody is sending when we close
- // the transceiver.
+ // Prevent further writes.
//
- synchronized(_sendMutex)
+ _transceiver.shutdownWrite();
+
+ while(_sendInProgress)
{
try
{
- _transceiver.close();
+ wait();
}
- catch(LocalException ex)
+ catch(java.lang.Exception ex)
{
- localEx = ex;
}
-
- _transceiver = null;
- notifyAll();
}
+ try
+ {
+ _transceiver.close();
+ }
+ catch(LocalException ex)
+ {
+ localEx = ex;
+ }
+ _transceiver = null;
+ notifyAll();
+
//
// We cannot simply return here. We have to make sure
// that all requests (regular and async) are notified
@@ -2495,15 +2974,6 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
//
closed = true;
}
-
- if(_state == StateClosed || _state == StateClosing)
- {
- requests = _requests;
- _requests = new IceInternal.IntMap();
-
- asyncRequests = _asyncRequests;
- _asyncRequests = new IceInternal.IntMap();
- }
}
//
@@ -2520,29 +2990,36 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
// must be done outside the thread synchronization, so that nested
// calls are possible.
//
- invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
+ invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
info.adapter);
- if(requests != null)
+ if(closed)
{
- java.util.Iterator i = requests.entryIterator();
+ java.util.Iterator i = _queuedStreams.iterator();
+ while(i.hasNext())
+ {
+ OutgoingMessage message = (OutgoingMessage)i.next();
+ message.finished(_exception);
+ }
+ _queuedStreams.clear();
+
+ i = _requests.entryIterator();
while(i.hasNext())
{
IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
IceInternal.Outgoing out = (IceInternal.Outgoing)e.getValue();
out.finished(_exception); // The exception is immutable at this point.
}
- }
+ _requests.clear();
- if(asyncRequests != null)
- {
- java.util.Iterator i = asyncRequests.entryIterator();
+ i = _asyncRequests.entryIterator();
while(i.hasNext())
{
IceInternal.IntMap.Entry e = (IceInternal.IntMap.Entry)i.next();
IceInternal.OutgoingAsync out = (IceInternal.OutgoingAsync)e.getValue();
out.__finished(_exception); // The exception is immutable at this point.
}
+ _asyncRequests.clear();
}
if(localEx != null)
@@ -2628,8 +3105,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
public IceInternal.Outgoing
- getOutgoing(IceInternal.Reference reference, String operation, OperationMode mode, java.util.Map context,
- boolean compress)
+ getOutgoing(IceInternal.RequestHandler handler, String operation, OperationMode mode, java.util.Map context)
throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing out = null;
@@ -2640,20 +3116,20 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
{
if(_outgoingCache == null)
{
- out = new IceInternal.Outgoing(this, reference, operation, mode, context, compress);
+ out = new IceInternal.Outgoing(handler, operation, mode, context);
}
else
{
out = _outgoingCache;
_outgoingCache = _outgoingCache.next;
- out.reset(reference, operation, mode, context, compress);
+ out.reset(handler, operation, mode, context);
out.next = null;
}
}
}
else
{
- out = new IceInternal.Outgoing(this, reference, operation, mode, context, compress);
+ out = new IceInternal.Outgoing(handler, operation, mode, context);
}
return out;
@@ -2704,11 +3180,96 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
}
}
+
+ private static class OutgoingMessage
+ {
+ OutgoingMessage(IceInternal.BasicStream stream, boolean compress, boolean adopt)
+ {
+ this.stream = stream;
+ this.compress = compress;
+ this.adopt = adopt;
+ }
+
+ OutgoingMessage(IceInternal.OutgoingMessageCallback out, IceInternal.BasicStream stream, boolean compress,
+ boolean resp)
+ {
+ this.stream = stream;
+ this.compress = compress;
+ this.out = out;
+ this.response = resp;
+ }
+
+ OutgoingMessage(IceInternal.OutgoingAsyncMessageCallback out, IceInternal.BasicStream stream, boolean compress,
+ boolean resp)
+ {
+ this.stream = stream;
+ this.compress = compress;
+ this.outAsync = out;
+ this.response = resp;
+ }
+
+ public void
+ adopt()
+ {
+ if(adopt)
+ {
+ IceInternal.BasicStream stream = new IceInternal.BasicStream(this.stream.instance());
+ stream.swap(this.stream);
+ this.stream = stream;
+ adopt = false;
+ }
+ }
+
+ public void
+ sent(ConnectionI connection, boolean notify)
+ {
+ if(out != null)
+ {
+ out.sent(notify); // true = notify the waiting thread that the request was sent.
+ }
+ else if(outAsync != null)
+ {
+ outAsync.__sent(connection);
+ }
+ }
+
+ public void
+ finished(Ice.LocalException ex)
+ {
+ //
+ // Only notify oneway requests. The connection keeps track of twoway
+ // requests in the _requests/_asyncRequests maps and will notify them
+ // of the connection exceptions.
+ //
+ if(!response)
+ {
+ if(out != null)
+ {
+ out.finished(ex);
+ }
+ else if(outAsync != null)
+ {
+ outAsync.__finished(ex);
+ }
+ }
+ }
+
+ public IceInternal.BasicStream stream;
+ public IceInternal.OutgoingMessageCallback out;
+ public IceInternal.OutgoingAsyncMessageCallback outAsync;
+ public boolean compress;
+ public boolean response;
+ boolean adopt;
+ boolean prepared;
+ }
+
private Thread _thread;
private final boolean _threadPerConnection;
private IceInternal.Transceiver _transceiver;
- private final String _desc;
+ private Ice.BooleanHolder _hasMoreData = new Ice.BooleanHolder(false);
+
+ private String _desc;
private final String _type;
private final IceInternal.EndpointI _endpoint;
@@ -2721,6 +3282,9 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
private boolean _registeredWithPool;
private int _finishedCount;
private final IceInternal.ThreadPool _threadPool;
+ private final IceInternal.SelectorThread _selectorThread;
+
+ private StartCallback _startCallback = null;
private final boolean _warn;
@@ -2743,17 +3307,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
private boolean _batchRequestCompress;
private int _batchMarker;
+ private java.util.LinkedList _queuedStreams = new java.util.LinkedList();
+ private java.util.LinkedList _sendStreams = new java.util.LinkedList();
+ private boolean _sendInProgress;
+ private int _waitingForSend;
+
private int _dispatchCount;
private int _state; // The current state.
private long _stateTime; // The last time when the state was changed.
- //
- // We have a separate mutex for sending, so that we don't block
- // the whole connection when we do a blocking send.
- //
- private java.lang.Object _sendMutex = new java.lang.Object();
-
private IceInternal.Incoming _incomingCache;
private java.lang.Object _incomingCacheMutex = new java.lang.Object();
diff --git a/java/src/Ice/InputStreamI.java b/java/src/Ice/InputStreamI.java
index 4cd30cbd4aa..eaa75550cf9 100644
--- a/java/src/Ice/InputStreamI.java
+++ b/java/src/Ice/InputStreamI.java
@@ -19,10 +19,10 @@ public class InputStreamI implements InputStream
_is = new IceInternal.BasicStream(Util.getInstance(communicator));
_is.closure(this);
_is.resize(data.length, true);
- java.nio.ByteBuffer buf = _is.prepareRead();
- buf.position(0);
- buf.put(data);
- buf.position(0);
+ IceInternal.Buffer buf = _is.getBuffer();
+ buf.b.position(0);
+ buf.b.put(data);
+ buf.b.position(0);
}
public Communicator
diff --git a/java/src/Ice/ObjectAdapterI.java b/java/src/Ice/ObjectAdapterI.java
index 8d3e8bf8779..adb890ae473 100644
--- a/java/src/Ice/ObjectAdapterI.java
+++ b/java/src/Ice/ObjectAdapterI.java
@@ -370,7 +370,6 @@ public final class ObjectAdapterI implements ObjectAdapter
_routerInfo = null;
_publishedEndpoints = null;
_locatorInfo = null;
- _connectors = null;
objectAdapterFactory = _objectAdapterFactory;
_objectAdapterFactory = null;
@@ -538,22 +537,17 @@ public final class ObjectAdapterI implements ObjectAdapter
{
IceInternal.IncomingConnectionFactory factory =
(IceInternal.IncomingConnectionFactory)_incomingConnectionFactories.get(i);
- ConnectionI[] conns = factory.connections();
- for(int j = 0; j < conns.length; ++j)
- {
- connections.add(conns[j]);
- }
+ connections.addAll(factory.connections());
}
//
// Create a reference and return a reverse proxy for this
// reference.
//
- IceInternal.EndpointI[] endpoints = new IceInternal.EndpointI[0];
ConnectionI[] arr = new ConnectionI[connections.size()];
connections.toArray(arr);
IceInternal.Reference ref =
- _instance.referenceFactory().create(ident, _instance.getDefaultContext(), "",
+ _instance.referenceFactory().create(ident, _instance.getDefaultContext(), "",
IceInternal.Reference.ModeTwoway, arr);
return _instance.proxyFactory().referenceToProxy(ref);
}
@@ -580,14 +574,6 @@ public final class ObjectAdapterI implements ObjectAdapter
oldPublishedEndpoints = _publishedEndpoints;
_publishedEndpoints = parsePublishedEndpoints();
- _connectors.clear();
- java.util.Iterator p = _incomingConnectionFactories.iterator();
- while(p.hasNext())
- {
- IceInternal.IncomingConnectionFactory factory = (IceInternal.IncomingConnectionFactory)p.next();
- _connectors.addAll(factory.endpoint().connectors());
- }
-
locatorInfo = _locatorInfo;
if(!_noConfig)
{
@@ -654,7 +640,6 @@ public final class ObjectAdapterI implements ObjectAdapter
endpoints = ref.getEndpoints();
}
-
synchronized(this)
{
checkForDeactivation();
@@ -666,15 +651,24 @@ public final class ObjectAdapterI implements ObjectAdapter
//
for(int i = 0; i < endpoints.length; ++i)
{
- final int sz = _connectors.size();
- for(int j = 0; j < sz; j++)
+ java.util.Iterator p;
+ p = _publishedEndpoints.iterator();
+ while(p.hasNext())
+ {
+ if(endpoints[i].equivalent((IceInternal.EndpointI)p.next()))
+ {
+ return true;
+ }
+ }
+ p = _incomingConnectionFactories.iterator();
+ while(p.hasNext())
{
- IceInternal.Connector connector = (IceInternal.Connector)_connectors.get(j);
- if(endpoints[i].equivalent(connector))
+ if(endpoints[i].equivalent(((IceInternal.IncomingConnectionFactory)p.next()).endpoint()))
{
return true;
}
}
+
}
//
@@ -842,7 +836,7 @@ public final class ObjectAdapterI implements ObjectAdapter
_id = properties.getProperty(_name + ".AdapterId");
_replicaGroupId = properties.getProperty(_name + ".ReplicaGroupId");
-
+
try
{
_threadPerConnection = properties.getPropertyAsInt(_name + ".ThreadPerConnection") > 0;
@@ -932,9 +926,8 @@ public final class ObjectAdapterI implements ObjectAdapter
else
{
//
- // Parse the endpoints, but don't store them in the adapter.
- // The connection factory might change it, for example, to
- // fill in the real port number.
+ // Parse the endpoints, but don't store them in the adapter. The connection
+ // factory might change it, for example, to fill in the real port number.
//
java.util.ArrayList endpoints;
if(endpointInfo.length() == 0)
@@ -957,11 +950,10 @@ public final class ObjectAdapterI implements ObjectAdapter
ex.unsupportedFeature = "endpoint requires thread-per-connection:\n" + endp.toString();
throw ex;
}
+
IceInternal.IncomingConnectionFactory factory =
new IceInternal.IncomingConnectionFactory(instance, endp, this, _name);
_incomingConnectionFactories.add(factory);
-
- _connectors.addAll(factory.endpoint().connectors());
}
if(endpoints.size() == 0)
{
@@ -1193,7 +1185,7 @@ public final class ObjectAdapterI implements ObjectAdapter
while(p.hasNext())
{
IceInternal.EndpointI endp = (IceInternal.EndpointI)p.next();
- java.util.ArrayList endps = endp.expand();
+ java.util.List endps = endp.expand();
expandedEndpoints.addAll(endps);
}
return expandedEndpoints;
@@ -1373,7 +1365,6 @@ public final class ObjectAdapterI implements ObjectAdapter
final private String _id;
final private String _replicaGroupId;
private java.util.ArrayList _incomingConnectionFactories = new java.util.ArrayList();
- private java.util.ArrayList _connectors = new java.util.ArrayList();
private java.util.ArrayList _routerEndpoints = new java.util.ArrayList();
private IceInternal.RouterInfo _routerInfo = null;
private java.util.ArrayList _publishedEndpoints = new java.util.ArrayList();
diff --git a/java/src/Ice/ObjectPrx.java b/java/src/Ice/ObjectPrx.java
index b0f187de430..a33669161df 100644
--- a/java/src/Ice/ObjectPrx.java
+++ b/java/src/Ice/ObjectPrx.java
@@ -138,5 +138,8 @@ public interface ObjectPrx
Connection ice_getConnection();
Connection ice_getCachedConnection();
+ void ice_flushBatchRequests();
+ void ice_flushBatchRequests_async(AMI_Object_ice_flushBatchRequests cb);
+
boolean equals(java.lang.Object r);
}
diff --git a/java/src/Ice/ObjectPrxHelperBase.java b/java/src/Ice/ObjectPrxHelperBase.java
index 72df0844773..87c3b86f3d2 100644
--- a/java/src/Ice/ObjectPrxHelperBase.java
+++ b/java/src/Ice/ObjectPrxHelperBase.java
@@ -82,7 +82,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
try
{
__checkTwowayOnly("ice_isA");
- __del = __getDelegate();
+ __del = __getDelegate(false);
return __del.ice_isA(__id, __context);
}
catch(IceInternal.LocalExceptionWrapper __ex)
@@ -122,7 +122,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = null;
try
{
- __del = __getDelegate();
+ __del = __getDelegate(false);
__del.ice_ping(__context);
return;
}
@@ -164,7 +164,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
try
{
__checkTwowayOnly("ice_ids");
- __del = __getDelegate();
+ __del = __getDelegate(false);
return __del.ice_ids(__context);
}
catch(IceInternal.LocalExceptionWrapper __ex)
@@ -205,7 +205,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
try
{
__checkTwowayOnly("ice_id");
- __del = __getDelegate();
+ __del = __getDelegate(false);
return __del.ice_id(__context);
}
catch(IceInternal.LocalExceptionWrapper __ex)
@@ -247,7 +247,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = null;
try
{
- __del = __getDelegate();
+ __del = __getDelegate(false);
return __del.ice_invoke(operation, mode, inParams, outParams, context);
}
catch(IceInternal.LocalExceptionWrapper __ex)
@@ -776,8 +776,8 @@ public class ObjectPrxHelperBase implements ObjectPrx
**/
public final Connection
ice_connection()
- {
- return ice_getConnection();
+ {
+ return ice_getConnection();
}
public final Connection
@@ -789,8 +789,9 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = null;
try
{
- __del = __getDelegate();
- return __del.__getConnection(new BooleanHolder());
+ __del = __getDelegate(false);
+ // Wait for the connection to be established.
+ return __del.__getRequestHandler().getConnection(true);
}
catch(LocalException __ex)
{
@@ -812,7 +813,8 @@ public class ObjectPrxHelperBase implements ObjectPrx
{
try
{
- return __del.__getConnection(new BooleanHolder());
+ // Don't wait for the connection to be established.
+ return __del.__getRequestHandler().getConnection(false);
}
catch(CollocationOptimizationException ex)
{
@@ -821,6 +823,36 @@ public class ObjectPrxHelperBase implements ObjectPrx
return null;
}
+ public void
+ ice_flushBatchRequests()
+ {
+ int __cnt = 0;
+ while(true)
+ {
+ _ObjectDel __del = null;
+ try
+ {
+ __del = __getDelegate(false);
+ __del.ice_flushBatchRequests();
+ return;
+ }
+ catch(IceInternal.LocalExceptionWrapper __ex)
+ {
+ __handleExceptionWrapper(__del, __ex);
+ }
+ catch(LocalException __ex)
+ {
+ __cnt = __handleException(__del, __ex, __cnt);
+ }
+ }
+ }
+
+ public void
+ ice_flushBatchRequests_async(AMI_Object_ice_flushBatchRequests cb)
+ {
+ cb.__invoke(this);
+ }
+
public final boolean
equals(java.lang.Object r)
{
@@ -988,7 +1020,7 @@ public class ObjectPrxHelperBase implements ObjectPrx
}
public final synchronized _ObjectDel
- __getDelegate()
+ __getDelegate(boolean async)
{
if(_delegate != null)
{
@@ -1010,19 +1042,8 @@ public class ObjectPrxHelperBase implements ObjectPrx
if(delegate == null)
{
_ObjectDelM d = __createDelegateM();
- d.setup(_reference);
+ d.setup(_reference, this, async);
delegate = d;
-
- //
- // If this proxy is for a non-local object, and we are
- // using a router, then add this proxy to the router info
- // object.
- //
- IceInternal.RouterInfo ri = _reference.getRouterInfo();
- if(ri != null)
- {
- ri.addProxy(this);
- }
}
if(_reference.getCacheConnection())
@@ -1038,6 +1059,24 @@ public class ObjectPrxHelperBase implements ObjectPrx
return delegate;
}
+ synchronized public void
+ __setRequestHandler(_ObjectDel delegate, IceInternal.RequestHandler handler)
+ {
+ if(delegate == _delegate)
+ {
+ if(_delegate instanceof _ObjectDelM)
+ {
+ _delegate = __createDelegateM();
+ _delegate.__setRequestHandler(handler);
+ }
+ else if(_delegate instanceof _ObjectDelD)
+ {
+ _delegate = __createDelegateD();
+ _delegate.__setRequestHandler(handler);
+ }
+ }
+ }
+
protected _ObjectDelM
__createDelegateM()
{
diff --git a/java/src/Ice/OutputStreamI.java b/java/src/Ice/OutputStreamI.java
index 2a0884014ef..0393caf4689 100644
--- a/java/src/Ice/OutputStreamI.java
+++ b/java/src/Ice/OutputStreamI.java
@@ -190,9 +190,9 @@ public class OutputStreamI implements OutputStream
public byte[]
finished()
{
- java.nio.ByteBuffer buf = _os.prepareWrite();
- byte[] result = new byte[buf.limit()];
- buf.get(result);
+ IceInternal.Buffer buf = _os.prepareWrite();
+ byte[] result = new byte[buf.b.limit()];
+ buf.b.get(result);
return result;
}
diff --git a/java/src/Ice/_ObjectDel.java b/java/src/Ice/_ObjectDel.java
index e17416dfe8a..8eefc506fca 100644
--- a/java/src/Ice/_ObjectDel.java
+++ b/java/src/Ice/_ObjectDel.java
@@ -27,5 +27,9 @@ public interface _ObjectDel
java.util.Map context)
throws IceInternal.LocalExceptionWrapper;
- ConnectionI __getConnection(BooleanHolder compress);
+ void ice_flushBatchRequests()
+ throws IceInternal.LocalExceptionWrapper;
+
+ IceInternal.RequestHandler __getRequestHandler();
+ void __setRequestHandler(IceInternal.RequestHandler handler);
}
diff --git a/java/src/Ice/_ObjectDelD.java b/java/src/Ice/_ObjectDelD.java
index 7caece078cd..0248419607d 100644
--- a/java/src/Ice/_ObjectDelD.java
+++ b/java/src/Ice/_ObjectDelD.java
@@ -215,8 +215,20 @@ public class _ObjectDelD implements _ObjectDel
throw new CollocationOptimizationException();
}
- public ConnectionI
- __getConnection(BooleanHolder compress)
+ public void
+ ice_flushBatchRequests()
+ {
+ throw new CollocationOptimizationException();
+ }
+
+ public IceInternal.RequestHandler
+ __getRequestHandler()
+ {
+ throw new CollocationOptimizationException();
+ }
+
+ public void
+ __setRequestHandler(IceInternal.RequestHandler handler)
{
throw new CollocationOptimizationException();
}
diff --git a/java/src/Ice/_ObjectDelM.java b/java/src/Ice/_ObjectDelM.java
index b37bd91733e..8bc56496b33 100644
--- a/java/src/Ice/_ObjectDelM.java
+++ b/java/src/Ice/_ObjectDelM.java
@@ -15,8 +15,7 @@ public class _ObjectDelM implements _ObjectDel
ice_isA(String __id, java.util.Map __context)
throws IceInternal.LocalExceptionWrapper
{
- IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_isA", OperationMode.Nonmutating,
- __context, __compress);
+ IceInternal.Outgoing __og = __handler.getOutgoing("ice_isA", OperationMode.Nonmutating, __context);
try
{
try
@@ -52,7 +51,7 @@ public class _ObjectDelM implements _ObjectDel
}
finally
{
- __connection.reclaimOutgoing(__og);
+ __handler.reclaimOutgoing(__og);
}
}
@@ -60,8 +59,7 @@ public class _ObjectDelM implements _ObjectDel
ice_ping(java.util.Map __context)
throws IceInternal.LocalExceptionWrapper
{
- IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_ping", OperationMode.Nonmutating,
- __context, __compress);
+ IceInternal.Outgoing __og = __handler.getOutgoing("ice_ping", OperationMode.Nonmutating, __context);
try
{
boolean __ok = __og.invoke();
@@ -87,7 +85,7 @@ public class _ObjectDelM implements _ObjectDel
}
finally
{
- __connection.reclaimOutgoing(__og);
+ __handler.reclaimOutgoing(__og);
}
}
@@ -95,8 +93,7 @@ public class _ObjectDelM implements _ObjectDel
ice_ids(java.util.Map __context)
throws IceInternal.LocalExceptionWrapper
{
- IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_ids", OperationMode.Nonmutating,
- __context, __compress);
+ IceInternal.Outgoing __og = __handler.getOutgoing("ice_ids", OperationMode.Nonmutating, __context);
try
{
boolean __ok = __og.invoke();
@@ -123,7 +120,7 @@ public class _ObjectDelM implements _ObjectDel
}
finally
{
- __connection.reclaimOutgoing(__og);
+ __handler.reclaimOutgoing(__og);
}
}
@@ -131,8 +128,7 @@ public class _ObjectDelM implements _ObjectDel
ice_id(java.util.Map __context)
throws IceInternal.LocalExceptionWrapper
{
- IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_id", OperationMode.Nonmutating,
- __context, __compress);
+ IceInternal.Outgoing __og = __handler.getOutgoing("ice_id", OperationMode.Nonmutating, __context);
try
{
boolean __ok = __og.invoke();
@@ -159,7 +155,7 @@ public class _ObjectDelM implements _ObjectDel
}
finally
{
- __connection.reclaimOutgoing(__og);
+ __handler.reclaimOutgoing(__og);
}
}
@@ -167,7 +163,7 @@ public class _ObjectDelM implements _ObjectDel
ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams, java.util.Map __context)
throws IceInternal.LocalExceptionWrapper
{
- IceInternal.Outgoing __og = __connection.getOutgoing(__reference, operation, mode, __context, __compress);
+ IceInternal.Outgoing __og = __handler.getOutgoing(operation, mode, __context);
try
{
if(inParams != null)
@@ -183,7 +179,7 @@ public class _ObjectDelM implements _ObjectDel
}
}
boolean ok = __og.invoke();
- if(__reference.getMode() == IceInternal.Reference.ModeTwoway)
+ if(__handler.getReference().getMode() == IceInternal.Reference.ModeTwoway)
{
try
{
@@ -203,15 +199,40 @@ public class _ObjectDelM implements _ObjectDel
}
finally
{
- __connection.reclaimOutgoing(__og);
+ __handler.reclaimOutgoing(__og);
}
}
- public ConnectionI
- __getConnection(BooleanHolder compress)
+ public void
+ ice_flushBatchRequests()
+ throws IceInternal.LocalExceptionWrapper
+ {
+ IceInternal.BatchOutgoing out = new IceInternal.BatchOutgoing(__handler);
+ try
+ {
+ out.invoke();
+ }
+ catch(Ice.LocalException ex)
+ {
+ //
+ // We never retry flusing the batch requests as the connection batched
+ // requests were discarded and the caller needs to be notified of the
+ // failure.
+ //
+ throw new IceInternal.LocalExceptionWrapper(ex, false);
+ }
+ }
+
+ public IceInternal.RequestHandler
+ __getRequestHandler()
{
- compress.value = __compress;
- return __connection;
+ return __handler;
+ }
+
+ public void
+ __setRequestHandler(IceInternal.RequestHandler handler)
+ {
+ __handler = handler;
}
//
@@ -230,32 +251,38 @@ public class _ObjectDelM implements _ObjectDel
// upon initialization.
//
- assert(__reference == null);
- assert(__connection == null);
+ assert(__handler == null);
- __reference = from.__reference;
- __connection = from.__connection;
- __compress = from.__compress;
+ __handler = from.__handler;
}
- protected IceInternal.Reference __reference;
- protected ConnectionI __connection;
- protected boolean __compress;
+ protected IceInternal.RequestHandler __handler;
public void
- setup(IceInternal.Reference ref)
+ setup(IceInternal.Reference ref, Ice.ObjectPrx proxy, boolean async)
{
//
// No need to synchronize, as this operation is only called
// upon initialization.
//
- assert(__reference == null);
- assert(__connection == null);
+ assert(__handler == null);
- __reference = ref;
- BooleanHolder compress = new BooleanHolder();
- __connection = __reference.getConnection(compress);
- __compress = compress.value;
+ //
+ // If the delegate is created as a result of an AMI call or if the proxy is
+ // a batch proxy we use the connect request handler to connect the in the
+ // background.
+ //
+ if(async ||
+ ref.getMode() == IceInternal.Reference.ModeBatchOneway ||
+ ref.getMode() == IceInternal.Reference.ModeBatchDatagram)
+ {
+ IceInternal.ConnectRequestHandler handler = new IceInternal.ConnectRequestHandler(ref, proxy, this);
+ __handler = handler.connect();
+ }
+ else
+ {
+ __handler = new IceInternal.ConnectionRequestHandler(ref, proxy);
+ }
}
}
diff --git a/java/src/IceInternal/BasicStream.java b/java/src/IceInternal/BasicStream.java
index d7a33113069..16409506b80 100644
--- a/java/src/IceInternal/BasicStream.java
+++ b/java/src/IceInternal/BasicStream.java
@@ -12,27 +12,24 @@ package IceInternal;
public class BasicStream
{
public
- BasicStream(IceInternal.Instance instance)
+ BasicStream(Instance instance)
{
initialize(instance, false);
}
public
- BasicStream(IceInternal.Instance instance, boolean unlimited)
+ BasicStream(Instance instance, boolean unlimited)
{
initialize(instance, unlimited);
}
private void
- initialize(IceInternal.Instance instance, boolean unlimited)
+ initialize(Instance instance, boolean unlimited)
{
_instance = instance;
+ _buf = new Buffer(_instance.messageSizeMax());
_closure = null;
_unlimited = unlimited;
- allocate(1500);
- _capacity = _buf.capacity();
- _limit = 0;
- assert(_buf.limit() == _capacity);
_readEncapsStack = null;
_writeEncapsStack = null;
@@ -56,9 +53,7 @@ public class BasicStream
public void
reset()
{
- _limit = 0;
- _buf.limit(_capacity);
- _buf.position(0);
+ _buf.reset();
if(_readEncapsStack != null)
{
@@ -75,7 +70,7 @@ public class BasicStream
}
}
- public IceInternal.Instance
+ public Instance
instance()
{
return _instance;
@@ -104,18 +99,10 @@ public class BasicStream
other._closure = _closure;
_closure = tmpClosure;
- java.nio.ByteBuffer tmpBuf = other._buf;
+ Buffer tmpBuf = other._buf;
other._buf = _buf;
_buf = tmpBuf;
- int tmpCapacity = other._capacity;
- other._capacity = _capacity;
- _capacity = tmpCapacity;
-
- int tmpLimit = other._limit;
- other._limit = _limit;
- _limit = tmpLimit;
-
ReadEncaps tmpRead = other._readEncapsStack;
other._readEncapsStack = _readEncapsStack;
_readEncapsStack = tmpRead;
@@ -154,49 +141,31 @@ public class BasicStream
}
public void
- resize(int total, boolean reading)
+ resize(int sz, boolean reading)
{
- if(!_unlimited && total > _messageSizeMax)
- {
- throw new Ice.MemoryLimitException();
- }
- if(total > _capacity)
- {
- final int cap2 = _capacity << 1;
- int newCapacity = cap2 > total ? cap2 : total;
- _buf.limit(_limit);
- reallocate(newCapacity);
- _capacity = _buf.capacity();
- }
//
- // If this stream is used for reading, then we want to set the
- // buffer's limit to the new total size. If this buffer is
- // used for writing, then we must set the buffer's limit to
- // the buffer's capacity.
+ // Check memory limit if stream is not unlimited.
//
- if(reading)
+ if(!_unlimited && sz > _messageSizeMax)
{
- _buf.limit(total);
- }
- else
- {
- _buf.limit(_capacity);
+ throw new Ice.MemoryLimitException();
}
- _buf.position(total);
- _limit = total;
+
+ _buf.resize(sz, reading);
+ _buf.b.position(sz);
}
- public java.nio.ByteBuffer
- prepareRead()
+ public Buffer
+ prepareWrite()
{
+ _buf.b.limit(_buf.size());
+ _buf.b.position(0);
return _buf;
}
- public java.nio.ByteBuffer
- prepareWrite()
+ public Buffer
+ getBuffer()
{
- _buf.limit(_limit);
- _buf.position(0);
return _buf;
}
@@ -261,7 +230,7 @@ public class BasicStream
sd.previous = _seqDataStack;
_seqDataStack = sd;
- int bytesLeft = _buf.remaining();
+ int bytesLeft = _buf.b.remaining();
if(_seqDataStack.previous == null) // Outermost sequence
{
//
@@ -287,7 +256,7 @@ public class BasicStream
public void
checkSeq()
{
- checkSeq(_buf.remaining());
+ checkSeq(_buf.b.remaining());
}
public void
@@ -311,7 +280,7 @@ public class BasicStream
public void
checkFixedSeq(int numElements, int elemSize)
{
- int bytesLeft = _buf.remaining();
+ int bytesLeft = _buf.b.remaining();
if(_seqDataStack == null) // Outermost sequence
{
//
@@ -376,7 +345,7 @@ public class BasicStream
_writeEncapsStack = curr;
}
- _writeEncapsStack.start = _buf.position();
+ _writeEncapsStack.start = _buf.size();
writeBlob(_encapsBlob);
}
@@ -385,8 +354,8 @@ public class BasicStream
{
assert(_writeEncapsStack != null);
int start = _writeEncapsStack.start;
- int sz = _buf.position() - start; // Size includes size and version.
- _buf.putInt(start, sz);
+ int sz = _buf.size() - start; // Size includes size and version.
+ _buf.b.putInt(start, sz);
WriteEncaps curr = _writeEncapsStack;
_writeEncapsStack = curr.next;
@@ -413,8 +382,8 @@ public class BasicStream
_readEncapsStack = curr;
}
- _readEncapsStack.start = _buf.position();
-
+ _readEncapsStack.start = _buf.b.position();
+
//
// I don't use readSize() and writeSize() for encapsulations,
// because when creating an encapsulation, I must know in
@@ -428,7 +397,7 @@ public class BasicStream
throw new Ice.NegativeSizeException();
}
- if(sz - 4 > _buf.limit())
+ if(sz - 4 > _buf.b.limit())
{
throw new Ice.UnmarshalOutOfBoundsException();
}
@@ -457,7 +426,7 @@ public class BasicStream
int sz = _readEncapsStack.sz;
try
{
- _buf.position(start + sz);
+ _buf.b.position(start + sz);
}
catch(IllegalArgumentException ex)
{
@@ -477,7 +446,7 @@ public class BasicStream
assert(_readEncapsStack != null);
int start = _readEncapsStack.start;
int sz = _readEncapsStack.sz;
- if(_buf.position() != start + sz)
+ if(_buf.b.position() != start + sz)
{
throw new Ice.EncapsulationException();
}
@@ -500,7 +469,7 @@ public class BasicStream
}
try
{
- _buf.position(_buf.position() + sz - 4);
+ _buf.b.position(_buf.b.position() + sz - 4);
}
catch(IllegalArgumentException ex)
{
@@ -512,13 +481,13 @@ public class BasicStream
startWriteSlice()
{
writeInt(0); // Placeholder for the slice length.
- _writeSlice = _buf.position();
+ _writeSlice = _buf.size();
}
public void endWriteSlice()
{
- final int sz = _buf.position() - _writeSlice + 4;
- _buf.putInt(_writeSlice - 4, sz);
+ final int sz = _buf.size() - _writeSlice + 4;
+ _buf.b.putInt(_writeSlice - 4, sz);
}
public void startReadSlice()
@@ -528,7 +497,7 @@ public class BasicStream
{
throw new Ice.NegativeSizeException();
}
- _readSlice = _buf.position();
+ _readSlice = _buf.b.position();
}
public void endReadSlice()
@@ -544,7 +513,7 @@ public class BasicStream
}
try
{
- _buf.position(_buf.position() + sz - 4);
+ _buf.b.position(_buf.b.position() + sz - 4);
}
catch(IllegalArgumentException ex)
{
@@ -558,13 +527,13 @@ public class BasicStream
if(v > 254)
{
expand(5);
- _buf.put((byte)-1);
- _buf.putInt(v);
+ _buf.b.put((byte)-1);
+ _buf.b.putInt(v);
}
else
{
expand(1);
- _buf.put((byte)v);
+ _buf.b.put((byte)v);
}
}
@@ -573,10 +542,10 @@ public class BasicStream
{
try
{
- byte b = _buf.get();
+ byte b = _buf.b.get();
if(b == -1)
{
- int v = _buf.getInt();
+ int v = _buf.b.getInt();
if(v < 0)
{
throw new Ice.NegativeSizeException();
@@ -640,14 +609,14 @@ public class BasicStream
writeBlob(byte[] v)
{
expand(v.length);
- _buf.put(v);
+ _buf.b.put(v);
}
public void
writeBlob(byte[] v, int off, int len)
{
expand(len);
- _buf.put(v, off, len);
+ _buf.b.put(v, off, len);
}
public byte[]
@@ -656,7 +625,7 @@ public class BasicStream
byte[] v = new byte[sz];
try
{
- _buf.get(v);
+ _buf.b.get(v);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -669,7 +638,7 @@ public class BasicStream
writeByte(byte v)
{
expand(1);
- _buf.put(v);
+ _buf.b.put(v);
}
public void
@@ -693,7 +662,7 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length);
- _buf.put(v);
+ _buf.b.put(v);
}
}
@@ -702,7 +671,7 @@ public class BasicStream
{
try
{
- return _buf.get();
+ return _buf.b.get();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -729,7 +698,7 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 1);
byte[] v = new byte[sz];
- _buf.get(v);
+ _buf.b.get(v);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -742,7 +711,7 @@ public class BasicStream
writeBool(boolean v)
{
expand(1);
- _buf.put(v ? (byte)1 : (byte)0);
+ _buf.b.put(v ? (byte)1 : (byte)0);
}
public void
@@ -758,7 +727,7 @@ public class BasicStream
expand(v.length);
for(int i = 0; i < v.length; i++)
{
- _buf.put(v[i] ? (byte)1 : (byte)0);
+ _buf.b.put(v[i] ? (byte)1 : (byte)0);
}
}
}
@@ -768,7 +737,7 @@ public class BasicStream
{
try
{
- return _buf.get() == 1;
+ return _buf.b.get() == 1;
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -786,7 +755,7 @@ public class BasicStream
boolean[] v = new boolean[sz];
for(int i = 0; i < sz; i++)
{
- v[i] = _buf.get() == 1;
+ v[i] = _buf.b.get() == 1;
}
return v;
}
@@ -800,7 +769,7 @@ public class BasicStream
writeShort(short v)
{
expand(2);
- _buf.putShort(v);
+ _buf.b.putShort(v);
}
public void
@@ -824,9 +793,9 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length * 2);
- java.nio.ShortBuffer shortBuf = _buf.asShortBuffer();
+ java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer();
shortBuf.put(v);
- _buf.position(_buf.position() + v.length * 2);
+ _buf.b.position(_buf.b.position() + v.length * 2);
}
}
@@ -835,7 +804,7 @@ public class BasicStream
{
try
{
- return _buf.getShort();
+ return _buf.b.getShort();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -862,9 +831,9 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 2);
short[] v = new short[sz];
- java.nio.ShortBuffer shortBuf = _buf.asShortBuffer();
+ java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer();
shortBuf.get(v);
- _buf.position(_buf.position() + sz * 2);
+ _buf.b.position(_buf.b.position() + sz * 2);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -877,7 +846,7 @@ public class BasicStream
writeInt(int v)
{
expand(4);
- _buf.putInt(v);
+ _buf.b.putInt(v);
}
public void
@@ -901,9 +870,9 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length * 4);
- java.nio.IntBuffer intBuf = _buf.asIntBuffer();
+ java.nio.IntBuffer intBuf = _buf.b.asIntBuffer();
intBuf.put(v);
- _buf.position(_buf.position() + v.length * 4);
+ _buf.b.position(_buf.b.position() + v.length * 4);
}
}
@@ -912,7 +881,7 @@ public class BasicStream
{
try
{
- return _buf.getInt();
+ return _buf.b.getInt();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -939,9 +908,9 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 4);
int[] v = new int[sz];
- java.nio.IntBuffer intBuf = _buf.asIntBuffer();
+ java.nio.IntBuffer intBuf = _buf.b.asIntBuffer();
intBuf.get(v);
- _buf.position(_buf.position() + sz * 4);
+ _buf.b.position(_buf.b.position() + sz * 4);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -954,7 +923,7 @@ public class BasicStream
writeLong(long v)
{
expand(8);
- _buf.putLong(v);
+ _buf.b.putLong(v);
}
public void
@@ -968,9 +937,9 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length * 8);
- java.nio.LongBuffer longBuf = _buf.asLongBuffer();
+ java.nio.LongBuffer longBuf = _buf.b.asLongBuffer();
longBuf.put(v);
- _buf.position(_buf.position() + v.length * 8);
+ _buf.b.position(_buf.b.position() + v.length * 8);
}
}
@@ -979,7 +948,7 @@ public class BasicStream
{
try
{
- return _buf.getLong();
+ return _buf.b.getLong();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -995,9 +964,9 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 8);
long[] v = new long[sz];
- java.nio.LongBuffer longBuf = _buf.asLongBuffer();
+ java.nio.LongBuffer longBuf = _buf.b.asLongBuffer();
longBuf.get(v);
- _buf.position(_buf.position() + sz * 8);
+ _buf.b.position(_buf.b.position() + sz * 8);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -1010,7 +979,7 @@ public class BasicStream
writeFloat(float v)
{
expand(4);
- _buf.putFloat(v);
+ _buf.b.putFloat(v);
}
public void
@@ -1024,9 +993,9 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length * 4);
- java.nio.FloatBuffer floatBuf = _buf.asFloatBuffer();
+ java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer();
floatBuf.put(v);
- _buf.position(_buf.position() + v.length * 4);
+ _buf.b.position(_buf.b.position() + v.length * 4);
}
}
@@ -1035,7 +1004,7 @@ public class BasicStream
{
try
{
- return _buf.getFloat();
+ return _buf.b.getFloat();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -1051,9 +1020,9 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 4);
float[] v = new float[sz];
- java.nio.FloatBuffer floatBuf = _buf.asFloatBuffer();
+ java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer();
floatBuf.get(v);
- _buf.position(_buf.position() + sz * 4);
+ _buf.b.position(_buf.b.position() + sz * 4);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -1066,7 +1035,7 @@ public class BasicStream
writeDouble(double v)
{
expand(8);
- _buf.putDouble(v);
+ _buf.b.putDouble(v);
}
public void
@@ -1080,9 +1049,9 @@ public class BasicStream
{
writeSize(v.length);
expand(v.length * 8);
- java.nio.DoubleBuffer doubleBuf = _buf.asDoubleBuffer();
+ java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer();
doubleBuf.put(v);
- _buf.position(_buf.position() + v.length * 8);
+ _buf.b.position(_buf.b.position() + v.length * 8);
}
}
@@ -1091,7 +1060,7 @@ public class BasicStream
{
try
{
- return _buf.getDouble();
+ return _buf.b.getDouble();
}
catch(java.nio.BufferUnderflowException ex)
{
@@ -1107,9 +1076,9 @@ public class BasicStream
final int sz = readSize();
checkFixedSeq(sz, 8);
double[] v = new double[sz];
- java.nio.DoubleBuffer doubleBuf = _buf.asDoubleBuffer();
+ java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer();
doubleBuf.get(v);
- _buf.position(_buf.position() + sz * 8);
+ _buf.b.position(_buf.b.position() + sz * 8);
return v;
}
catch(java.nio.BufferUnderflowException ex)
@@ -1170,14 +1139,14 @@ public class BasicStream
}
writeSize(b.limit());
expand(b.limit());
- _buf.put(b);
+ _buf.b.put(b);
return;
}
_stringBytes[i] = (byte)_stringChars[i];
}
writeSize(len);
expand(len);
- _buf.put(_stringBytes, 0, len);
+ _buf.b.put(_stringBytes, 0, len);
}
else
{
@@ -1228,7 +1197,7 @@ public class BasicStream
{
_stringChars = new char[len];
}
- _buf.get(_stringBytes, 0, len);
+ _buf.b.get(_stringBytes, 0, len);
//
// It's more efficient to construct a string using a
@@ -1356,7 +1325,7 @@ public class BasicStream
}
public void
- readObject(IceInternal.Patcher patcher)
+ readObject(Patcher patcher)
{
Ice.Object v = null;
@@ -1747,7 +1716,7 @@ public class BasicStream
//
for(java.util.Iterator i = patchlist.iterator(); i.hasNext(); )
{
- IceInternal.Patcher p = (IceInternal.Patcher)i.next();
+ Patcher p = (Patcher)i.next();
try
{
p.patch(v);
@@ -1771,25 +1740,25 @@ public class BasicStream
public int
pos()
{
- return _buf.position();
+ return _buf.b.position();
}
public void
pos(int n)
{
- _buf.position(n);
+ _buf.b.position(n);
}
public int
size()
{
- return _limit;
+ return _buf.size();
}
public boolean
isEmpty()
{
- return _limit == 0;
+ return _buf.empty();
}
private static class BufferedOutputStream extends java.io.OutputStream
@@ -1865,8 +1834,8 @@ public class BasicStream
// If the ByteBuffer is backed by an array then we can avoid
// an extra copy by using the array directly.
//
- data = _buf.array();
- offset = _buf.arrayOffset();
+ data = _buf.b.array();
+ offset = _buf.b.arrayOffset();
}
catch(Exception ex)
{
@@ -1874,7 +1843,7 @@ public class BasicStream
// Otherwise, allocate an array to hold a copy of the uncompressed data.
//
data = new byte[size()];
- _buf.get(data);
+ _buf.b.get(data);
}
try
@@ -1922,7 +1891,7 @@ public class BasicStream
// Copy the header from the uncompressed stream to the
// compressed one.
//
- cstream._buf.put(data, offset, headerSize);
+ cstream._buf.b.put(data, offset, headerSize);
//
// Add the size of the uncompressed stream before the
@@ -1933,7 +1902,7 @@ public class BasicStream
//
// Add the compressed message body.
//
- cstream._buf.put(compressed, 0, compressedLen);
+ cstream._buf.b.put(compressed, 0, compressedLen);
return cstream;
}
@@ -1960,8 +1929,8 @@ public class BasicStream
// If the ByteBuffer is backed by an array then we can avoid
// an extra copy by using the array directly.
//
- compressed = _buf.array();
- offset = _buf.arrayOffset();
+ compressed = _buf.b.array();
+ offset = _buf.b.arrayOffset();
}
catch(Exception ex)
{
@@ -1969,7 +1938,7 @@ public class BasicStream
// Otherwise, allocate an array to hold a copy of the compressed data.
//
compressed = new byte[size()];
- _buf.get(compressed);
+ _buf.b.get(compressed);
}
BasicStream ucStream = new BasicStream(_instance);
@@ -2020,34 +1989,19 @@ public class BasicStream
// Copy the header from the compressed stream to the uncompressed one.
//
ucStream.pos(0);
- ucStream._buf.put(compressed, offset, headerSize);
+ ucStream._buf.b.put(compressed, offset, headerSize);
return ucStream;
}
private void
- expand(int size)
+ expand(int n)
{
- if(_buf.position() == _limit)
+ if(!_unlimited && _buf.b != null && _buf.b.position() + n > _messageSizeMax)
{
- int oldLimit = _limit;
- _limit += size;
- if(!_unlimited && _limit > _messageSizeMax)
- {
- throw new Ice.MemoryLimitException();
- }
- if(_limit > _capacity)
- {
- final int cap2 = _capacity << 1;
- int newCapacity = cap2 > _limit ? cap2 : _limit;
- _buf.limit(oldLimit);
- int pos = _buf.position();
- reallocate(newCapacity);
- _capacity = _buf.capacity();
- _buf.limit(_capacity);
- _buf.position(pos);
- }
+ throw new Ice.MemoryLimitException();
}
+ _buf.expand(n);
}
private static final class DynamicObjectFactory implements Ice.ObjectFactory
@@ -2334,52 +2288,9 @@ public class BasicStream
return buf.toString();
}
- private void
- allocate(int size)
- {
- java.nio.ByteBuffer buf = null;
- try
- {
- //buf = java.nio.ByteBuffer.allocateDirect(size);
- buf = java.nio.ByteBuffer.allocate(size);
- }
- catch(OutOfMemoryError ex)
- {
- Ice.MarshalException e = new Ice.MarshalException();
- e.reason = "OutOfMemoryError occurred while allocating a ByteBuffer";
- e.initCause(ex);
- throw e;
- }
- buf.order(java.nio.ByteOrder.LITTLE_ENDIAN);
- _buf = buf;
- }
-
- private void
- reallocate(int size)
- {
- //
- // Limit the buffer size to MessageSizeMax
- //
- if(!_unlimited)
- {
- size = size > _messageSizeMax ? _messageSizeMax : size;
- }
-
- java.nio.ByteBuffer old = _buf;
- assert(old != null);
-
- allocate(size);
- assert(_buf != null);
-
- old.position(0);
- _buf.put(old);
- }
-
- private IceInternal.Instance _instance;
+ private Instance _instance;
+ private Buffer _buf;
private Object _closure;
- private java.nio.ByteBuffer _buf;
- private int _capacity; // Cache capacity to avoid excessive method calls.
- private int _limit; // Cache limit to avoid excessive method calls.
private byte[] _stringBytes; // Reusable array for reading strings.
private char[] _stringChars; // Reusable array for reading strings.
diff --git a/java/src/IceInternal/BatchOutgoing.java b/java/src/IceInternal/BatchOutgoing.java
new file mode 100644
index 00000000000..1e0071f047a
--- /dev/null
+++ b/java/src/IceInternal/BatchOutgoing.java
@@ -0,0 +1,92 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public final class BatchOutgoing implements OutgoingMessageCallback
+{
+ public
+ BatchOutgoing(Ice.ConnectionI connection, Instance instance)
+ {
+ _connection = connection;
+ _sent = false;
+ _os = new BasicStream(instance);
+ }
+
+ public
+ BatchOutgoing(RequestHandler handler)
+ {
+ _handler = handler;
+ _sent = false;
+ _os = new BasicStream(handler.getReference().getInstance());
+ }
+
+ public void
+ invoke()
+ {
+ assert(_handler != null || _connection != null);
+
+ if(_handler != null && !_handler.flushBatchRequests(this) ||
+ _connection != null && !_connection.flushBatchRequests(this))
+ synchronized(this)
+ {
+ while(_exception == null && !_sent)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ }
+ }
+
+ public void
+ sent(boolean notify)
+ {
+ if(notify)
+ {
+ synchronized(this)
+ {
+ _sent = true;
+ notify();
+ }
+ }
+ else
+ {
+ _sent = true;
+ }
+ }
+
+ public synchronized void
+ finished(Ice.LocalException ex)
+ {
+ _exception = ex;
+ notify();
+ }
+
+ public BasicStream
+ os()
+ {
+ return _os;
+ }
+
+ private RequestHandler _handler;
+ private Ice.ConnectionI _connection;
+ private BasicStream _os;
+ private boolean _sent;
+ private Ice.LocalException _exception;
+}
diff --git a/java/src/IceInternal/BatchOutgoingAsync.java b/java/src/IceInternal/BatchOutgoingAsync.java
new file mode 100644
index 00000000000..94e15c2dca3
--- /dev/null
+++ b/java/src/IceInternal/BatchOutgoingAsync.java
@@ -0,0 +1,106 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public abstract class BatchOutgoingAsync implements OutgoingAsyncMessageCallback
+{
+ public
+ BatchOutgoingAsync()
+ {
+ }
+
+ public abstract void ice_exception(Ice.LocalException ex);
+
+ public final BasicStream
+ __os()
+ {
+ return __os;
+ }
+
+ public final void
+ __sent(final Ice.ConnectionI connection)
+ {
+ synchronized(_monitor)
+ {
+ cleanup();
+ }
+ }
+
+ public final void
+ __finished(Ice.LocalException exc)
+ {
+ try
+ {
+ ice_exception(exc);
+ }
+ catch(java.lang.Exception ex)
+ {
+ warning(ex);
+ }
+ finally
+ {
+ synchronized(_monitor)
+ {
+ cleanup();
+ }
+ }
+ }
+
+ protected final void
+ __prepare(Instance instance)
+ {
+ synchronized(_monitor)
+ {
+ while(__os != null)
+ {
+ try
+ {
+ _monitor.wait();
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+
+ assert(__os == null);
+ __os = new BasicStream(instance);
+ }
+ }
+
+ private final void
+ warning(java.lang.Exception ex)
+ {
+ if(__os != null) // Don't print anything if cleanup() was already called.
+ {
+ if(__os.instance().initializationData().properties.getPropertyAsIntWithDefault(
+ "Ice.Warn.AMICallback", 1) > 0)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ IceUtil.OutputBase out = new IceUtil.OutputBase(pw);
+ out.setUseTab(false);
+ out.print("exception raised by AMI callback:\n");
+ ex.printStackTrace(pw);
+ pw.flush();
+ __os.instance().initializationData().logger.warning(sw.toString());
+ }
+ }
+ }
+
+ private final void
+ cleanup()
+ {
+ __os = null;
+ _monitor.notify();
+ }
+
+ protected BasicStream __os;
+ private final java.lang.Object _monitor = new java.lang.Object();
+}
diff --git a/java/src/IceInternal/Buffer.java b/java/src/IceInternal/Buffer.java
new file mode 100644
index 00000000000..8795f5fccde
--- /dev/null
+++ b/java/src/IceInternal/Buffer.java
@@ -0,0 +1,183 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+//
+// An instance of java.nio.ByteBuffer cannot grow beyond its initial capacity.
+// This class wraps a ByteBuffer and supports reallocation.
+//
+public class Buffer
+{
+ public
+ Buffer(int maxCapacity)
+ {
+ b = null;
+ _size = 0;
+ _capacity = 0;
+ _maxCapacity = maxCapacity;
+ }
+
+ public int
+ size()
+ {
+ return _size;
+ }
+
+ public boolean
+ empty()
+ {
+ return _size == 0;
+ }
+
+ public void
+ clear()
+ {
+ b = null;
+ _size = 0;
+ _capacity = 0;
+ }
+
+ //
+ // Call expand(n) to add room for n additional bytes. Note that expand()
+ // examines the current position of the buffer first; we don't want to
+ // expand the buffer if the caller is writing to a location that is
+ // already in the buffer.
+ //
+ public void
+ expand(int n)
+ {
+ final int sz = b == null ? n : b.position() + n;
+ if(sz > _size)
+ {
+ resize(sz, false);
+ }
+ }
+
+ public void
+ resize(int n, boolean reading)
+ {
+ if(n == 0)
+ {
+ clear();
+ }
+ else if(n > _capacity)
+ {
+ reserve(n);
+ }
+ _size = n;
+
+ //
+ // When used for reading, we want to set the buffer's limit to the new size.
+ //
+ if(reading)
+ {
+ b.limit(_size);
+ }
+ }
+
+ public void
+ reset()
+ {
+ if(_size > 0 && _size * 2 < _capacity)
+ {
+ //
+ // If the current buffer size is smaller than the
+ // buffer capacity, we shrink the buffer memory to the
+ // current size. This is to avoid holding on to too much
+ // memory if it's not needed anymore.
+ //
+ if(++_shrinkCounter > 2)
+ {
+ reserve(_size);
+ _shrinkCounter = 0;
+ }
+ }
+ else
+ {
+ _shrinkCounter = 0;
+ }
+ _size = 0;
+ if(b != null)
+ {
+ b.limit(b.capacity());
+ b.position(0);
+ }
+ }
+
+ private void
+ reserve(int n)
+ {
+ if(n > _capacity)
+ {
+ _capacity = java.lang.Math.max(n, java.lang.Math.min(2 * _capacity, _maxCapacity));
+ _capacity = java.lang.Math.max(240, _capacity);
+ }
+ else if(n < _capacity)
+ {
+ _capacity = n;
+ }
+ else
+ {
+ return;
+ }
+
+ try
+ {
+ java.nio.ByteBuffer buf;
+
+ if(DIRECT)
+ {
+ buf = java.nio.ByteBuffer.allocateDirect(_capacity);
+ }
+ else
+ {
+ buf = java.nio.ByteBuffer.allocate(_capacity);
+ }
+
+ if(b == null)
+ {
+ b = buf;
+ }
+ else
+ {
+ final int pos = b.position();
+ b.position(0);
+ b.limit(java.lang.Math.min(_capacity, b.capacity()));
+ buf.put(b);
+ b = buf;
+ b.limit(b.capacity());
+ b.position(pos);
+ }
+
+ b.order(java.nio.ByteOrder.LITTLE_ENDIAN);
+ }
+ catch(OutOfMemoryError ex)
+ {
+ Ice.MarshalException e = new Ice.MarshalException();
+ e.reason = "OutOfMemoryError occurred while allocating a ByteBuffer";
+ e.initCause(ex);
+ throw e;
+ }
+ }
+
+ public java.nio.ByteBuffer b;
+
+ private int _size;
+ private int _capacity; // Cache capacity to avoid excessive method calls.
+ private int _maxCapacity;
+ private int _shrinkCounter;
+
+ //
+ // This flag indicates whether we should use direct byte buffers. It is set to false
+ // because direct byte buffers have been known to cause problems in the past (for
+ // example, see bug 1582).
+ //
+ private static final boolean DIRECT = false;
+}
diff --git a/java/src/IceInternal/ConnectRequestHandler.java b/java/src/IceInternal/ConnectRequestHandler.java
new file mode 100644
index 00000000000..45aa6c959b9
--- /dev/null
+++ b/java/src/IceInternal/ConnectRequestHandler.java
@@ -0,0 +1,480 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class ConnectRequestHandler
+ implements RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback
+{
+ static class Request
+ {
+ Request(BasicStream os)
+ {
+ this.os = new BasicStream(os.instance());
+ this.os.swap(os);
+ }
+
+ Request(OutgoingAsync out)
+ {
+ this.out = out;
+ }
+
+ Request(BatchOutgoingAsync out)
+ {
+ this.batchOut = out;
+ }
+
+ OutgoingAsync out = null;
+ BatchOutgoingAsync batchOut = null;
+ BasicStream os = null;
+ }
+
+ public void
+ prepareBatchRequest(BasicStream os)
+ {
+ synchronized(this)
+ {
+ while(_batchRequestInProgress)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(!initialized())
+ {
+ _batchStream.swap(os);
+ _batchRequestInProgress = true;
+ return;
+ }
+ }
+
+ _connection.prepareBatchRequest(os);
+ }
+
+ public void
+ finishBatchRequest(BasicStream os)
+ {
+ synchronized(this)
+ {
+ if(!initialized())
+ {
+ assert(_batchRequestInProgress);
+ _batchRequestInProgress = false;
+ notifyAll();
+
+ _batchStream.swap(os);
+
+ if(!_batchAutoFlush &&
+ _batchStream.size() + _batchRequestsSize > _reference.getInstance().messageSizeMax())
+ {
+ throw new Ice.MemoryLimitException();
+ }
+
+ _requests.add(new Request(_batchStream));
+ return;
+ }
+ }
+
+ _connection.finishBatchRequest(os, _compress);
+ }
+
+ public void
+ abortBatchRequest()
+ {
+ synchronized(this)
+ {
+ if(!initialized())
+ {
+ assert(_batchRequestInProgress);
+ _batchRequestInProgress = false;
+ notifyAll();
+
+ BasicStream dummy = new BasicStream(_reference.getInstance(), _batchAutoFlush);
+ _batchStream.swap(dummy);
+ _batchRequestsSize = Protocol.requestBatchHdr.length;
+ return;
+ }
+ }
+
+ _connection.abortBatchRequest();
+ }
+
+ public Ice.ConnectionI
+ sendRequest(Outgoing out)
+ throws LocalExceptionWrapper
+ {
+ return (!getConnection(true).sendRequest(out, _compress, _response) || _response) ? _connection : null;
+ }
+
+ public void
+ sendAsyncRequest(OutgoingAsync out)
+ {
+ try
+ {
+ synchronized(this)
+ {
+ if(!initialized())
+ {
+ _requests.add(new Request(out));
+ return;
+ }
+ }
+
+ _connection.sendAsyncRequest(out, _compress, _response);
+ }
+ catch(LocalExceptionWrapper ex)
+ {
+ out.__finished(ex);
+ }
+ catch(Ice.LocalException ex)
+ {
+ out.__finished(ex);
+ }
+ }
+
+ public boolean
+ flushBatchRequests(BatchOutgoing out)
+ {
+ return getConnection(true).flushBatchRequests(out);
+ }
+
+ public void
+ flushAsyncBatchRequests(BatchOutgoingAsync out)
+ {
+ try
+ {
+ synchronized(this)
+ {
+ if(!initialized())
+ {
+ _requests.add(new Request(out));
+ return;
+ }
+ }
+
+ _connection.flushAsyncBatchRequests(out);
+ }
+ catch(Ice.LocalException ex)
+ {
+ out.__finished(ex);
+ }
+ }
+
+ public Outgoing
+ getOutgoing(String operation, Ice.OperationMode mode, java.util.Map context)
+ throws LocalExceptionWrapper
+ {
+ synchronized(this)
+ {
+ if(!initialized())
+ {
+ return new IceInternal.Outgoing(this, operation, mode, context);
+ }
+ }
+
+ return _connection.getOutgoing(this, operation, mode, context);
+ }
+
+ public void
+ reclaimOutgoing(Outgoing out)
+ {
+ synchronized(this)
+ {
+ if(_connection == null)
+ {
+ return;
+ }
+ }
+
+ _connection.reclaimOutgoing(out);
+ }
+
+ public Reference
+ getReference()
+ {
+ return _reference;
+ }
+
+ synchronized public Ice.ConnectionI
+ getConnection(boolean wait)
+ {
+ if(wait)
+ {
+ //
+ // Wait for the connection establishment to complete or fail.
+ //
+ while(!_initialized && _exception == null)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+ }
+
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ else
+ {
+ assert(!wait || _initialized);
+ return _connection;
+ }
+ }
+
+ //
+ // Implementation of Reference.GetConnectionCallback
+ //
+
+ public void
+ setConnection(Ice.ConnectionI connection, boolean compress)
+ {
+ synchronized(this)
+ {
+ _connection = connection;
+ _compress = compress;
+ }
+
+ //
+ // If this proxy is for a non-local object, and we are using a router, then
+ // add this proxy to the router info object.
+ //
+ RouterInfo ri = _reference.getRouterInfo();
+ if(ri != null)
+ {
+ if(!ri.addProxy(_proxy, this))
+ {
+ return; // The request handler will be initialized once addProxy returns.
+ }
+ }
+
+ flushRequests();
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ synchronized(this)
+ {
+ _exception = ex;
+ _proxy = null; // Break cyclic reference count.
+ _delegate = null; // Break cyclic reference count.
+ notifyAll();
+ }
+
+ java.util.Iterator p = _requests.iterator();
+ while(p.hasNext())
+ {
+ Request request = (Request)p.next();
+ if(request.out != null)
+ {
+ request.out.__finished(ex);
+ }
+ else if(request.batchOut != null)
+ {
+ request.batchOut.__finished(ex);
+ }
+ }
+ _requests.clear();
+ }
+
+ //
+ // Implementation of RouterInfo.AddProxyCallback
+ //
+ public void
+ addedProxy()
+ {
+ flushRequests();
+ }
+
+ public
+ ConnectRequestHandler(Reference ref, Ice.ObjectPrx proxy, Ice._ObjectDelM delegate)
+ {
+ _reference = ref;
+ _response = _reference.getMode() == Reference.ModeTwoway;
+ _proxy = (Ice.ObjectPrxHelperBase)proxy;
+ _delegate = delegate;
+ _batchAutoFlush = ref.getInstance().initializationData().properties.getPropertyAsIntWithDefault(
+ "Ice.BatchAutoFlush", 1) > 0 ? true : false;
+ _batchStream = new BasicStream(ref.getInstance(), _batchAutoFlush);
+ _batchRequestInProgress = false;
+ _batchRequestsSize = Protocol.requestBatchHdr.length;
+ _updateRequestHandler = false;
+ }
+
+ public RequestHandler
+ connect()
+ {
+ _reference.getConnection(this);
+
+ synchronized(this)
+ {
+ if(_connection != null)
+ {
+ return new ConnectionRequestHandler(_reference, _connection, _compress);
+ }
+ else
+ {
+ _updateRequestHandler = true;
+ return this;
+ }
+ }
+ }
+
+ private boolean
+ initialized()
+ {
+ if(_initialized)
+ {
+ assert(_connection != null);
+ return true;
+ }
+ else
+ {
+ while(_flushing)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(_exception != null)
+ {
+ throw _exception;
+ }
+ else
+ {
+ return _initialized;
+ }
+ }
+ }
+
+ private void
+ flushRequests()
+ {
+ synchronized(this)
+ {
+ assert(_connection != null);
+
+ if(_batchRequestInProgress)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ //
+ // We set the _flushing flag to true to prevent any additional queuing. Callers
+ // might block for a little while as the queued requests are being sent but this
+ // shouldn't be an issue as the request sends are non-blocking.
+ //
+ _flushing = true;
+ }
+
+ java.util.Iterator p = _requests.iterator(); // _requests is immutable when _flushing = true
+ while(p.hasNext())
+ {
+ Request request = (Request)p.next();
+ if(request.out != null)
+ {
+ try
+ {
+ _connection.sendAsyncRequest(request.out, _compress, _response);
+ }
+ catch(LocalExceptionWrapper ex)
+ {
+ request.out.__finished(ex);
+ }
+ catch(Ice.LocalException ex)
+ {
+ request.out.__finished(ex);
+ }
+ }
+ else if(request.batchOut != null)
+ {
+ try
+ {
+ _connection.flushAsyncBatchRequests(request.batchOut);
+ }
+ catch(Ice.LocalException ex)
+ {
+ request.batchOut.__finished(ex);
+ }
+ }
+ else
+ {
+ //
+ // TODO: Add sendBatchRequest() method to ConnectionI?
+ //
+ try
+ {
+ BasicStream os = new BasicStream(request.os.instance());
+ _connection.prepareBatchRequest(os);
+ request.os.pos(0);
+ os.writeBlob(request.os.readBlob(request.os.size()));
+ _connection.finishBatchRequest(os, _compress);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _connection.abortBatchRequest();
+ _exception = ex;
+ }
+ }
+ }
+ _requests.clear();
+
+ synchronized(this)
+ {
+ _initialized = true;
+ _flushing = false;
+ notifyAll();
+ }
+
+ if(_updateRequestHandler && _exception == null)
+ {
+ _proxy.__setRequestHandler(_delegate, new ConnectionRequestHandler(_reference, _connection, _compress));
+ }
+ _proxy = null; // Break cyclic reference count.
+ _delegate = null; // Break cyclic reference count.
+ }
+
+ private final Reference _reference;
+ private final boolean _batchAutoFlush;
+ private Ice.ObjectPrxHelperBase _proxy;
+ private Ice._ObjectDelM _delegate;
+ private boolean _initialized = false;
+ private boolean _flushing = false;
+ private Ice.ConnectionI _connection = null;
+ private boolean _compress = false;
+ private boolean _response;
+ private Ice.LocalException _exception = null;
+
+ private java.util.ArrayList _requests = new java.util.ArrayList();
+ private boolean _batchRequestInProgress;
+ private int _batchRequestsSize;
+ private BasicStream _batchStream;
+ private boolean _updateRequestHandler;
+}
diff --git a/java/src/IceInternal/ConnectionMonitor.java b/java/src/IceInternal/ConnectionMonitor.java
index 7f46d20f19b..3806b077b13 100644
--- a/java/src/IceInternal/ConnectionMonitor.java
+++ b/java/src/IceInternal/ConnectionMonitor.java
@@ -59,7 +59,7 @@ public final class ConnectionMonitor implements IceInternal.TimerTask
}
public void
- run()
+ runTimerTask()
{
java.util.HashSet connections = new java.util.HashSet();
diff --git a/java/src/IceInternal/ConnectionRequestHandler.java b/java/src/IceInternal/ConnectionRequestHandler.java
new file mode 100644
index 00000000000..2f1b1c031ed
--- /dev/null
+++ b/java/src/IceInternal/ConnectionRequestHandler.java
@@ -0,0 +1,134 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class ConnectionRequestHandler implements RequestHandler
+{
+ public void
+ prepareBatchRequest(BasicStream out)
+ {
+ _connection.prepareBatchRequest(out);
+ }
+
+ public void
+ finishBatchRequest(BasicStream out)
+ {
+ _connection.finishBatchRequest(out, _compress);
+ }
+
+ public void
+ abortBatchRequest()
+ {
+ _connection.abortBatchRequest();
+ }
+
+ public Ice.ConnectionI
+ sendRequest(Outgoing out)
+ throws LocalExceptionWrapper
+ {
+ return (!_connection.sendRequest(out, _compress, _response) || _response) ? _connection : null;
+ }
+
+ public void
+ sendAsyncRequest(OutgoingAsync out)
+ {
+ try
+ {
+ _connection.sendAsyncRequest(out, _compress, _response);
+ }
+ catch(LocalExceptionWrapper ex)
+ {
+ out.__finished(ex);
+ }
+ catch(Ice.LocalException ex)
+ {
+ out.__finished(ex);
+ }
+ }
+
+ public boolean
+ flushBatchRequests(BatchOutgoing out)
+ {
+ return _connection.flushBatchRequests(out);
+ }
+
+ public void
+ flushAsyncBatchRequests(BatchOutgoingAsync out)
+ {
+ try
+ {
+ _connection.flushAsyncBatchRequests(out);
+ }
+ catch(Ice.LocalException ex)
+ {
+ out.__finished(ex);
+ }
+ }
+
+ public Outgoing
+ getOutgoing(String operation, Ice.OperationMode mode, java.util.Map context)
+ throws LocalExceptionWrapper
+ {
+ return _connection.getOutgoing(this, operation, mode, context);
+ }
+
+ public void
+ reclaimOutgoing(Outgoing out)
+ {
+ _connection.reclaimOutgoing(out);
+ }
+
+ public Reference
+ getReference()
+ {
+ return _reference;
+ }
+
+ public Ice.ConnectionI
+ getConnection(boolean wait)
+ {
+ return _connection;
+ }
+
+ public
+ ConnectionRequestHandler(Reference ref, Ice.ObjectPrx proxy)
+ {
+ _reference = ref;
+ _response = _reference.getMode() == Reference.ModeTwoway;
+
+ Ice.BooleanHolder compress = new Ice.BooleanHolder();
+ _connection = _reference.getConnection(compress);
+ _compress = compress.value;
+
+ //
+ // If this proxy is for a non-local object, and we are using a router, then
+ // add this proxy to the router info object.
+ //
+ IceInternal.RouterInfo ri = _reference.getRouterInfo();
+ if(ri != null)
+ {
+ ri.addProxy(proxy);
+ }
+ }
+
+ public
+ ConnectionRequestHandler(Reference ref, Ice.ConnectionI connection, boolean compress)
+ {
+ _reference = ref;
+ _response = _reference.getMode() == Reference.ModeTwoway;
+ _connection = connection;
+ _compress = compress;
+ }
+
+ private final Reference _reference;
+ private final boolean _response;
+ private final Ice.ConnectionI _connection;
+ private final boolean _compress;
+}
diff --git a/java/src/IceInternal/Connector.java b/java/src/IceInternal/Connector.java
index 7e4c5d16f37..52b71a84a6a 100644
--- a/java/src/IceInternal/Connector.java
+++ b/java/src/IceInternal/Connector.java
@@ -12,6 +12,7 @@ package IceInternal;
public interface Connector
{
Transceiver connect(int timeout);
+
short type();
String toString();
diff --git a/java/src/IceInternal/DirectReference.java b/java/src/IceInternal/DirectReference.java
index 56224453de5..2a60fda7e7a 100644
--- a/java/src/IceInternal/DirectReference.java
+++ b/java/src/IceInternal/DirectReference.java
@@ -116,7 +116,7 @@ public class DirectReference extends RoutableReference
return getInstance().referenceFactory().create(getIdentity(), getContext(), getFacet(), getMode(),
getSecure(), getPreferSecure(), newAdapterId, getRouterInfo(),
locatorInfo, getCollocationOptimization(), getCacheConnection(),
- getEndpointSelection(), getThreadPerConnection(),
+ getEndpointSelection(), getThreadPerConnection(),
getLocatorCacheTimeout());
}
@@ -188,28 +188,57 @@ public class DirectReference extends RoutableReference
public Ice.ConnectionI
getConnection(Ice.BooleanHolder comp)
{
- EndpointI[] endpts = super.getRoutedEndpoints();
- applyOverrides(endpts);
-
- if(endpts.length == 0)
+ if(getRouterInfo() != null)
{
- endpts = _endpoints; // Endpoint overrides are already applied on these endpoints.
+ //
+ // If we route, we send everything to the router's client
+ // proxy endpoints.
+ //
+ EndpointI[] endpts = getRouterInfo().getClientEndpoints();
+ if(endpts.length > 0)
+ {
+ applyOverrides(endpts);
+ return createConnection(endpts, comp);
+ }
}
- Ice.ConnectionI connection = createConnection(endpts, comp);
+ return createConnection(_endpoints, comp);
+ }
- //
- // If we have a router, set the object adapter for this router
- // (if any) to the new connection, so that callbacks from the
- // router can be received over this new connection.
- //
+ public void
+ getConnection(final GetConnectionCallback callback)
+ {
if(getRouterInfo() != null)
{
- connection.setAdapter(getRouterInfo().getAdapter());
+ //
+ // If we route, we send everything to the router's client
+ // proxy endpoints.
+ //
+ getRouterInfo().getClientEndpoints(new RouterInfo.GetClientEndpointsCallback()
+ {
+ public void
+ setEndpoints(EndpointI[] endpts)
+ {
+ if(endpts.length > 0)
+ {
+ applyOverrides(endpts);
+ createConnection(endpts, callback);
+ return;
+ }
+
+ createConnection(_endpoints, callback);
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
+ return;
}
- assert(connection != null);
- return connection;
+ createConnection(_endpoints, callback);
}
public boolean
diff --git a/java/src/IceInternal/EndpointFactoryManager.java b/java/src/IceInternal/EndpointFactoryManager.java
index 52b2e21888e..fc772b3f6fe 100644
--- a/java/src/IceInternal/EndpointFactoryManager.java
+++ b/java/src/IceInternal/EndpointFactoryManager.java
@@ -80,7 +80,7 @@ public final class EndpointFactoryManager
EndpointI e = f.create(s.substring(m.end()), server);
BasicStream bs = new BasicStream(_instance, true);
e.streamWrite(bs);
- java.nio.ByteBuffer buf = bs.prepareRead();
+ java.nio.ByteBuffer buf = bs.getBuffer();
buf.position(0);
short type = bs.readShort();
EndpointI ue = new IceInternal.UnknownEndpointI(type, bs);
@@ -110,8 +110,8 @@ public final class EndpointFactoryManager
//
BasicStream bs = new BasicStream(_instance, true);
ue.streamWrite(bs);
- java.nio.ByteBuffer buf = bs.prepareRead();
- buf.position(0);
+ Buffer buf = bs.getBuffer();
+ buf.b.position(0);
short type = bs.readShort();
return f.read(bs);
}
@@ -136,7 +136,6 @@ public final class EndpointFactoryManager
return f.read(s);
}
}
-
return new UnknownEndpointI(type, s);
}
diff --git a/java/src/IceInternal/EndpointHostResolver.java b/java/src/IceInternal/EndpointHostResolver.java
new file mode 100644
index 00000000000..4ef6d756e0f
--- /dev/null
+++ b/java/src/IceInternal/EndpointHostResolver.java
@@ -0,0 +1,166 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class EndpointHostResolver
+{
+ EndpointHostResolver(Instance instance)
+ {
+ _instance = instance;
+
+ _thread = new HelperThread();
+ _thread.start();
+ }
+
+ synchronized public void
+ resolve(String host, int port, EndpointI endpoint, EndpointI_connectors callback)
+ {
+ //
+ // TODO: Optimize to avoid the lookup if the given host is a textual IPv4 or IPv6
+ // address. This requires implementing parsing of IPv4/IPv6 addresses (Java does
+ // not provide such methods).
+ //
+
+ assert(!_destroyed);
+
+ ResolveEntry entry = new ResolveEntry();
+ entry.host = host;
+ entry.port = port;
+ entry.endpoint = endpoint;
+ entry.callback = callback;
+ _queue.add(entry);
+ notify();
+ }
+
+ synchronized public void
+ destroy()
+ {
+ assert(!_destroyed);
+ _destroyed = true;
+ notify();
+ }
+
+ public void
+ joinWithThread()
+ {
+ if(_thread != null)
+ {
+ try
+ {
+ _thread.join();
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+ }
+
+ public void
+ run()
+ {
+ while(true)
+ {
+ ResolveEntry resolve;
+ synchronized(this)
+ {
+ while(!_destroyed && _queue.isEmpty())
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(_destroyed)
+ {
+ break;
+ }
+
+ resolve = (ResolveEntry)_queue.removeFirst();
+ }
+
+ resolve.callback.connectors(resolve.endpoint.connectors(Network.getAddresses(resolve.host, resolve.port)));
+ }
+
+ java.util.Iterator p = _queue.iterator();
+ while(p.hasNext())
+ {
+ ((ResolveEntry)p.next()).callback.exception(new Ice.CommunicatorDestroyedException());
+ }
+ _queue.clear();
+ }
+
+ class ResolveEntry
+ {
+ String host;
+ int port;
+ EndpointI endpoint;
+ EndpointI_connectors callback;
+ }
+
+ private final Instance _instance;
+ private boolean _destroyed;
+ private java.util.LinkedList _queue = new java.util.LinkedList();
+
+ private final class HelperThread extends Thread
+ {
+ HelperThread()
+ {
+ String threadName = _instance.initializationData().properties.getProperty("Ice.ProgramName");
+ if(threadName.length() > 0)
+ {
+ threadName += "-";
+ }
+ setName(threadName + "Ice.EndpointHostResolverThread");
+ }
+
+ public void
+ run()
+ {
+ if(_instance.initializationData().threadHook != null)
+ {
+ _instance.initializationData().threadHook.start();
+ }
+
+ try
+ {
+ EndpointHostResolver.this.run();
+ }
+ catch(Ice.LocalException ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "exception in endpoint host resolver thread " + getName() + ":\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ }
+ catch(java.lang.Exception ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "unknown exception in endpoint host resolver thread " + getName() + ":\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ }
+
+ if(_instance.initializationData().threadHook != null)
+ {
+ _instance.initializationData().threadHook.stop();
+ }
+ }
+ }
+
+ private HelperThread _thread;
+}
diff --git a/java/src/IceInternal/EndpointI.java b/java/src/IceInternal/EndpointI.java
index c0a29e2187e..8086bf138fd 100644
--- a/java/src/IceInternal/EndpointI.java
+++ b/java/src/IceInternal/EndpointI.java
@@ -86,7 +86,8 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable
// Return connectors for this endpoint, or empty list if no connector
// is available.
//
- public abstract java.util.ArrayList connectors();
+ public abstract java.util.List connectors();
+ public abstract void connectors_async(EndpointI_connectors callback);
//
// Return an acceptor for this endpoint, or null if no acceptors
@@ -101,12 +102,12 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable
// Expand endpoint out in to separate endpoints for each local
// host if listening on INADDR_NAY.
//
- public abstract java.util.ArrayList expand();
+ public abstract java.util.List expand();
//
- // Check whether the endpoint is equivalent to a specific Connector.
+ // Check whether the endpoint is equivalent to another one.
//
- public abstract boolean equivalent(Connector connector);
+ public abstract boolean equivalent(EndpointI endpoint);
//
// Compare endpoints for sorting purposes.
@@ -120,4 +121,15 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable
// TODO: Remove this when we no longer support SSL for JDK 1.4.
//
public abstract boolean requiresThreadPerConnection();
+
+ public java.util.List
+ connectors(java.util.List addresses)
+ {
+ //
+ // This method must be extended by endpoints which use the EndpointHostResolver to create
+ // connectors from IP addresses.
+ //
+ assert(false);
+ return null;
+ }
}
diff --git a/java/src/IceInternal/EndpointI_connectors.java b/java/src/IceInternal/EndpointI_connectors.java
new file mode 100644
index 00000000000..dd4f8bba305
--- /dev/null
+++ b/java/src/IceInternal/EndpointI_connectors.java
@@ -0,0 +1,16 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public interface EndpointI_connectors
+{
+ void connectors(java.util.List connectors);
+ void exception(Ice.LocalException ex);
+} \ No newline at end of file
diff --git a/java/src/IceInternal/EventHandler.java b/java/src/IceInternal/EventHandler.java
index 3a0ed6231a2..11241725083 100644
--- a/java/src/IceInternal/EventHandler.java
+++ b/java/src/IceInternal/EventHandler.java
@@ -25,12 +25,17 @@ public abstract class EventHandler
// Read data via the event handler. May only be called if
// readable() returns true.
//
- // NOTE: In Java, read returns true if the handler has more data
- // data available, and therefore read should be called again.
- //
abstract public boolean read(BasicStream is);
//
+ // In Java, it's possible that the transceiver reads more data
+ // than what was really asked. If this is the case, hasMoreData()
+ // returns true and the handler read() method should be called
+ // again (without doing a select()).
+ //
+ abstract public boolean hasMoreData();
+
+ //
// A complete message has been received.
//
abstract public void message(BasicStream stream, ThreadPool threadPool);
@@ -68,7 +73,8 @@ public abstract class EventHandler
protected Instance _instance;
//
- // The _stream data member is for use by ThreadPool only.
+ // The _stream data member is only for use by the ThreadPool or by the
+ // connection for validation.
//
- BasicStream _stream;
+ protected BasicStream _stream;
}
diff --git a/java/src/IceInternal/FixedReference.java b/java/src/IceInternal/FixedReference.java
index 055dc12b288..d86791e7fb0 100644
--- a/java/src/IceInternal/FixedReference.java
+++ b/java/src/IceInternal/FixedReference.java
@@ -198,6 +198,20 @@ public class FixedReference extends Reference
return connection;
}
+ public void
+ getConnection(GetConnectionCallback callback)
+ {
+ try
+ {
+ Ice.BooleanHolder compress = new Ice.BooleanHolder();
+ callback.setConnection(getConnection(compress), compress.value);
+ }
+ catch(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ }
+
public boolean
equals(java.lang.Object obj)
{
diff --git a/java/src/IceInternal/IncomingConnectionFactory.java b/java/src/IceInternal/IncomingConnectionFactory.java
index 5f2fdb15201..2d01a11be95 100644
--- a/java/src/IceInternal/IncomingConnectionFactory.java
+++ b/java/src/IceInternal/IncomingConnectionFactory.java
@@ -9,7 +9,7 @@
package IceInternal;
-public final class IncomingConnectionFactory extends EventHandler
+public final class IncomingConnectionFactory extends EventHandler implements Ice.ConnectionI.StartCallback
{
public synchronized void
activate()
@@ -73,7 +73,7 @@ public final class IncomingConnectionFactory extends EventHandler
waitUntilFinished()
{
Thread threadPerIncomingConnectionFactory = null;
- java.util.LinkedList connections;
+ java.util.LinkedList connections = null;
synchronized(this)
{
@@ -104,12 +104,10 @@ public final class IncomingConnectionFactory extends EventHandler
// We want to wait until all connections are finished outside the
// thread synchronization.
//
- // For consistency with C#, we set _connections to null rather than to a
- // new empty list so that our finalizer does not try to invoke any
- // methods on member objects.
- //
- connections = _connections;
- _connections = null;
+ if(_connections != null)
+ {
+ connections = new java.util.LinkedList(_connections);
+ }
}
if(threadPerIncomingConnectionFactory != null)
@@ -136,6 +134,16 @@ public final class IncomingConnectionFactory extends EventHandler
connection.waitUntilFinished();
}
}
+
+ synchronized(this)
+ {
+ //
+ // For consistency with C#, we set _connections to null rather than to a
+ // new empty list so that our finalizer does not try to invoke any
+ // methods on member objects.
+ //
+ _connections = null;
+ }
}
public EndpointI
@@ -145,7 +153,7 @@ public final class IncomingConnectionFactory extends EventHandler
return _endpoint;
}
- public synchronized Ice.ConnectionI[]
+ public synchronized java.util.LinkedList
connections()
{
java.util.LinkedList connections = new java.util.LinkedList();
@@ -157,26 +165,24 @@ public final class IncomingConnectionFactory extends EventHandler
while(p.hasNext())
{
Ice.ConnectionI connection = (Ice.ConnectionI)p.next();
- if(!connection.isDestroyed())
+ if(connection.isActiveOrHolding())
{
connections.add(connection);
}
}
-
- Ice.ConnectionI[] arr = new Ice.ConnectionI[connections.size()];
- connections.toArray(arr);
- return arr;
+
+ return connections;
}
public void
flushBatchRequests()
{
- Ice.ConnectionI[] c = connections(); // connections() is synchronized, so no need to synchronize here.
- for(int i = 0; i < c.length; i++)
+ java.util.Iterator p = connections().iterator(); // connections() is synchronized, no need to synchronize here.
+ while(p.hasNext())
{
try
{
- c[i].flushBatchRequests();
+ ((Ice.ConnectionI)p.next()).flushBatchRequests();
}
catch(Ice.LocalException ex)
{
@@ -211,6 +217,14 @@ public final class IncomingConnectionFactory extends EventHandler
return false;
}
+ public boolean
+ hasMoreData()
+ {
+ assert(!_threadPerConnection); // Only for use with a thread pool.
+ assert(false); // Must not be called.
+ return false;
+ }
+
public void
message(BasicStream unused, ThreadPool threadPool)
{
@@ -218,9 +232,9 @@ public final class IncomingConnectionFactory extends EventHandler
Ice.ConnectionI connection = null;
- synchronized(this)
+ try
{
- try
+ synchronized(this)
{
if(_state != StateActive)
{
@@ -244,7 +258,7 @@ public final class IncomingConnectionFactory extends EventHandler
//
// Now accept a new connection.
//
- Transceiver transceiver;
+ Transceiver transceiver = null;
try
{
transceiver = _acceptor.accept(0);
@@ -275,47 +289,38 @@ public final class IncomingConnectionFactory extends EventHandler
{
assert(!_threadPerConnection);
connection = new Ice.ConnectionI(_instance, transceiver, _endpoint, _adapter, false);
- connection.start();
}
catch(Ice.LocalException ex)
{
+ try
+ {
+ transceiver.close();
+ }
+ catch(Ice.LocalException exc)
+ {
+ // Ignore
+ }
+
+ if(_warn)
+ {
+ warning(ex);
+ }
return;
}
_connections.add(connection);
}
- finally
- {
- //
- // This makes sure that we promote a follower before
- // we leave the scope of the mutex above, but after we
- // call accept() (if we call it).
- //
- threadPool.promoteFollower();
- }
}
-
- assert(connection != null);
-
- //
- // We validate and activate outside the thread
- // synchronization, to not block the factory.
- //
- try
+ finally
{
- connection.validate();
- }
- catch(Ice.LocalException ex)
- {
- synchronized(this)
- {
- connection.waitUntilFinished(); // We must call waitUntilFinished() for cleanup.
- _connections.remove(connection);
- return;
- }
+ //
+ // This makes sure that we promote a follower before we leave the scope of the mutex
+ // above, but after we call accept() (if we call it).
+ //
+ threadPool.promoteFollower();
}
- connection.activate();
+ connection.start(this);
}
public synchronized void
@@ -354,9 +359,48 @@ public final class IncomingConnectionFactory extends EventHandler
return _acceptor.toString();
}
+ //
+ // Operations from ConnectionI.StartCallback
+ //
+ public synchronized void
+ connectionStartCompleted(Ice.ConnectionI connection)
+ {
+ //
+ // Initially, connections are in the holding state. If the factory is active
+ // we activate the connection.
+ //
+ if(_state == StateActive)
+ {
+ connection.activate();
+ }
+ }
+
+ public synchronized void
+ connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex)
+ {
+ if(_state == StateClosed)
+ {
+ return;
+ }
+
+ if(_warn)
+ {
+ warning(ex);
+ }
+
+ //
+ // If the connection is finished, remove it right away from
+ // the connection map. Otherwise, we keep it in the map, it
+ // will eventually be reaped.
+ //
+ if(connection.isFinished())
+ {
+ _connections.remove(connection);
+ }
+ }
+
public
- IncomingConnectionFactory(Instance instance, EndpointI endpoint, Ice.ObjectAdapter adapter,
- String adapterName)
+ IncomingConnectionFactory(Instance instance, EndpointI endpoint, Ice.ObjectAdapter adapter, String adapterName)
{
super(instance);
_endpoint = endpoint;
@@ -390,28 +434,25 @@ public final class IncomingConnectionFactory extends EventHandler
{
_endpoint = h.value;
- Ice.ConnectionI connection = null;
-
- try
- {
- connection = new Ice.ConnectionI(_instance, _transceiver, _endpoint, _adapter,
+ Ice.ConnectionI connection;
+ try
+ {
+ connection = new Ice.ConnectionI(_instance, _transceiver, _endpoint, _adapter,
_threadPerConnection);
- connection.start();
- connection.validate();
- }
- catch(Ice.LocalException ex)
- {
- //
- // If a connection object was constructed, then
- // validate() must have raised the exception.
- //
- if(connection != null)
- {
- connection.waitUntilFinished(); // We must call waitUntilFinished() for cleanup.
- }
-
- return;
- }
+ }
+ catch(Ice.LocalException ex)
+ {
+ try
+ {
+ _transceiver.close();
+ }
+ catch(Ice.LocalException exc)
+ {
+ // Ignore
+ }
+ throw ex;
+ }
+ connection.start(null);
_connections.add(connection);
}
@@ -654,8 +695,7 @@ public final class IncomingConnectionFactory extends EventHandler
}
catch(Ice.SocketException ex)
{
- // Do not ignore SocketException in Java.
- throw ex;
+ // Ignore socket exceptions.
}
catch(Ice.TimeoutException ex)
{
@@ -669,9 +709,8 @@ public final class IncomingConnectionFactory extends EventHandler
warning(ex);
}
}
-
+
Ice.ConnectionI connection = null;
-
synchronized(this)
{
while(_state == StateHolding)
@@ -730,37 +769,42 @@ public final class IncomingConnectionFactory extends EventHandler
}
}
- //
- // Create a connection object for the connection.
- //
- if(transceiver != null)
+ if(transceiver == null)
{
- try
- {
- connection = new Ice.ConnectionI(_instance, transceiver, _endpoint, _adapter,
- _threadPerConnection);
- connection.start();
- }
- catch(Ice.LocalException ex)
+ continue;
+ }
+
+ try
+ {
+ connection = new Ice.ConnectionI(_instance, transceiver, _endpoint, _adapter, _threadPerConnection);
+ }
+ catch(Ice.LocalException ex)
+ {
+ try
+ {
+ transceiver.close();
+ }
+ catch(Ice.LocalException exc)
+ {
+ // Ignore
+ }
+
+ if(_warn)
{
- return;
+ warning(ex);
}
-
- _connections.add(connection);
+ continue;
}
+ _connections.add(connection);
}
//
- // In thread per connection mode, the connection's thread
- // will take care of connection validation and activation
- // (for non-datagram connections). We don't want to block
- // this thread waiting until validation is complete,
- // because in contrast to thread pool mode, it is the only
- // thread that can accept connections with this factory's
- // acceptor. Therefore we don't call validate() and
- // activate() from the connection factory in thread per
- // connection mode.
+ // In thread-per-connection mode and regardless of the background mode,
+ // start() doesn't block. The connection thread is started and takes
+ // care of the connection validation and notifies the factory through
+ // the callback when it's done.
//
+ connection.start(this);
}
}
@@ -796,5 +840,5 @@ public final class IncomingConnectionFactory extends EventHandler
private int _state;
- private boolean _threadPerConnection;
+ private final boolean _threadPerConnection;
}
diff --git a/java/src/IceInternal/IndirectReference.java b/java/src/IceInternal/IndirectReference.java
index 004d63350dc..55eb6f60c13 100644
--- a/java/src/IceInternal/IndirectReference.java
+++ b/java/src/IceInternal/IndirectReference.java
@@ -163,23 +163,38 @@ public class IndirectReference extends RoutableReference
public Ice.ConnectionI
getConnection(Ice.BooleanHolder comp)
{
- Ice.ConnectionI connection;
+ if(getRouterInfo() != null)
+ {
+ //
+ // If we route, we send everything to the router's client
+ // proxy endpoints.
+ //
+ EndpointI[] endpts = getRouterInfo().getClientEndpoints();
+ if(endpts.length > 0)
+ {
+ applyOverrides(endpts);
+ return createConnection(endpts, comp);
+ }
+ }
while(true)
{
- EndpointI[] endpts = super.getRoutedEndpoints();
Ice.BooleanHolder cached = new Ice.BooleanHolder(false);
- if(endpts.length == 0 && _locatorInfo != null)
+ EndpointI[] endpts = null;
+ if(_locatorInfo != null)
{
endpts = _locatorInfo.getEndpoints(this, _locatorCacheTimeout, cached);
+ applyOverrides(endpts);
}
- applyOverrides(endpts);
+ if(endpts == null || endpts.length == 0)
+ {
+ throw new Ice.NoEndpointException(toString());
+ }
try
{
- connection = createConnection(endpts, comp);
- assert(connection != null);
+ return createConnection(endpts, comp);
}
catch(Ice.NoEndpointException ex)
{
@@ -187,44 +202,132 @@ public class IndirectReference extends RoutableReference
}
catch(Ice.LocalException ex)
{
- if(getRouterInfo() == null)
+ assert(_locatorInfo != null);
+ _locatorInfo.clearCache(this);
+ if(cached.value)
{
- assert(_locatorInfo != null);
- _locatorInfo.clearCache(this);
-
- if(cached.value)
+ TraceLevels traceLevels = getInstance().traceLevels();
+ if(traceLevels.retry >= 2)
{
- TraceLevels traceLevels = getInstance().traceLevels();
-
- if(traceLevels.retry >= 2)
- {
- String s = "connection to cached endpoints failed\n" +
- "removing endpoints from cache and trying one more time\n" + ex;
- getInstance().initializationData().logger.trace(traceLevels.retryCat, s);
- }
-
- continue;
+ String s = "connection to cached endpoints failed\n" +
+ "removing endpoints from cache and trying one more time\n" + ex;
+ getInstance().initializationData().logger.trace(traceLevels.retryCat, s);
}
+ continue; // Try again if the endpoints were cached.
}
-
throw ex;
}
-
- break;
}
+ }
- //
- // If we have a router, set the object adapter for this router
- // (if any) to the new connection, so that callbacks from the
- // router can be received over this new connection.
- //
+ public void
+ getConnection(final GetConnectionCallback callback)
+ {
if(getRouterInfo() != null)
{
- connection.setAdapter(getRouterInfo().getAdapter());
+ //
+ // If we route, we send everything to the router's client
+ // proxy endpoints.
+ //
+ getRouterInfo().getClientEndpoints(new RouterInfo.GetClientEndpointsCallback()
+ {
+ public void
+ setEndpoints(EndpointI[] endpts)
+ {
+ if(endpts.length > 0)
+ {
+ applyOverrides(endpts);
+ createConnection(endpts, callback);
+ }
+ else
+ {
+ getConnectionNoRouterInfo(callback);
+ }
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
}
+ else
+ {
+ getConnectionNoRouterInfo(callback);
+ }
+ }
- assert(connection != null);
- return connection;
+ private void
+ getConnectionNoRouterInfo(final GetConnectionCallback callback)
+ {
+ final IndirectReference self = this;
+ if(_locatorInfo != null)
+ {
+ _locatorInfo.getEndpoints(this, _locatorCacheTimeout, new LocatorInfo.GetEndpointsCallback()
+ {
+ public void
+ setEndpoints(EndpointI[] endpoints, final boolean cached)
+ {
+ if(endpoints.length == 0)
+ {
+ callback.setException(new Ice.NoEndpointException(self.toString()));
+ return;
+ }
+
+ applyOverrides(endpoints);
+ createConnection(endpoints, new GetConnectionCallback()
+ {
+ public void
+ setConnection(Ice.ConnectionI connection, boolean compress)
+ {
+ callback.setConnection(connection, compress);
+ }
+
+ public void
+ setException(Ice.LocalException exc)
+ {
+ try
+ {
+ throw exc;
+ }
+ catch(Ice.NoEndpointException ex)
+ {
+ callback.setException(ex); // No need to retry if there's no endpoints.
+ }
+ catch(Ice.LocalException ex)
+ {
+ assert(_locatorInfo != null);
+ _locatorInfo.clearCache(self);
+ if(cached)
+ {
+ TraceLevels traceLvls = getInstance().traceLevels();
+ if(traceLvls.retry >= 2)
+ {
+ String s = "connection to cached endpoints failed\n" +
+ "removing endpoints from cache and trying one more time\n" + ex;
+ getInstance().initializationData().logger.trace(traceLvls.retryCat, s);
+ }
+ getConnectionNoRouterInfo(callback); // Retry.
+ return;
+ }
+ callback.setException(ex);
+ }
+ }
+ });
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
+ }
+ else
+ {
+ callback.setException(new Ice.NoEndpointException(toString()));
+ }
}
public synchronized int
diff --git a/java/src/IceInternal/Instance.java b/java/src/IceInternal/Instance.java
index 3051450518d..aea0de5b8e7 100644
--- a/java/src/IceInternal/Instance.java
+++ b/java/src/IceInternal/Instance.java
@@ -158,14 +158,46 @@ public final class Instance
return _serverThreadPool;
}
+ public synchronized SelectorThread
+ selectorThread()
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_selectorThread == null) // Lazy initialization.
+ {
+ _selectorThread = new SelectorThread(this);
+ }
+
+ return _selectorThread;
+ }
+
+ public synchronized EndpointHostResolver
+ endpointHostResolver()
+ {
+ if(_state == StateDestroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ if(_endpointHostResolver == null) // Lazy initialization.
+ {
+ _endpointHostResolver = new EndpointHostResolver(this);
+ }
+
+ return _endpointHostResolver;
+ }
+
synchronized public Timer
timer()
{
if(_state == StateDestroyed)
{
throw new Ice.CommunicatorDestroyedException();
- }
-
+ }
+
if(_timer == null) // Lazy initialization.
{
_timer = new Timer(this);
@@ -186,6 +218,12 @@ public final class Instance
return _threadPerConnectionStackSize;
}
+ public boolean
+ background()
+ {
+ return _background;
+ }
+
public synchronized EndpointFactoryManager
endpointFactoryManager()
{
@@ -598,6 +636,8 @@ public final class Instance
_threadPerConnectionStackSize = stackSize;
}
+ _background = _initData.properties.getPropertyAsInt("Ice.Background") > 0;
+
_routerManager = new RouterManager();
_locatorManager = new LocatorManager();
@@ -655,6 +695,8 @@ public final class Instance
IceUtil.Assert.FinalizerAssert(_objectAdapterFactory == null);
IceUtil.Assert.FinalizerAssert(_clientThreadPool == null);
IceUtil.Assert.FinalizerAssert(_serverThreadPool == null);
+ IceUtil.Assert.FinalizerAssert(_selectorThread == null);
+ IceUtil.Assert.FinalizerAssert(_endpointHostResolver == null);
IceUtil.Assert.FinalizerAssert(_timer == null);
IceUtil.Assert.FinalizerAssert(_routerManager == null);
IceUtil.Assert.FinalizerAssert(_locatorManager == null);
@@ -777,6 +819,8 @@ public final class Instance
ThreadPool serverThreadPool = null;
ThreadPool clientThreadPool = null;
+ SelectorThread selectorThread = null;
+ EndpointHostResolver endpointHostResolver = null;
synchronized(this)
{
@@ -804,6 +848,20 @@ public final class Instance
_clientThreadPool = null;
}
+ if(_selectorThread != null)
+ {
+ _selectorThread.destroy();
+ selectorThread = _selectorThread;
+ _selectorThread = null;
+ }
+
+ if(_endpointHostResolver != null)
+ {
+ _endpointHostResolver.destroy();
+ endpointHostResolver = _endpointHostResolver;
+ _endpointHostResolver = null;
+ }
+
if(_timer != null)
{
_timer._destroy();
@@ -857,8 +915,7 @@ public final class Instance
}
//
- // Join with the thread pool threads outside the
- // synchronization.
+ // Join with threads outside the synchronization.
//
if(clientThreadPool != null)
{
@@ -868,6 +925,14 @@ public final class Instance
{
serverThreadPool.joinWithAllThreads();
}
+ if(selectorThread != null)
+ {
+ selectorThread.joinWithThread();
+ }
+ if(endpointHostResolver != null)
+ {
+ endpointHostResolver.joinWithThread();
+ }
if(_initData.properties.getPropertyAsInt("Ice.Warn.UnusedProperties") > 0)
{
@@ -935,9 +1000,12 @@ public final class Instance
private ObjectAdapterFactory _objectAdapterFactory;
private ThreadPool _clientThreadPool;
private ThreadPool _serverThreadPool;
+ private SelectorThread _selectorThread;
+ private EndpointHostResolver _endpointHostResolver;
private Timer _timer;
private final boolean _threadPerConnection;
private final int _threadPerConnectionStackSize;
+ private final boolean _background;
private EndpointFactoryManager _endpointFactoryManager;
private Ice.PluginManager _pluginManager;
private java.util.Map _defaultContext;
diff --git a/java/src/IceInternal/LocatorInfo.java b/java/src/IceInternal/LocatorInfo.java
index 0d54d87555a..c5b4b1d0060 100644
--- a/java/src/IceInternal/LocatorInfo.java
+++ b/java/src/IceInternal/LocatorInfo.java
@@ -11,6 +11,12 @@ package IceInternal;
public final class LocatorInfo
{
+ interface GetEndpointsCallback
+ {
+ void setEndpoints(EndpointI[] endpoints, boolean cached);
+ void setException(Ice.LocalException ex);
+ }
+
LocatorInfo(Ice.LocatorPrx locator, LocatorTable table)
{
_locator = locator;
@@ -158,94 +164,137 @@ public final class LocatorInfo
cached.value = objectCached || endpointsCached;
}
}
- catch(Ice.AdapterNotFoundException ex)
+ catch(Exception ex)
{
- if(ref.getInstance().traceLevels().location >= 1)
- {
- StringBuffer s = new StringBuffer();
- s.append("adapter not found\n");
- s.append("adapter = " + adapterId);
- ref.getInstance().initializationData().logger.trace(
- ref.getInstance().traceLevels().locationCat, s.toString());
- }
-
- Ice.NotRegisteredException e = new Ice.NotRegisteredException();
- e.kindOfObject = "object adapter";
- e.id = adapterId;
- throw e;
+ getEndpointsException(ref, ex);
}
- catch(Ice.ObjectNotFoundException ex)
- {
- if(ref.getInstance().traceLevels().location >= 1)
- {
- StringBuffer s = new StringBuffer();
- s.append("object not found\n");
- s.append("object = " + ref.getInstance().identityToString(identity));
- ref.getInstance().initializationData().logger.trace(
- ref.getInstance().traceLevels().locationCat, s.toString());
- }
- Ice.NotRegisteredException e = new Ice.NotRegisteredException();
- e.kindOfObject = "object";
- e.id = ref.getInstance().identityToString(identity);
- throw e;
- }
- catch(Ice.NotRegisteredException ex)
+ if(ref.getInstance().traceLevels().location >= 1)
{
- throw ex;
+ getEndpointsTrace(ref, endpoints, cached.value);
}
- catch(Ice.LocalException ex)
+
+ return endpoints == null ? new EndpointI[0] : endpoints;
+ }
+
+ public void
+ getEndpoints(final IndirectReference ref, final int ttl, final GetEndpointsCallback callback)
+ {
+ final String adapterId = ref.getAdapterId();
+ final Ice.Identity identity = ref.getIdentity();
+ final Instance instance = ref.getInstance();
+ if(adapterId.length() > 0)
{
- if(ref.getInstance().traceLevels().location >= 1)
+ EndpointI[] endpoints = _table.getAdapterEndpoints(adapterId, ttl);
+ if(endpoints == null)
{
- StringBuffer s = new StringBuffer();
- s.append("couldn't contact the locator to retrieve adapter endpoints\n");
- if(adapterId.length() > 0)
+ if(instance.traceLevels().location >= 1)
{
- s.append("adapter = " + adapterId + "\n");
+ StringBuffer s = new StringBuffer();
+ s.append("searching for adapter by id\n");
+ s.append("adapter = " + adapterId);
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
}
- else
+
+ //
+ // Search the adapter in the location service if we didn't
+ // find it in the cache.
+ //
+ _locator.findAdapterById_async(new Ice.AMI_Locator_findAdapterById()
+ {
+ public void
+ ice_response(Ice.ObjectPrx object)
+ {
+ EndpointI[] endpoints = null;
+ if(object != null)
+ {
+ endpoints = ((Ice.ObjectPrxHelperBase)object).__reference().getEndpoints();
+ if(endpoints.length > 0)
+ {
+ _table.addAdapterEndpoints(adapterId, endpoints);
+ }
+ }
+
+ if(instance.traceLevels().location >= 1)
+ {
+ getEndpointsTrace(ref, endpoints, false);
+ }
+
+ if(endpoints == null)
+ {
+ callback.setEndpoints(new EndpointI[0], false);
+ }
+ else
+ {
+ callback.setEndpoints(endpoints, false);
+ }
+ }
+
+ public void
+ ice_exception(Ice.UserException ex)
+ {
+ getEndpointsException(ref, ex, callback);
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ getEndpointsException(ref, ex, callback);
+ }
+ }, adapterId);
+ return;
+ }
+ else
+ {
+ if(instance.traceLevels().location >= 1)
{
- s.append("object = " + ref.getInstance().identityToString(identity) + "\n");
+ getEndpointsTrace(ref, endpoints, true);
}
- s.append("reason = " + ex);
- ref.getInstance().initializationData().logger.trace(
- ref.getInstance().traceLevels().locationCat, s.toString());
+ callback.setEndpoints(endpoints, true);
+ return;
}
- throw ex;
}
-
- if(ref.getInstance().traceLevels().location >= 1)
+ else
{
- if(endpoints != null && endpoints.length > 0)
+ Ice.ObjectPrx object = _table.getProxy(identity, ttl);
+ if(object == null)
{
- if(cached.value)
- {
- trace("found endpoints in locator table", ref, endpoints);
- }
- else
+ if(instance.traceLevels().location >= 1)
{
- trace("retrieved endpoints from locator, adding to locator table", ref, endpoints);
+ StringBuffer s = new StringBuffer();
+ s.append("searching for object by id\n");
+ s.append("object = " + instance.identityToString(identity));
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
}
+
+ _locator.findObjectById_async(new Ice.AMI_Locator_findObjectById()
+ {
+ public void
+ ice_response(Ice.ObjectPrx object)
+ {
+ getWellKnownObjectEndpoints(ref, object, ttl, false, callback);
+ }
+
+ public void
+ ice_exception(Ice.UserException ex)
+ {
+ getEndpointsException(ref, ex, callback);
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ getEndpointsException(ref, ex, callback);
+ }
+ }, identity);
+ return;
}
else
{
- StringBuffer s = new StringBuffer();
- s.append("no endpoints configured for ");
- if(adapterId.length() > 0)
- {
- s.append("adapter\n");
- s.append("adapter = " + adapterId + "\n");
- }
- else
- {
- s.append("object\n");
- s.append("object = " + ref.getInstance().identityToString(identity) + "\n");
- }
+ getWellKnownObjectEndpoints(ref, object, ttl, true, callback);
+ return;
}
}
-
- return endpoints == null ? new EndpointI[0] : endpoints;
}
public void
@@ -333,14 +382,204 @@ public final class LocatorInfo
{
s.append(endpoints[i].toString());
if(i + 1 < sz)
+ {
s.append(":");
+ }
}
ref.getInstance().initializationData().logger.trace(ref.getInstance().traceLevels().locationCat, s.toString());
}
+ private void
+ getEndpointsException(IndirectReference ref, Exception exc)
+ {
+ try
+ {
+ throw exc;
+ }
+ catch(Ice.AdapterNotFoundException ex)
+ {
+ final Instance instance = ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("adapter not found\n");
+ s.append("adapter = " + ref.getAdapterId());
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
+ }
+
+ Ice.NotRegisteredException e = new Ice.NotRegisteredException();
+ e.kindOfObject = "object adapter";
+ e.id = ref.getAdapterId();
+ throw e;
+ }
+ catch(Ice.ObjectNotFoundException ex)
+ {
+ final Instance instance = ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("object not found\n");
+ s.append("object = " + instance.identityToString(ref.getIdentity()));
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
+ }
+
+ Ice.NotRegisteredException e = new Ice.NotRegisteredException();
+ e.kindOfObject = "object";
+ e.id = instance.identityToString(ref.getIdentity());
+ throw e;
+ }
+ catch(Ice.NotRegisteredException ex)
+ {
+ throw ex;
+ }
+ catch(Ice.LocalException ex)
+ {
+ final Instance instance = ref.getInstance();
+ if(instance.traceLevels().location >= 1)
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("couldn't contact the locator to retrieve adapter endpoints\n");
+ if(ref.getAdapterId().length() > 0)
+ {
+ s.append("adapter = " + ref.getAdapterId() + "\n");
+ }
+ else
+ {
+ s.append("object = " + instance.identityToString(ref.getIdentity()) + "\n");
+ }
+ s.append("reason = " + ex);
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
+ }
+ throw ex;
+ }
+ catch(Exception ex)
+ {
+ assert(false);
+ }
+ }
+
+ private void
+ getEndpointsException(IndirectReference ref, Exception exc, GetEndpointsCallback callback)
+ {
+ try
+ {
+ getEndpointsException(ref, exc);
+ }
+ catch(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ catch(Exception ex)
+ {
+ assert(false);
+ }
+ }
+
+ private void
+ getWellKnownObjectEndpoints(final IndirectReference ref,
+ final Ice.ObjectPrx object,
+ final int ttl,
+ final boolean objectCached,
+ final GetEndpointsCallback callback)
+ {
+ EndpointI[] endpoints = null;
+ if(object != null)
+ {
+ Reference r = ((Ice.ObjectPrxHelperBase)object).__reference();
+ if(r instanceof DirectReference)
+ {
+ DirectReference odr = (DirectReference)r;
+ endpoints = odr.getEndpoints();
+ }
+ else
+ {
+ IndirectReference oir = (IndirectReference)r;
+ if(oir.getAdapterId().length() > 0)
+ {
+ getEndpoints(oir, ttl, new GetEndpointsCallback()
+ {
+ public void
+ setEndpoints(EndpointI[] endpoints, boolean endpointsCached)
+ {
+ if(!objectCached && endpoints != null && endpoints.length > 0)
+ {
+ _table.addProxy(ref.getIdentity(), object);
+ }
+
+ if(ref.getInstance().traceLevels().location >= 1)
+ {
+ getEndpointsTrace(ref, endpoints, objectCached || endpointsCached);
+ }
+
+ callback.setEndpoints(endpoints, objectCached || endpointsCached);
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
+ return;
+ }
+ }
+ }
+
+ if(!objectCached && endpoints != null && endpoints.length > 0)
+ {
+ _table.addProxy(ref.getIdentity(), object);
+ }
+
+ if(ref.getInstance().traceLevels().location >= 1)
+ {
+ getEndpointsTrace(ref, endpoints, objectCached);
+ }
+
+ if(endpoints == null)
+ {
+ callback.setEndpoints(new EndpointI[0], false);
+ }
+ else
+ {
+ callback.setEndpoints(endpoints, objectCached);
+ }
+ }
+
+ private void
+ getEndpointsTrace(IndirectReference ref, EndpointI[] endpoints, boolean cached)
+ {
+ if(endpoints != null && endpoints.length > 0)
+ {
+ if(cached)
+ {
+ trace("found endpoints in locator table", ref, endpoints);
+ }
+ else
+ {
+ trace("retrieved endpoints from locator, adding to locator table", ref, endpoints);
+ }
+ }
+ else
+ {
+ final Instance instance = ref.getInstance();
+ StringBuffer s = new StringBuffer();
+ s.append("no endpoints configured for ");
+ if(ref.getAdapterId().length() > 0)
+ {
+ s.append("adapter\n");
+ s.append("adapter = " + ref.getAdapterId() + "\n");
+ }
+ else
+ {
+ s.append("object\n");
+ s.append("object = " + instance.identityToString(ref.getIdentity()) + "\n");
+ }
+ instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString());
+ }
+ }
+
private final Ice.LocatorPrx _locator;
private Ice.LocatorRegistryPrx _locatorRegistry;
private final LocatorTable _table;
}
-
diff --git a/java/src/IceInternal/Network.java b/java/src/IceInternal/Network.java
index 07770711f45..5971e1122d5 100644
--- a/java/src/IceInternal/Network.java
+++ b/java/src/IceInternal/Network.java
@@ -162,7 +162,7 @@ public final class Network
}
}
- private static void
+ public static void
closeSocketNoThrow(java.nio.channels.SelectableChannel fd)
{
try
@@ -274,13 +274,74 @@ public final class Network
}
}
- public static void
+ public static boolean
doConnect(java.nio.channels.SocketChannel fd, java.net.InetSocketAddress addr, int timeout)
{
try
{
if(!fd.connect(addr))
{
+ if(timeout == 0)
+ {
+ return false;
+ }
+
+ try
+ {
+ doFinishConnect(fd, timeout);
+ }
+ catch(Ice.LocalException ex)
+ {
+ closeSocketNoThrow(fd);
+ throw ex;
+ }
+ return true;
+ }
+ }
+ catch(java.net.ConnectException ex)
+ {
+ closeSocketNoThrow(fd);
+
+ Ice.ConnectFailedException se;
+ if(connectionRefused(ex))
+ {
+ se = new Ice.ConnectionRefusedException();
+ }
+ else
+ {
+ se = new Ice.ConnectFailedException();
+ }
+ se.initCause(ex);
+ throw se;
+ }
+ catch(java.io.IOException ex)
+ {
+ closeSocketNoThrow(fd);
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+
+ if(addr.equals(fd.socket().getLocalSocketAddress()))
+ {
+ closeSocketNoThrow(fd);
+ throw new Ice.ConnectionRefusedException();
+ }
+ return true;
+ }
+
+ public static void
+ doFinishConnect(java.nio.channels.SocketChannel fd, int timeout)
+ {
+ //
+ // Note: we don't close the socket if there's an exception. It's the responsibility
+ // of the caller to do so.
+ //
+
+ if(timeout != 0)
+ {
+ try
+ {
java.nio.channels.Selector selector = java.nio.channels.Selector.open();
try
{
@@ -288,17 +349,13 @@ public final class Network
{
try
{
- java.nio.channels.SelectionKey key =
+ java.nio.channels.SelectionKey key =
fd.register(selector, java.nio.channels.SelectionKey.OP_CONNECT);
int n;
if(timeout > 0)
{
n = selector.select(timeout);
}
- else if(timeout == 0)
- {
- n = selector.selectNow();
- }
else
{
n = selector.select();
@@ -306,7 +363,6 @@ public final class Network
if(n == 0)
{
- closeSocketNoThrow(fd);
throw new Ice.ConnectTimeoutException();
}
@@ -335,17 +391,35 @@ public final class Network
// Ignore
}
}
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
- if(!fd.finishConnect())
- {
- throw new Ice.ConnectFailedException();
- }
+ try
+ {
+ if(!fd.finishConnect())
+ {
+ throw new Ice.ConnectFailedException();
+ }
+
+ //
+ // Prevent self connect (self connect happens on Linux when a client tries to connect to
+ // a server which was just deactivated if the client socket re-uses the same ephemeral
+ // port as the server).
+ //
+ java.net.SocketAddress addr = fd.socket().getRemoteSocketAddress();
+ if(addr != null && addr.equals(fd.socket().getLocalSocketAddress()))
+ {
+ throw new Ice.ConnectionRefusedException();
}
}
catch(java.net.ConnectException ex)
{
- closeSocketNoThrow(fd);
-
Ice.ConnectFailedException se;
if(connectionRefused(ex))
{
@@ -360,7 +434,6 @@ public final class Network
}
catch(java.io.IOException ex)
{
- closeSocketNoThrow(fd);
Ice.SocketException se = new Ice.SocketException();
se.initCause(ex);
throw se;
diff --git a/java/src/IceInternal/Outgoing.java b/java/src/IceInternal/Outgoing.java
index 85cf0c1ce9b..fd22795c6cf 100644
--- a/java/src/IceInternal/Outgoing.java
+++ b/java/src/IceInternal/Outgoing.java
@@ -9,19 +9,19 @@
package IceInternal;
-public final class Outgoing
+public final class Outgoing implements OutgoingMessageCallback
{
public
- Outgoing(Ice.ConnectionI connection, Reference ref, String operation, Ice.OperationMode mode,
- java.util.Map context, boolean compress)
+ Outgoing(RequestHandler handler, String operation, Ice.OperationMode mode, java.util.Map context)
throws LocalExceptionWrapper
{
- _connection = connection;
- _reference = ref;
_state = StateUnsent;
- _is = new BasicStream(ref.getInstance());
- _os = new BasicStream(ref.getInstance());
- _compress = compress;
+ _sent = false;
+ _handler = handler;
+
+ Instance instance = _handler.getReference().getInstance();
+ _is = new BasicStream(instance);
+ _os = new BasicStream(instance);
writeHeader(operation, mode, context);
}
@@ -30,13 +30,13 @@ public final class Outgoing
// These functions allow this object to be reused, rather than reallocated.
//
public void
- reset(Reference ref, String operation, Ice.OperationMode mode, java.util.Map context, boolean compress)
+ reset(RequestHandler handler, String operation, Ice.OperationMode mode, java.util.Map context)
throws LocalExceptionWrapper
{
- _reference = ref;
_state = StateUnsent;
_exception = null;
- _compress = compress;
+ _sent = false;
+ _handler = handler;
writeHeader(operation, mode, context);
}
@@ -57,41 +57,39 @@ public final class Outgoing
_os.endWriteEncaps();
- switch(_reference.getMode())
+ switch(_handler.getReference().getMode())
{
case Reference.ModeTwoway:
{
- //
- // We let all exceptions raised by sending directly
- // propagate to the caller, because they can be
- // retried without violating "at-most-once". In case
- // of such exceptions, the connection object does not
- // call back on this object, so we don't need to lock
- // the mutex, keep track of state, or save exceptions.
- //
- _connection.sendRequest(_os, this, _compress);
+ _state = StateInProgress;
- //
- // Wait until the request has completed, or until the
- // request times out.
- //
+ Ice.ConnectionI connection = _handler.sendRequest(this);
boolean timedOut = false;
synchronized(this)
{
+
//
- // It's possible that the request has already
- // completed, due to a regular response, or because of
- // an exception. So we only change the state to "in
- // progress" if it is still "unsent".
+ // If the request is being sent in the background we first wait for the
+ // sent notification.
//
- if(_state == StateUnsent)
+ while(_state != StateFailed && !_sent)
{
- _state = StateInProgress;
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
}
-
- int timeout = _connection.timeout();
+
+ //
+ // Wait until the request has completed, or until the request
+ // times out.
+ //
+ int timeout = connection.timeout();
while(_state == StateInProgress && !timedOut)
{
try
@@ -99,7 +97,7 @@ public final class Outgoing
if(timeout >= 0)
{
wait(timeout);
-
+
if(_state == StateInProgress)
{
timedOut = true;
@@ -115,15 +113,15 @@ public final class Outgoing
}
}
}
-
+
if(timedOut)
{
//
// Must be called outside the synchronization of
// this object
//
- _connection.exception(new Ice.TimeoutException());
-
+ connection.exception(new Ice.TimeoutException());
+
//
// We must wait until the exception set above has
// propagated to this Outgoing object.
@@ -142,11 +140,11 @@ public final class Outgoing
}
}
}
-
+
if(_exception != null)
{
_exception.fillInStackTrace();
-
+
//
// A CloseConnectionException indicates graceful
// server shutdown, and is therefore always repeatable
@@ -158,12 +156,13 @@ public final class Outgoing
// An ObjectNotExistException can always be retried as
// well without violating "at-most-once".
//
- if(_exception instanceof Ice.CloseConnectionException ||
+ if(!_sent ||
+ _exception instanceof Ice.CloseConnectionException ||
_exception instanceof Ice.ObjectNotExistException)
{
throw _exception;
}
-
+
//
// Throw the exception wrapped in a LocalExceptionWrapper, to
// indicate that the request cannot be resent without
@@ -171,30 +170,68 @@ public final class Outgoing
//
throw new LocalExceptionWrapper(_exception, false);
}
-
+
if(_state == StateUserException)
{
return false;
}
-
- assert(_state == StateOK);
- break;
+ else
+ {
+ assert(_state == StateOK);
+ return true;
+ }
+
}
case Reference.ModeOneway:
case Reference.ModeDatagram:
{
- //
- // For oneway and datagram requests, the connection object
- // never calls back on this object. Therefore we don't
- // need to lock the mutex or save exceptions. We simply
- // let all exceptions from sending propagate to the
- // caller, because such exceptions can be retried without
- // violating "at-most-once".
- //
- _state = StateInProgress;
- _connection.sendRequest(_os, null, _compress);
- break;
+ try
+ {
+ _state = StateInProgress;
+ if(_handler.sendRequest(this) != null)
+ {
+ //
+ // If the handler returns the connection, we must wait for the sent callback.
+ //
+ synchronized(this)
+ {
+ while(_state != StateFailed && !_sent)
+ {
+ try
+ {
+ wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(_exception != null)
+ {
+ assert(!_sent);
+ throw _exception;
+ }
+ }
+ }
+ return true;
+ }
+ catch(Ice.LocalException ex) // Java specfic work-around (see ConnectionI.sendRequest())
+ {
+ if(!_sent) // The send might have failed but the request might still be sent...
+ {
+ throw ex;
+ }
+ else
+ {
+ //
+ // We wrap the exception into a LocalExceptionWrapper to indicate that
+ // the request cannot be resent without potentially violating the
+ // "at-most-once" principle.
+ //
+ throw new IceInternal.LocalExceptionWrapper(ex, false);
+ }
+ }
}
case Reference.ModeBatchOneway:
@@ -206,12 +243,13 @@ public final class Outgoing
// apply.
//
_state = StateInProgress;
- _connection.finishBatchRequest(_os, _compress);
- break;
+ _handler.finishBatchRequest(_os);
+ return true;
}
}
-
- return true;
+
+ assert(false);
+ return false;
}
public void
@@ -225,10 +263,10 @@ public final class Outgoing
// must notify the connection about that we give up ownership
// of the batch stream.
//
- int mode = _reference.getMode();
+ int mode = _handler.getReference().getMode();
if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram)
{
- _connection.abortBatchRequest();
+ _handler.abortBatchRequest();
//
// If we abort a batch requests, we cannot retry, because
@@ -242,10 +280,31 @@ public final class Outgoing
throw ex;
}
+ public void
+ sent(boolean notify)
+ {
+ if(notify)
+ {
+ synchronized(this)
+ {
+ _sent = true;
+ notify();
+ }
+ }
+ else
+ {
+ //
+ // No synchronization is necessary if called from sendRequest() because the connection
+ // send mutex is locked and no other threads can call on Outgoing until it's released.
+ //
+ _sent = true;
+ }
+ }
+
public synchronized void
finished(BasicStream is)
{
- assert(_reference.getMode() == Reference.ModeTwoway); // Can only be called for twoways.
+ assert(_handler.getReference().getMode() == Reference.ModeTwoway); // Only for twoways.
assert(_state <= StateInProgress);
@@ -390,11 +449,8 @@ public final class Outgoing
public synchronized void
finished(Ice.LocalException ex)
{
- assert(_reference.getMode() == Reference.ModeTwoway); // Can only be called for twoways.
-
assert(_state <= StateInProgress);
-
- _state = StateLocalException;
+ _state = StateFailed;
_exception = ex;
notify();
}
@@ -415,7 +471,7 @@ public final class Outgoing
writeHeader(String operation, Ice.OperationMode mode, java.util.Map context)
throws LocalExceptionWrapper
{
- switch(_reference.getMode())
+ switch(_handler.getReference().getMode())
{
case Reference.ModeTwoway:
case Reference.ModeOneway:
@@ -428,19 +484,19 @@ public final class Outgoing
case Reference.ModeBatchOneway:
case Reference.ModeBatchDatagram:
{
- _connection.prepareBatchRequest(_os);
+ _handler.prepareBatchRequest(_os);
break;
}
}
try
{
- _reference.getIdentity().__write(_os);
+ _handler.getReference().getIdentity().__write(_os);
//
// For compatibility with the old FacetPath.
//
- String facet = _reference.getFacet();
+ String facet = _handler.getReference().getFacet();
if(facet == null || facet.length() == 0)
{
_os.writeStringSeq(null);
@@ -467,10 +523,8 @@ public final class Outgoing
//
// Implicit context
//
- Ice.ImplicitContextI implicitContext =
- _reference.getInstance().getImplicitContext();
-
- java.util.Map prxContext = _reference.getContext();
+ Ice.ImplicitContextI implicitContext = _handler.getReference().getInstance().getImplicitContext();
+ java.util.Map prxContext = _handler.getReference().getContext();
if(implicitContext == null)
{
@@ -495,8 +549,11 @@ public final class Outgoing
}
}
- private Ice.ConnectionI _connection;
- private Reference _reference;
+ private RequestHandler _handler;
+ private BasicStream _is;
+ private BasicStream _os;
+ private boolean _sent;
+
private Ice.LocalException _exception;
private static final int StateUnsent = 0;
@@ -504,12 +561,8 @@ public final class Outgoing
private static final int StateOK = 2;
private static final int StateUserException = 3;
private static final int StateLocalException = 4;
+ private static final int StateFailed = 5;
private int _state;
- private BasicStream _is;
- private BasicStream _os;
-
- private boolean _compress;
-
public Outgoing next; // For use by Ice._ObjectDelM
}
diff --git a/java/src/IceInternal/OutgoingAsync.java b/java/src/IceInternal/OutgoingAsync.java
index 8f49c69ac06..184355e8e06 100644
--- a/java/src/IceInternal/OutgoingAsync.java
+++ b/java/src/IceInternal/OutgoingAsync.java
@@ -9,7 +9,7 @@
package IceInternal;
-public abstract class OutgoingAsync
+public abstract class OutgoingAsync implements OutgoingAsyncMessageCallback
{
public
OutgoingAsync()
@@ -18,19 +18,75 @@ public abstract class OutgoingAsync
public abstract void ice_exception(Ice.LocalException ex);
+ public final BasicStream
+ __os()
+ {
+ return __os;
+ }
+
public final void
- __finished(BasicStream is)
+ __sent(final Ice.ConnectionI connection)
{
synchronized(_monitor)
{
- byte replyStatus;
-
- try
+ _sent = true;
+
+ if(!_proxy.ice_isTwoway())
+ {
+ cleanup(); // No response expected, we're done with the OutgoingAsync.
+ }
+ else if(_response)
+ {
+ _monitor.notifyAll(); // If the response was already received notify finished() which is waiting.
+ }
+ else if(connection.timeout() >= 0)
+ {
+ assert(_timerTask == null);
+ _timerTask = new TimerTask()
+ {
+ public void
+ runTimerTask()
+ {
+ __runTimerTask(connection);
+ }
+ };
+ _proxy.__reference().getInstance().timer().schedule(_timerTask, connection.timeout());
+ }
+ }
+ }
+
+ public final void
+ __finished(BasicStream is)
+ {
+ assert(_proxy.ice_isTwoway()); // Can only be called for twoways.
+
+ byte replyStatus;
+ try
+ {
+ synchronized(_monitor)
{
+ assert(__os != null);
+ _response = true;
+
+ if(_timerTask != null && _proxy.__reference().getInstance().timer().cancel(_timerTask))
+ {
+ _timerTask = null; // Timer cancelled.
+ }
+
+ while(!_sent || _timerTask != null)
+ {
+ try
+ {
+ _monitor.wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
__is.swap(is);
-
replyStatus = __is.readByte();
-
+
switch(replyStatus)
{
case ReplyStatus.replyOK:
@@ -39,7 +95,7 @@ public abstract class OutgoingAsync
__is.startReadEncaps();
break;
}
-
+
case ReplyStatus.replyObjectNotExist:
case ReplyStatus.replyFacetNotExist:
case ReplyStatus.replyOperationNotExist:
@@ -145,36 +201,57 @@ public abstract class OutgoingAsync
}
}
}
- catch(Ice.LocalException ex)
- {
- __finished(ex);
- return;
- }
-
- assert(replyStatus == ReplyStatus.replyOK || replyStatus == ReplyStatus.replyUserException);
+ }
+ catch(Ice.LocalException ex)
+ {
+ __finished(ex);
+ return;
+ }
+
+ assert(replyStatus == ReplyStatus.replyOK || replyStatus == ReplyStatus.replyUserException);
- try
- {
- __response(replyStatus == ReplyStatus.replyOK);
- }
- catch(java.lang.Exception ex)
- {
- warning(ex);
- }
- finally
+ try
+ {
+ __response(replyStatus == ReplyStatus.replyOK);
+ }
+ catch(java.lang.Exception ex)
+ {
+ warning(ex);
+ }
+ finally
+ {
+ synchronized(_monitor)
{
cleanup();
}
}
}
+
public final void
__finished(Ice.LocalException exc)
{
+ boolean retry = false;
synchronized(_monitor)
{
- if(__os != null) // Don't retry if cleanup() was already called.
+ if(__os != null) // Might be called from __prepare or before __prepare
{
+ if(_timerTask != null && _proxy.__reference().getInstance().timer().cancel(_timerTask))
+ {
+ _timerTask = null; // Timer cancelled.
+ }
+
+ while(_timerTask != null)
+ {
+ try
+ {
+ _monitor.wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
//
// A CloseConnectionException indicates graceful
// server shutdown, and is therefore always repeatable
@@ -187,53 +264,85 @@ public abstract class OutgoingAsync
// An ObjectNotExistException can always be retried as
// well without violating "at-most-once".
//
- if(_mode == Ice.OperationMode.Nonmutating || _mode == Ice.OperationMode.Idempotent ||
+ if(!_sent ||
+ _mode == Ice.OperationMode.Nonmutating || _mode == Ice.OperationMode.Idempotent ||
exc instanceof Ice.CloseConnectionException || exc instanceof Ice.ObjectNotExistException)
{
- try
- {
- _cnt = ((Ice.ObjectPrxHelperBase)_proxy).__handleException(_delegate, exc, _cnt);
- __send();
- return;
- }
- catch(Ice.LocalException ex)
- {
- }
+ retry = true;
}
}
-
+ }
+
+ if(retry)
+ {
try
{
- ice_exception(exc);
+ _cnt = _proxy.__handleException(_delegate, exc, _cnt);
+ __send();
+ return;
}
- catch(java.lang.Exception ex)
+ catch(Ice.LocalException ex)
{
- warning(ex);
}
- finally
+ }
+
+ try
+ {
+ ice_exception(exc);
+ }
+ catch(java.lang.Exception ex)
+ {
+ warning(ex);
+ }
+ finally
+ {
+ synchronized(_monitor)
{
cleanup();
}
}
}
- public final boolean
- __timedOut()
+ public final void
+ __finished(LocalExceptionWrapper ex)
{
//
- // No synchronization necessary, because
- // _absoluteTimeoutMillis is declared volatile. We cannot
- // synchronize here because otherwise there might be deadlocks
- // when Ice.ConnectionI calls back on this object with this
- // function.
+ // NOTE: This is called if sendRequest/sendAsyncRequest fails with
+ // a LocalExceptionWrapper exception. It's not possible for the
+ // timer to be set at this point because the request couldn't be
+ // sent.
//
- if(_absoluteTimeoutMillis > 0)
+ assert(!_sent && _timerTask == null);
+
+ try
{
- return IceInternal.Time.currentMonotonicTimeMillis() >= _absoluteTimeoutMillis;
+ if(_mode == Ice.OperationMode.Nonmutating || _mode == Ice.OperationMode.Idempotent)
+ {
+ _cnt = _proxy.__handleExceptionWrapperRelaxed(_delegate, ex, _cnt);
+ }
+ else
+ {
+ _proxy.__handleExceptionWrapper(_delegate, ex);
+ }
+ __send();
}
- else
+ catch(Ice.LocalException exc)
{
- return false;
+ try
+ {
+ ice_exception(exc);
+ }
+ catch(java.lang.Exception exl)
+ {
+ warning(exl);
+ }
+ finally
+ {
+ synchronized(_monitor)
+ {
+ cleanup();
+ }
+ }
}
}
@@ -259,23 +368,28 @@ public abstract class OutgoingAsync
}
//
- // Can't call async via a oneway proxy.
+ // Can't call async via a batch proxy.
//
- ((Ice.ObjectPrxHelperBase)prx).__checkTwowayOnly(operation);
+ _proxy = (Ice.ObjectPrxHelperBase)prx;
+ if(_proxy.ice_isBatchOneway() || _proxy.ice_isBatchDatagram())
+ {
+ throw new Ice.FeatureNotSupportedException("can't send batch requests with AMI");
+ }
- _proxy = prx;
_delegate = null;
_cnt = 0;
_mode = mode;
+ _sent = false;
+ _response = false;
- Reference ref = ((Ice.ObjectPrxHelperBase)_proxy).__reference();
+ Reference ref = _proxy.__reference();
assert(__is == null);
__is = new BasicStream(ref.getInstance());
assert(__os == null);
__os = new BasicStream(ref.getInstance());
__os.writeBlob(IceInternal.Protocol.requestHdr);
-
+
ref.getIdentity().__write(__os);
//
@@ -308,11 +422,9 @@ public abstract class OutgoingAsync
//
// Implicit context
//
- Ice.ImplicitContextI implicitContext =
- ref.getInstance().getImplicitContext();
-
+ Ice.ImplicitContextI implicitContext = ref.getInstance().getImplicitContext();
java.util.Map prxContext = ref.getContext();
-
+
if(implicitContext == null)
{
Ice.ContextHelper.write(__os, prxContext);
@@ -322,7 +434,7 @@ public abstract class OutgoingAsync
implicitContext.write(prxContext, __os);
}
}
-
+
__os.startWriteEncaps();
}
catch(Ice.LocalException ex)
@@ -336,62 +448,56 @@ public abstract class OutgoingAsync
protected final void
__send()
{
+ //
+ // NOTE: no synchronization needed. At this point, no other threads can be calling on this object.
+ //
+
+ RequestHandler handler;
+ try
+ {
+ _delegate = _proxy.__getDelegate(true);
+ handler = _delegate.__getRequestHandler();
+ }
+ catch(Ice.LocalException ex)
+ {
+ __finished(ex);
+ return;
+ }
+
+ _sent = false;
+ _response = false;
+ handler.sendAsyncRequest(this);
+ }
+
+ protected abstract void __response(boolean ok);
+
+ private final void
+ __runTimerTask(Ice.ConnectionI connection)
+ {
synchronized(_monitor)
{
- try
- {
- while(true)
- {
- Ice.BooleanHolder comp = new Ice.BooleanHolder();
- _delegate = ((Ice.ObjectPrxHelperBase)_proxy).__getDelegate();
- Ice.ConnectionI con = _delegate.__getConnection(comp);
- if(con.timeout() >= 0)
- {
- _absoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + con.timeout();
- }
- else
- {
- _absoluteTimeoutMillis = 0;
- }
-
- try
- {
- con.sendAsyncRequest(__os, this, comp.value);
-
- //
- // Don't do anything after sendAsyncRequest() returned
- // without an exception. I such case, there will be
- // callbacks, i.e., calls to the __finished()
- // functions. Since there is no mutex protection, we
- // cannot modify state here and in such callbacks.
- //
- return;
- }
- catch(LocalExceptionWrapper ex)
- {
- ((Ice.ObjectPrxHelperBase)_proxy).__handleExceptionWrapper(_delegate, ex);
- }
- catch(Ice.LocalException ex)
- {
- _cnt = ((Ice.ObjectPrxHelperBase)_proxy).__handleException(_delegate, ex, _cnt);
- }
- }
- }
- catch(Ice.LocalException ex)
+ assert(_timerTask != null && _sent); // Can only be set once the request is sent.
+
+ if(_response) // If the response was just received, don't close the connection.
{
- __finished(ex);
+ connection = null;
}
+ _timerTask = null;
+ _monitor.notifyAll();
}
- }
- protected abstract void __response(boolean ok);
+ if(connection != null)
+ {
+ connection.exception(new Ice.TimeoutException());
+ }
+ }
private final void
warning(java.lang.Exception ex)
{
if(__os != null) // Don't print anything if cleanup() was already called.
{
- Reference ref = ((Ice.ObjectPrxHelperBase)_proxy).__reference();
+ Reference ref = _proxy.__reference();
if(ref.getInstance().initializationData().properties.getPropertyAsIntWithDefault(
"Ice.Warn.AMICallback", 1) > 0)
{
@@ -410,6 +516,8 @@ public abstract class OutgoingAsync
private final void
cleanup()
{
+ assert(_timerTask == null);
+
__is = null;
__os = null;
@@ -419,16 +527,14 @@ public abstract class OutgoingAsync
protected BasicStream __is;
protected BasicStream __os;
- private Ice.ObjectPrx _proxy;
+ private boolean _sent;
+ private boolean _response;
+ private Ice.ObjectPrxHelperBase _proxy;
private Ice._ObjectDel _delegate;
private int _cnt;
private Ice.OperationMode _mode;
- //
- // Must be volatile, because we don't want to lock the monitor
- // below in __timedOut(), to avoid deadlocks.
- //
- private volatile long _absoluteTimeoutMillis;
+ private TimerTask _timerTask;
private final java.lang.Object _monitor = new java.lang.Object();
}
diff --git a/java/src/IceInternal/OutgoingAsyncMessageCallback.java b/java/src/IceInternal/OutgoingAsyncMessageCallback.java
new file mode 100644
index 00000000000..2575dd33b38
--- /dev/null
+++ b/java/src/IceInternal/OutgoingAsyncMessageCallback.java
@@ -0,0 +1,16 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public interface OutgoingAsyncMessageCallback
+{
+ void __sent(Ice.ConnectionI connection);
+ void __finished(Ice.LocalException ex);
+}; \ No newline at end of file
diff --git a/java/src/IceInternal/OutgoingConnectionFactory.java b/java/src/IceInternal/OutgoingConnectionFactory.java
index ffec338dd83..fb3108aa472 100644
--- a/java/src/IceInternal/OutgoingConnectionFactory.java
+++ b/java/src/IceInternal/OutgoingConnectionFactory.java
@@ -11,6 +11,11 @@ package IceInternal;
public final class OutgoingConnectionFactory
{
+ interface CreateConnectionCallback
+ {
+ void setConnection(Ice.ConnectionI connection, boolean compress);
+ void setException(Ice.LocalException ex);
+ }
public synchronized void
destroy()
@@ -40,7 +45,7 @@ public final class OutgoingConnectionFactory
public void
waitUntilFinished()
{
- java.util.HashMap connections;
+ java.util.HashMap connections = null;
synchronized(this)
{
@@ -50,7 +55,7 @@ public final class OutgoingConnectionFactory
// anymore. Only then we can be sure the _connections
// contains all connections.
//
- while(!_destroyed || !_pending.isEmpty())
+ while(!_destroyed || !_pending.isEmpty() || !_pendingEndpoints.isEmpty())
{
try
{
@@ -65,17 +70,14 @@ public final class OutgoingConnectionFactory
// We want to wait until all connections are finished outside the
// thread synchronization.
//
- // For consistency with C#, we set _connections to null rather than to a
- // new empty list so that our finalizer does not try to invoke any
- // methods on member objects.
- //
- connections = _connections;
- _connections = null;
+ if(_connections != null)
+ {
+ connections = new java.util.HashMap(_connections);
+ }
}
//
- // Now we wait for until the destruction of each connection is
- // finished.
+ // Now we wait until the destruction of each connection is finished.
//
java.util.Iterator p = connections.values().iterator();
while(p.hasNext())
@@ -89,257 +91,119 @@ public final class OutgoingConnectionFactory
connection.waitUntilFinished();
}
}
+
+ synchronized(this)
+ {
+ //
+ // For consistency with C#, we set _connections to null rather than to a
+ // new empty list so that our finalizer does not try to invoke any
+ // methods on member objects.
+ //
+ _connections = null;
+ }
}
public Ice.ConnectionI
- create(EndpointI[] endpts, boolean hasMore, boolean threadPerConnection, Ice.EndpointSelectionType selType,
+ create(EndpointI[] endpts, boolean hasMore, boolean tpc, Ice.EndpointSelectionType selType,
Ice.BooleanHolder compress)
{
- class ConnectorEndpointPair
- {
- public ConnectorEndpointPair(Connector c, EndpointI e)
- {
- connector = c;
- endpoint = e;
- }
-
- public Connector connector;
- public EndpointI endpoint;
- }
-
assert(endpts.length > 0);
- java.util.ArrayList connectors = new java.util.ArrayList();
-
- DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
- synchronized(this)
+ //
+ // TODO: Remove when we no longer support SSL for JDK 1.4. We can also remove
+ // the threadPerConnection argument.
+ //
+ for(int i = 0; i < endpts.length; i++)
{
- if(_destroyed)
+ if(!tpc && endpts[i].requiresThreadPerConnection())
{
- throw new Ice.CommunicatorDestroyedException();
+ Ice.FeatureNotSupportedException ex = new Ice.FeatureNotSupportedException();
+ ex.unsupportedFeature = "endpoint requires thread-per-connection:\n" + endpts[i].toString();
+ throw ex;
}
+ }
- //
- // TODO: Remove when we no longer support SSL for JDK 1.4.
- //
- for(int i = 0; i < endpts.length; i++)
- {
- if(!threadPerConnection && endpts[i].requiresThreadPerConnection())
- {
- Ice.FeatureNotSupportedException ex = new Ice.FeatureNotSupportedException();
- ex.unsupportedFeature = "endpoint requires thread-per-connection:\n" + endpts[i].toString();
- throw ex;
- }
- }
+ //
+ // Apply the overrides.
+ //
+ java.util.List endpoints = applyOverrides(endpts);
- //
- // Reap connections for which destruction has completed.
- //
- java.util.Iterator p = _connections.values().iterator();
- while(p.hasNext())
- {
- java.util.LinkedList connectionList = (java.util.LinkedList)p.next();
-
- java.util.Iterator q = connectionList.iterator();
- while(q.hasNext())
- {
- Ice.ConnectionI con = (Ice.ConnectionI)q.next();
- if(con.isFinished())
- {
- q.remove();
- }
- }
+ //
+ // Try to find a connection to one of the given endpoints.
+ //
+ Ice.ConnectionI connection = findConnection(endpoints, tpc, compress);
+ if(connection != null)
+ {
+ return connection;
+ }
- if(connectionList.isEmpty())
- {
- p.remove();
- }
- }
+ Ice.LocalException exception = null;
- EndpointI[] endpoints = new EndpointI[endpts.length];
- System.arraycopy(endpts, 0, endpoints, 0, endpts.length);
- for(int i = 0; i < endpoints.length; i++)
- {
- //
- // Modify endpoints with overrides.
- //
- if(defaultsAndOverrides.overrideTimeout)
- {
- endpoints[i] = endpoints[i].timeout(defaultsAndOverrides.overrideTimeoutValue);
- }
+ //
+ // If we didn't find a connection with the endpoints, we create the connectors
+ // for the endpoints.
+ //
+ java.util.ArrayList connectors = new java.util.ArrayList();
+ java.util.Iterator p = endpoints.iterator();
+ while(p.hasNext())
+ {
+ EndpointI endpoint = (EndpointI)p.next();
- //
- // Create connectors for the endpoint.
- //
- java.util.ArrayList cons = endpoints[i].connectors();
+ //
+ // Create connectors for the endpoint.
+ //
+ try
+ {
+ java.util.List cons = endpoint.connectors();
assert(cons.size() > 0);
-
+
//
- // Shuffle connectors is endpoint selection type is Random.
+ // Shuffle connectors if endpoint selection type is Random.
//
if(selType == Ice.EndpointSelectionType.Random)
{
java.util.Collections.shuffle(cons);
}
-
- p = cons.iterator();
- while(p.hasNext())
- {
- connectors.add(new ConnectorEndpointPair((Connector)p.next(), endpoints[i]));
- }
-
- }
-
- //
- // Search for existing connections.
- //
- p = connectors.iterator();
- while(p.hasNext())
- {
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
-
-
- java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(cep.connector);
- if(connectionList != null)
- {
- java.util.Iterator q = connectionList.iterator();
-
- while(q.hasNext())
- {
- Ice.ConnectionI connection = (Ice.ConnectionI)q.next();
-
- //
- // Don't return connections for which destruction has
- // been initiated. The connection must also match the
- // requested thread-per-connection setting.
- //
- if(!connection.isDestroyed() && connection.threadPerConnection() == threadPerConnection)
- {
- if(defaultsAndOverrides.overrideCompress)
- {
- compress.value = defaultsAndOverrides.overrideCompressValue;
- }
- else
- {
- compress.value = cep.endpoint.compress();
- }
-
- return connection;
- }
- }
- }
- }
-
- //
- // If some other thread is currently trying to establish a
- // connection to any of our endpoints, we wait until this
- // thread is finished.
- //
- boolean searchAgain = false;
- while(!_destroyed)
- {
- boolean found = false;
- p = connectors.iterator();
- while(p.hasNext())
- {
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
- if(_pending.contains(cep.connector))
- {
- found = true;
- break;
- }
- }
- if(!found)
- {
- break;
- }
-
- searchAgain = true;
-
- try
- {
- wait();
- }
- catch(InterruptedException ex)
- {
- }
- }
-
- if(_destroyed)
- {
- throw new Ice.CommunicatorDestroyedException();
- }
-
- //
- // Search for existing connections again if we waited
- // above, as new connections might have been added in the
- // meantime.
- //
- if(searchAgain)
- {
- p = connectors.iterator();
- while(p.hasNext())
+ java.util.Iterator q = cons.iterator();
+ while(q.hasNext())
{
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
-
- java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(cep.connector);
- if(connectionList != null)
- {
- java.util.Iterator q = connectionList.iterator();
-
- while(q.hasNext())
- {
- Ice.ConnectionI connection = (Ice.ConnectionI)q.next();
-
- //
- // Don't return connections for which destruction has
- // been initiated. The connection must also match the
- // requested thread-per-connection setting.
- //
- if(!connection.isDestroyed() && connection.threadPerConnection() == threadPerConnection)
- {
- if(defaultsAndOverrides.overrideCompress)
- {
- compress.value = defaultsAndOverrides.overrideCompressValue;
- }
- else
- {
- compress.value = cep.endpoint.compress();
- }
-
- return connection;
- }
- }
- }
+ connectors.add(new ConnectorInfo((Connector)q.next(), endpoint, tpc));
}
}
-
- //
- // No connection to any of our endpoints exists yet, so we
- // will try to create one. To avoid that other threads try
- // to create connections to the same endpoints, we add our
- // endpoints to _pending.
- //
- p = connectors.iterator();
- while(p.hasNext())
+ catch(Ice.LocalException ex)
{
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
- _pending.add(cep.connector);
+ exception = ex;
+ handleException(exception, hasMore || p.hasNext());
}
}
+
+ if(connectors.isEmpty())
+ {
+ assert(exception != null);
+ throw exception;
+ }
+
+ //
+ // Try to get a connection to one of the connectors. A null result indicates that no
+ // connection was found and that we should try to establish the connection (and that
+ // the connectors were added to _pending to prevent other threads from establishing
+ // the connection).
+ //
+ connection = getConnection(connectors, null, compress);
+ if(connection != null)
+ {
+ return connection;
+ }
- Connector connector = null;
- Ice.ConnectionI connection = null;
- Ice.LocalException exception = null;
-
- java.util.Iterator p = connectors.iterator();
+ //
+ // Try to establish the connection to the connectors.
+ //
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ p = connectors.iterator();
while(p.hasNext())
{
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
- connector = cep.connector;
- EndpointI endpoint = cep.endpoint;
-
+ ConnectorInfo ci = (ConnectorInfo)p.next();
try
{
int timeout;
@@ -347,21 +211,17 @@ public final class OutgoingConnectionFactory
{
timeout = defaultsAndOverrides.overrideConnectTimeoutValue;
}
- // It is not necessary to check for overrideTimeout,
- // the endpoint has already been modified with this
- // override, if set.
else
{
- timeout = endpoint.timeout();
+ //
+ // It is not necessary to check for overrideTimeout, the endpoint has already
+ // been modified with this override, if set.
+ //
+ timeout = ci.endpoint.timeout();
}
- Transceiver transceiver = connector.connect(timeout);
- assert(transceiver != null);
-
- connection =
- new Ice.ConnectionI(_instance, transceiver, endpoint.compress(false), null, threadPerConnection);
- connection.start();
- connection.validate();
+ connection = createConnection(ci.connector.connect(timeout), ci);
+ connection.start(null);
if(defaultsAndOverrides.overrideCompress)
{
@@ -369,86 +229,79 @@ public final class OutgoingConnectionFactory
}
else
{
- compress.value = endpoint.compress();
+ compress.value = ci.endpoint.compress();
}
+
break;
}
- catch(Ice.LocalException ex)
+ catch(Ice.CommunicatorDestroyedException ex)
{
exception = ex;
-
- //
- // If a connection object was constructed, then validate()
- // must have raised the exception.
- //
- if(connection != null)
- {
- connection.waitUntilFinished(); // We must call waitUntilFinished() for cleanup.
- connection = null;
- }
+ handleException(exception, ci, connection, hasMore || p.hasNext());
+ connection = null;
+ break; // No need to continue
}
-
- TraceLevels traceLevels = _instance.traceLevels();
- if(traceLevels.retry >= 2)
+ catch(Ice.LocalException ex)
{
- StringBuffer s = new StringBuffer();
- s.append("connection to endpoint failed");
- if(hasMore || p.hasNext())
- {
- s.append(", trying next endpoint\n");
- }
- else
- {
- s.append(" and no more endpoints to try\n");
- }
- s.append(exception.toString());
- _instance.initializationData().logger.trace(traceLevels.retryCat, s.toString());
+ exception = ex;
+ handleException(exception, ci, connection, hasMore || p.hasNext());
+ connection = null;
}
}
-
- synchronized(this)
+
+ //
+ // Finish creating the connection (this removes the connectors from the _pending
+ // list and notifies any waiting threads).
+ //
+ finishGetConnection(connectors, null, connection);
+
+ if(connection == null)
{
- //
- // Signal other threads that we are done with trying to
- // establish connections to our endpoints.
- //
- p = connectors.iterator();
- while(p.hasNext())
- {
- ConnectorEndpointPair cep = (ConnectorEndpointPair)p.next();
- _pending.remove(cep.connector);
- }
- notifyAll();
-
- if(connection == null)
+ assert(exception != null);
+ throw exception;
+ }
+
+ return connection;
+ }
+
+ public void
+ create(EndpointI[] endpts, boolean hasMore, boolean tpc, Ice.EndpointSelectionType selType,
+ CreateConnectionCallback callback)
+ {
+ assert(endpts.length > 0);
+
+ //
+ // TODO: Remove when we no longer support SSL for JDK 1.4. We can also remove
+ // the threadPerConnection argument.
+ //
+ for(int i = 0; i < endpts.length; i++)
+ {
+ if(!tpc && endpts[i].requiresThreadPerConnection())
{
- assert(exception != null);
- throw exception;
+ Ice.FeatureNotSupportedException ex = new Ice.FeatureNotSupportedException();
+ ex.unsupportedFeature = "endpoint requires thread-per-connection:\n" + endpts[i].toString();
+ throw ex;
}
- else
- {
- java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(connector);
- if(connectionList == null)
- {
- connectionList = new java.util.LinkedList();
- _connections.put(connector, connectionList);
- }
- connectionList.add(connection);
+ }
- if(_destroyed)
- {
- connection.destroy(Ice.ConnectionI.CommunicatorDestroyed);
- throw new Ice.CommunicatorDestroyedException();
- }
- else
- {
- connection.activate();
- }
- }
+ //
+ // Apply the overrides.
+ //
+ java.util.List endpoints = applyOverrides(endpts);
+
+ //
+ // Try to find a connection to one of the given endpoints.
+ //
+ Ice.BooleanHolder compress = new Ice.BooleanHolder();
+ Ice.ConnectionI connection = findConnection(endpoints, tpc, compress);
+ if(connection != null)
+ {
+ callback.setConnection(connection, compress.value);
+ return;
}
-
- assert(connection != null);
- return connection;
+
+ ConnectCallback cb = new ConnectCallback(this, endpoints, hasMore, callback, selType, tpc);
+ cb.getConnection();
}
public synchronized void
@@ -607,8 +460,740 @@ public final class OutgoingConnectionFactory
super.finalize();
}
+ private java.util.List
+ applyOverrides(EndpointI[] endpts)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ java.util.ArrayList endpoints = new java.util.ArrayList();
+ for(int i = 0; i < endpts.length; i++)
+ {
+ //
+ // Modify endpoints with overrides.
+ //
+ if(defaultsAndOverrides.overrideTimeout)
+ {
+ endpoints.add(endpts[i].timeout(defaultsAndOverrides.overrideTimeoutValue));
+ }
+ else
+ {
+ endpoints.add(endpts[i]);
+ }
+ }
+
+ return endpoints;
+ }
+
+ synchronized private Ice.ConnectionI
+ findConnection(java.util.List endpoints, boolean tpc, Ice.BooleanHolder compress)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ assert(!endpoints.isEmpty());
+
+ java.util.Iterator p = endpoints.iterator();
+ while(p.hasNext())
+ {
+ EndpointI endpoint = (EndpointI)p.next();
+ java.util.LinkedList connectionList = (java.util.LinkedList)_connectionsByEndpoint.get(endpoint);
+ if(connectionList == null)
+ {
+ continue;
+ }
+
+ java.util.Iterator q = connectionList.iterator();
+ while(q.hasNext())
+ {
+ Ice.ConnectionI connection = (Ice.ConnectionI)q.next();
+ if(connection.isActiveOrHolding() &&
+ connection.threadPerConnection() == tpc) // Don't return destroyed or un-validated connections
+ {
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress.value = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress.value = endpoint.compress();
+ }
+ return connection;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //
+ // Must be called while synchronized.
+ //
+ private Ice.ConnectionI
+ findConnection(java.util.List connectors, Ice.BooleanHolder compress)
+ {
+ DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
+ java.util.Iterator p = connectors.iterator();
+ while(p.hasNext())
+ {
+ ConnectorInfo ci = (ConnectorInfo)p.next();
+ java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(ci);
+ if(connectionList == null)
+ {
+ continue;
+ }
+
+ java.util.Iterator q = connectionList.iterator();
+ while(q.hasNext())
+ {
+ Ice.ConnectionI connection = (Ice.ConnectionI)q.next();
+ if(connection.isActiveOrHolding()) // Don't return destroyed or un-validated connections
+ {
+ if(connection.endpoint().equals(ci.endpoint))
+ {
+ java.util.List conList = (java.util.LinkedList)_connectionsByEndpoint.get(ci.endpoint);
+ if(conList == null)
+ {
+ conList = new java.util.LinkedList();
+ _connectionsByEndpoint.put(ci.endpoint, conList);
+ }
+ conList.add(connection);
+ }
+
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress.value = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress.value = ci.endpoint.compress();
+ }
+ return connection;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ synchronized private void
+ addPendingEndpoints(java.util.List endpoints)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+ _pendingEndpoints.addAll(endpoints);
+ }
+
+ synchronized private void
+ removePendingEndpoints(java.util.List endpoints)
+ {
+ java.util.Iterator p = endpoints.iterator();
+ while(p.hasNext())
+ {
+ _pendingEndpoints.remove(p.next());
+ }
+
+ if(_destroyed)
+ {
+ notifyAll();
+ }
+ }
+
+ private Ice.ConnectionI
+ getConnection(java.util.List connectors, ConnectCallback cb, Ice.BooleanHolder compress)
+ {
+ synchronized(this)
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ //
+ // Reap connections for which destruction has completed.
+ //
+ java.util.Iterator p = _connections.values().iterator();
+ while(p.hasNext())
+ {
+ java.util.LinkedList connectionList = (java.util.LinkedList)p.next();
+ java.util.Iterator q = connectionList.iterator();
+ while(q.hasNext())
+ {
+ Ice.ConnectionI con = (Ice.ConnectionI)q.next();
+ if(con.isFinished())
+ {
+ q.remove();
+ }
+ }
+
+ if(connectionList.isEmpty())
+ {
+ p.remove();
+ }
+ }
+
+ p = _connectionsByEndpoint.values().iterator();
+ while(p.hasNext())
+ {
+ java.util.LinkedList connectionList = (java.util.LinkedList)p.next();
+ java.util.Iterator q = connectionList.iterator();
+ while(q.hasNext())
+ {
+ Ice.ConnectionI con = (Ice.ConnectionI)q.next();
+ if(con.isFinished())
+ {
+ q.remove();
+ }
+ }
+
+ if(connectionList.isEmpty())
+ {
+ p.remove();
+ }
+ }
+
+ //
+ // Try to get the connection. We may need to wait for other threads to
+ // finish if one of them is currently establishing a connection to one
+ // of our connectors.
+ //
+ while(!_destroyed)
+ {
+ //
+ // Search for a matching connection. If we find one, we're done.
+ //
+ Ice.ConnectionI connection = findConnection(connectors, compress);
+ if(connection != null)
+ {
+ if(cb != null)
+ {
+ //
+ // This might not be the first getConnection call for the callback. We need
+ // to ensure that the callback isn't registered with any other pending
+ // connectors since we just found a connection and therefore don't need to
+ // wait anymore for other pending connectors.
+ //
+ p = connectors.iterator();
+ while(p.hasNext())
+ {
+ java.util.Set cbs = (java.util.Set)_pending.get(p.next());
+ if(cbs != null)
+ {
+ cbs.remove(cb);
+ }
+ }
+ }
+ return connection;
+ }
+
+ //
+ // Determine whether another thread is currently attempting to connect to one of our endpoints;
+ // if so we wait until it's done.
+ //
+ p = connectors.iterator();
+ boolean found = false;
+ while(p.hasNext())
+ {
+ java.util.Set cbs = (java.util.Set)_pending.get(p.next());
+ if(cbs != null)
+ {
+ found = true;
+ if(cb != null)
+ {
+ cbs.add(cb); // Add the callback to each pending connector.
+ }
+ }
+ }
+
+ if(!found)
+ {
+ //
+ // If no thread is currently establishing a connection to one of our connectors,
+ // we get out of this loop and start the connection establishment to one of the
+ // given connectors.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // If a callback is not specified we wait until another thread notifies us about a
+ // change to the pending list. Otherwise, if a callback is provided we're done:
+ // when the pending list changes the callback will be notified and will try to
+ // get the connection again.
+ //
+ if(cb == null)
+ {
+ try
+ {
+ wait();
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ //
+ // No connection to any of our endpoints exists yet; we add the given connectors to
+ // the _pending set to indicate that we're attempting connection establishment to
+ // these connectors.
+ //
+ p = connectors.iterator();
+ while(p.hasNext())
+ {
+ _pending.put(p.next(), new java.util.HashSet());
+ }
+ }
+
+ //
+ // At this point, we're responsible for establishing the connection to one of
+ // the given connectors. If it's a non-blocking connect, calling nextConnector
+ // will start the connection establishment. Otherwise, we return null to get
+ // the caller to establish the connection.
+ //
+ if(cb != null)
+ {
+ cb.nextConnector();
+ }
+
+ return null;
+ }
+
+ private synchronized Ice.ConnectionI
+ createConnection(Transceiver transceiver, ConnectorInfo ci)
+ {
+ assert(_pending.containsKey(ci) && transceiver != null);
+
+ //
+ // Create and add the connection to the connection map. Adding the connection to the map
+ // is necessary to support the interruption of the connection initialization and validation
+ // in case the communicator is destroyed.
+ //
+ try
+ {
+ if(_destroyed)
+ {
+ throw new Ice.CommunicatorDestroyedException();
+ }
+
+ Ice.ConnectionI connection = new Ice.ConnectionI(_instance, transceiver, ci.endpoint.compress(false),
+ null, ci.threadPerConnection);
+
+ java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(ci);
+ if(connectionList == null)
+ {
+ connectionList = new java.util.LinkedList();
+ _connections.put(ci, connectionList);
+ }
+ connectionList.add(connection);
+ return connection;
+ }
+ catch(Ice.LocalException ex)
+ {
+ try
+ {
+ transceiver.close();
+ }
+ catch(Ice.LocalException exc)
+ {
+ // Ignore
+ }
+ throw ex;
+ }
+ }
+
+ private void
+ finishGetConnection(java.util.List connectors, ConnectCallback cb, Ice.ConnectionI connection)
+ {
+ java.util.ArrayList callbacks = new java.util.ArrayList();
+
+ synchronized(this)
+ {
+ //
+ // We're done trying to connect to the given connectors so we remove the
+ // connectors from the pending list and notify waiting threads. We also
+ // notify the pending connect callbacks (outside the synchronization).
+ //
+
+ java.util.Iterator p = connectors.iterator();
+ while(p.hasNext())
+ {
+ callbacks.addAll((java.util.Set)_pending.remove(p.next()));
+ }
+ notifyAll();
+
+ //
+ // If the connect attempt succeeded and the communicator is not destroyed,
+ // activate the connection!
+ //
+ if(connection != null && !_destroyed)
+ {
+ connection.activate();
+ }
+ }
+
+ //
+ // Notify any waiting callbacks.
+ //
+ java.util.Iterator p = callbacks.iterator();
+ while(p.hasNext())
+ {
+ ((ConnectCallback)p.next()).getConnection();
+ }
+ }
+
+ private void
+ handleException(Ice.LocalException ex, ConnectorInfo ci, Ice.ConnectionI connection, boolean hasMore)
+ {
+ TraceLevels traceLevels = _instance.traceLevels();
+ if(traceLevels.retry >= 2)
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("connection to endpoint failed");
+ if(ex instanceof Ice.CommunicatorDestroyedException)
+ {
+ s.append("\n");
+ }
+ else
+ {
+ if(hasMore)
+ {
+ s.append(", trying next endpoint\n");
+ }
+ else
+ {
+ s.append(" and no more endpoints to try\n");
+ }
+ }
+ s.append(ex.toString());
+ _instance.initializationData().logger.trace(traceLevels.retryCat, s.toString());
+ }
+
+ if(connection != null && connection.isFinished())
+ {
+ //
+ // If the connection is finished, we remove it right away instead of
+ // waiting for the reaping.
+ //
+ // NOTE: it's possible for the connection to not be finished yet. That's
+ // for instance the case when using thread per connection and if it's the
+ // thread which is calling back the outgoing connection factory to notify
+ // it of the failure.
+ //
+ synchronized(this)
+ {
+ java.util.LinkedList connectionList = (java.util.LinkedList)_connections.get(ci);
+ if(connectionList != null) // It might have already been reaped!
+ {
+ connectionList.remove(connection);
+ if(connectionList.isEmpty())
+ {
+ _connections.remove(ci);
+ }
+ }
+ }
+ }
+ }
+
+ private void
+ handleException(Ice.LocalException ex, boolean hasMore)
+ {
+ TraceLevels traceLevels = _instance.traceLevels();
+ if(traceLevels.retry >= 2)
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("couldn't resolve endpoint host");
+ if(ex instanceof Ice.CommunicatorDestroyedException)
+ {
+ s.append("\n");
+ }
+ else
+ {
+ if(hasMore)
+ {
+ s.append(", trying next endpoint\n");
+ }
+ else
+ {
+ s.append(" and no more endpoints to try\n");
+ }
+ }
+ s.append(ex.toString());
+ _instance.initializationData().logger.trace(traceLevels.retryCat, s.toString());
+ }
+ }
+
+ private static class ConnectorInfo
+ {
+ public ConnectorInfo(Connector c, EndpointI e, boolean t)
+ {
+ connector = c;
+ endpoint = e;
+ threadPerConnection = t;
+ }
+
+ public boolean
+ equals(Object obj)
+ {
+ ConnectorInfo r = (ConnectorInfo)obj;
+ if(threadPerConnection != r.threadPerConnection)
+ {
+ return false;
+ }
+ return connector.equals(r.connector);
+ }
+
+ public int
+ hashCode()
+ {
+ return 2 * connector.hashCode() + (threadPerConnection ? 0 : 1);
+ }
+
+ public Connector connector;
+ public EndpointI endpoint;
+ public boolean threadPerConnection;
+ }
+
+ private static class ConnectCallback implements Ice.ConnectionI.StartCallback, EndpointI_connectors,
+ ThreadPoolWorkItem
+ {
+ ConnectCallback(OutgoingConnectionFactory f, java.util.List endpoints, boolean more,
+ CreateConnectionCallback cb, Ice.EndpointSelectionType selType, boolean threadPerConnection)
+ {
+ _factory = f;
+ _endpoints = endpoints;
+ _hasMore = more;
+ _callback = cb;
+ _selType = selType;
+ _threadPerConnection = threadPerConnection;
+ _endpointsIter = _endpoints.iterator();
+ }
+
+ //
+ // Methods from ConnectionI.StartCallback
+ //
+ public synchronized void
+ connectionStartCompleted(Ice.ConnectionI connection)
+ {
+ assert(_exception == null && connection == _connection);
+
+ boolean compress;
+ DefaultsAndOverrides defaultsAndOverrides = _factory._instance.defaultsAndOverrides();
+ if(defaultsAndOverrides.overrideCompress)
+ {
+ compress = defaultsAndOverrides.overrideCompressValue;
+ }
+ else
+ {
+ compress = _current.endpoint.compress();
+ }
+
+ _factory.finishGetConnection(_connectors, this, connection);
+ _factory.removePendingEndpoints(_endpoints);
+ _callback.setConnection(connection, compress);
+ }
+
+ public synchronized void
+ connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex)
+ {
+ assert(_exception == null && connection == _connection);
+
+ _exception = ex;
+ handleException();
+ }
+
+ //
+ // Methods from EndpointI_connectors
+ //
+ public void
+ connectors(java.util.List cons)
+ {
+ //
+ // Shuffle connectors if endpoint selection type is Random.
+ //
+ if(_selType == Ice.EndpointSelectionType.Random)
+ {
+ java.util.Collections.shuffle(cons);
+ }
+
+ java.util.Iterator q = cons.iterator();
+ while(q.hasNext())
+ {
+ _connectors.add(new ConnectorInfo((Connector)q.next(), _currentEndpoint, _threadPerConnection));
+ }
+
+ if(_endpointsIter.hasNext())
+ {
+ _currentEndpoint = (EndpointI)_endpointsIter.next();
+ _currentEndpoint.connectors_async(this);
+ }
+ else
+ {
+ assert(!_connectors.isEmpty());
+
+ //
+ // We now have all the connectors for the given endpoints. We can try to obtain the
+ // connection.
+ //
+ _iter = _connectors.iterator();
+ getConnection();
+ }
+ }
+
+ public void
+ exception(Ice.LocalException ex)
+ {
+ _factory.handleException(ex, _hasMore || _endpointsIter.hasNext());
+ if(_endpointsIter.hasNext())
+ {
+ _currentEndpoint = (EndpointI)_endpointsIter.next();
+ _currentEndpoint.connectors_async(this);
+ }
+ else if(!_connectors.isEmpty())
+ {
+ //
+ // We now have all the connectors for the given endpoints. We can try to obtain the
+ // connection.
+ //
+ _iter = _connectors.iterator();
+ getConnection();
+ }
+ else
+ {
+ _exception = ex;
+ _factory._instance.clientThreadPool().execute(this);
+ }
+ }
+
+ //
+ // Methods from ThreadPoolWorkItem
+ //
+ public void
+ execute(ThreadPool threadPool)
+ {
+ threadPool.promoteFollower();
+ assert(_exception != null);
+ _factory.removePendingEndpoints(_endpoints);
+ _callback.setException(_exception);
+ }
+
+ void
+ getConnection()
+ {
+ //
+ // First, get the connectors for all the endpoints.
+ //
+ if(_endpointsIter.hasNext())
+ {
+ try
+ {
+ _factory.addPendingEndpoints(_endpoints);
+ _currentEndpoint = (EndpointI)_endpointsIter.next();
+ _currentEndpoint.connectors_async(this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _callback.setException(ex);
+ }
+ return;
+ }
+
+ try
+ {
+ Ice.BooleanHolder compress = new Ice.BooleanHolder();
+ Ice.ConnectionI connection = _factory.getConnection(_connectors, this, compress);
+ if(connection == null)
+ {
+ //
+ // A null return value from getConnection indicates that the connection
+ // is being established and that everthing has been done to ensure that
+ // the callback will be notified when the connection establishment is
+ // done.
+ //
+ return;
+ }
+
+ _factory.removePendingEndpoints(_endpoints);
+ _callback.setConnection(connection, compress.value);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _exception = ex;
+ _factory._instance.clientThreadPool().execute(this);
+ }
+ }
+
+ void
+ nextConnector()
+ {
+ _current = (ConnectorInfo)_iter.next();
+ try
+ {
+ _exception = null;
+ _connection = _factory.createConnection(_current.connector.connect(0), _current);
+ _connection.start(this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ _exception = ex;
+ handleException();
+ }
+ }
+
+ private void
+ handleException()
+ {
+ assert(_current != null && _exception != null);
+
+ _factory.handleException(_exception, _current, _connection, _hasMore || _iter.hasNext());
+ if(_exception instanceof Ice.CommunicatorDestroyedException) // No need to continue.
+ {
+ _factory.finishGetConnection(_connectors, this, null);
+ _factory.removePendingEndpoints(_endpoints);
+ _callback.setException(_exception);
+ }
+ else if(_iter.hasNext()) // Try the next connector.
+ {
+ nextConnector();
+ }
+ else
+ {
+ _factory.finishGetConnection(_connectors, this, null);
+ _factory.removePendingEndpoints(_endpoints);
+ _callback.setException(_exception);
+ }
+ }
+
+ private final OutgoingConnectionFactory _factory;
+ private final boolean _hasMore;
+ private final CreateConnectionCallback _callback;
+ private final java.util.List _endpoints;
+ private final Ice.EndpointSelectionType _selType;
+ private final boolean _threadPerConnection;
+ private java.util.Iterator _endpointsIter;
+ private EndpointI _currentEndpoint;
+ private java.util.List _connectors = new java.util.ArrayList();
+ private java.util.Iterator _iter;
+ private ConnectorInfo _current;
+ private Ice.LocalException _exception;
+ private Ice.ConnectionI _connection;
+ }
+
private final Instance _instance;
private boolean _destroyed;
+
private java.util.HashMap _connections = new java.util.HashMap();
- private java.util.HashSet _pending = new java.util.HashSet();
+ private java.util.HashMap _pending = new java.util.HashMap();
+
+ private java.util.HashMap _connectionsByEndpoint = new java.util.HashMap();
+ private java.util.LinkedList _pendingEndpoints = new java.util.LinkedList();
}
diff --git a/java/src/IceInternal/OutgoingMessageCallback.java b/java/src/IceInternal/OutgoingMessageCallback.java
new file mode 100644
index 00000000000..53c7a744c12
--- /dev/null
+++ b/java/src/IceInternal/OutgoingMessageCallback.java
@@ -0,0 +1,16 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public interface OutgoingMessageCallback
+{
+ void sent(boolean notify);
+ void finished(Ice.LocalException ex);
+}
diff --git a/java/src/IceInternal/PropertyNames.java b/java/src/IceInternal/PropertyNames.java
index 1f9fc892260..49e5b9e5673 100644
--- a/java/src/IceInternal/PropertyNames.java
+++ b/java/src/IceInternal/PropertyNames.java
@@ -7,7 +7,7 @@
//
// **********************************************************************
//
-// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Nov 22 20:40:28 2007
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Mon Nov 26 11:29:02 2007
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
diff --git a/java/src/IceInternal/ProtocolPluginFacade.java b/java/src/IceInternal/ProtocolPluginFacade.java
index 52b92d5f57d..8423491d10f 100644
--- a/java/src/IceInternal/ProtocolPluginFacade.java
+++ b/java/src/IceInternal/ProtocolPluginFacade.java
@@ -18,6 +18,11 @@ public interface ProtocolPluginFacade
Ice.Communicator getCommunicator();
//
+ // Get the endpoint host resolver.
+ //
+ IceInternal.EndpointHostResolver getEndpointHostResolver();
+
+ //
// Get the default hostname to be used in endpoints.
//
String getDefaultHost();
@@ -32,4 +37,9 @@ public interface ProtocolPluginFacade
// Register an EndpointFactory.
//
void addEndpointFactory(EndpointFactory factory);
+
+ //
+ // Get an EndpointFactory.
+ //
+ EndpointFactory getEndpointFactory(short type);
}
diff --git a/java/src/IceInternal/ProtocolPluginFacadeI.java b/java/src/IceInternal/ProtocolPluginFacadeI.java
index 53ae82a59d1..1dacd623499 100644
--- a/java/src/IceInternal/ProtocolPluginFacadeI.java
+++ b/java/src/IceInternal/ProtocolPluginFacadeI.java
@@ -29,6 +29,15 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade
}
//
+ // Get the endpoint host resolver.
+ //
+ public EndpointHostResolver
+ getEndpointHostResolver()
+ {
+ return _instance.endpointHostResolver();
+ }
+
+ //
// Get the default hostname to be used in endpoints.
//
public String
@@ -61,6 +70,15 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade
_instance.endpointFactoryManager().add(factory);
}
+ //
+ // Register an EndpointFactory.
+ //
+ public EndpointFactory
+ getEndpointFactory(short type)
+ {
+ return _instance.endpointFactoryManager().get(type);
+ }
+
private Instance _instance;
private Ice.Communicator _communicator;
}
diff --git a/java/src/IceInternal/Reference.java b/java/src/IceInternal/Reference.java
index 59ccbee7bec..5d486b41af3 100644
--- a/java/src/IceInternal/Reference.java
+++ b/java/src/IceInternal/Reference.java
@@ -18,6 +18,12 @@ public abstract class Reference implements Cloneable
public final static int ModeBatchDatagram = 4;
public final static int ModeLast = ModeBatchDatagram;
+ public interface GetConnectionCallback
+ {
+ void setConnection(Ice.ConnectionI connection, boolean compress);
+ void setException(Ice.LocalException ex);
+ }
+
public final int
getMode()
{
@@ -325,6 +331,7 @@ public abstract class Reference implements Cloneable
}
public abstract Ice.ConnectionI getConnection(Ice.BooleanHolder comp);
+ public abstract void getConnection(GetConnectionCallback callback);
public boolean
equals(java.lang.Object obj)
diff --git a/java/src/IceInternal/ReferenceFactory.java b/java/src/IceInternal/ReferenceFactory.java
index 784c45c4aa3..37f24e64c56 100644
--- a/java/src/IceInternal/ReferenceFactory.java
+++ b/java/src/IceInternal/ReferenceFactory.java
@@ -100,7 +100,7 @@ public final class ReferenceFactory
//
// Create new reference
//
- FixedReference ref = new FixedReference(_instance, _communicator, ident, context, facet, mode,
+ FixedReference ref = new FixedReference(_instance, _communicator, ident, context, facet, mode,
fixedConnections);
return updateCache(ref);
}
diff --git a/java/src/IceInternal/RequestHandler.java b/java/src/IceInternal/RequestHandler.java
new file mode 100644
index 00000000000..49df9e6bc8d
--- /dev/null
+++ b/java/src/IceInternal/RequestHandler.java
@@ -0,0 +1,34 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public interface RequestHandler
+{
+ void prepareBatchRequest(BasicStream out);
+ void finishBatchRequest(BasicStream out);
+ void abortBatchRequest();
+
+ Ice.ConnectionI sendRequest(Outgoing out)
+ throws LocalExceptionWrapper;
+
+ void sendAsyncRequest(OutgoingAsync out);
+
+ boolean flushBatchRequests(BatchOutgoing out);
+ void flushAsyncBatchRequests(BatchOutgoingAsync out);
+
+ Reference getReference();
+
+ Ice.ConnectionI getConnection(boolean wait);
+
+ Outgoing getOutgoing(String operation, Ice.OperationMode mode, java.util.Map context)
+ throws LocalExceptionWrapper;
+
+ void reclaimOutgoing(Outgoing out);
+}
diff --git a/java/src/IceInternal/RoutableReference.java b/java/src/IceInternal/RoutableReference.java
index f04c30eb86c..213453b71cd 100644
--- a/java/src/IceInternal/RoutableReference.java
+++ b/java/src/IceInternal/RoutableReference.java
@@ -17,20 +17,6 @@ public abstract class RoutableReference extends Reference
return _routerInfo;
}
- public final EndpointI[]
- getRoutedEndpoints()
- {
- if(_routerInfo != null)
- {
- //
- // If we route, we send everything to the router's client
- // proxy endpoints.
- //
- return _routerInfo.getClientEndpoints();
- }
- return new EndpointI[0];
- }
-
public final boolean
getSecure()
{
@@ -252,6 +238,7 @@ public abstract class RoutableReference extends Reference
{
return false;
}
+
return _routerInfo == null ? rhs._routerInfo == null : _routerInfo.equals(rhs._routerInfo);
}
@@ -304,8 +291,8 @@ public abstract class RoutableReference extends Reference
}
}
- protected Ice.ConnectionI
- createConnection(EndpointI[] allEndpoints, Ice.BooleanHolder compress)
+ private EndpointI[]
+ filterEndpoints(EndpointI[] allEndpoints)
{
java.util.ArrayList endpoints = new java.util.ArrayList();
@@ -413,25 +400,30 @@ public abstract class RoutableReference extends Reference
java.util.Collections.sort(endpoints, _preferNonSecureEndpointComparator);
}
- if(endpoints.size() == 0)
+ return (EndpointI[])endpoints.toArray(new EndpointI[endpoints.size()]);
+ }
+
+ protected Ice.ConnectionI
+ createConnection(EndpointI[] allEndpoints, Ice.BooleanHolder compress)
+ {
+ EndpointI[] endpoints = filterEndpoints(allEndpoints);
+ if(endpoints.length == 0)
{
- Ice.NoEndpointException ex = new Ice.NoEndpointException();
- ex.proxy = toString();
- throw ex;
+ throw new Ice.NoEndpointException(toString());
}
//
// Finally, create the connection.
//
OutgoingConnectionFactory factory = getInstance().outgoingConnectionFactory();
- if(getCacheConnection() || endpoints.size() == 1)
+ Ice.ConnectionI connection = null;
+ if(getCacheConnection() || endpoints.length == 1)
{
//
// Get an existing connection or create one if there's no
// existing connection to one of the given endpoints.
//
- return factory.create((EndpointI[])endpoints.toArray(
- new EndpointI[endpoints.size()]), false, _threadPerConnection, getEndpointSelection(), compress);
+ connection = factory.create(endpoints, false, _threadPerConnection, getEndpointSelection(), compress);
}
else
{
@@ -444,16 +436,16 @@ public abstract class RoutableReference extends Reference
//
Ice.LocalException exception = null;
- EndpointI[] endpoint = new EndpointI[1];
-
- java.util.Iterator i = endpoints.iterator();
- while(i.hasNext())
+ EndpointI[] endpoint = new EndpointI[1];
+ for(int i = 0; i < endpoints.length; ++i)
{
try
{
- endpoint[0] = (EndpointI)i.next();
- return factory.create(endpoint, i.hasNext(), _threadPerConnection, getEndpointSelection(),
- compress);
+ endpoint[0] = endpoints[i];
+ final boolean more = i != endpoints.length - 1;
+ connection = factory.create(endpoint, more, _threadPerConnection, getEndpointSelection(),
+ compress);
+ break;
}
catch(Ice.LocalException ex)
{
@@ -461,8 +453,123 @@ public abstract class RoutableReference extends Reference
}
}
- assert(exception != null);
- throw exception;
+ if(connection == null)
+ {
+ assert(exception != null);
+ throw exception;
+ }
+ }
+
+ assert(connection != null);
+
+ //
+ // If we have a router, set the object adapter for this router
+ // (if any) to the new connection, so that callbacks from the
+ // router can be received over this new connection.
+ //
+ if(_routerInfo != null)
+ {
+ connection.setAdapter(_routerInfo.getAdapter());
+ }
+
+ return connection;
+ }
+
+ protected void
+ createConnection(EndpointI[] allEndpoints, final GetConnectionCallback callback)
+ {
+ final EndpointI[] endpoints = filterEndpoints(allEndpoints);
+ if(endpoints.length == 0)
+ {
+ callback.setException(new Ice.NoEndpointException(toString()));
+ return;
+ }
+
+ //
+ // Finally, create the connection.
+ //
+ final OutgoingConnectionFactory factory = getInstance().outgoingConnectionFactory();
+ if(getCacheConnection() || endpoints.length == 1)
+ {
+ //
+ // Get an existing connection or create one if there's no
+ // existing connection to one of the given endpoints.
+ //
+ factory.create(endpoints, false, _threadPerConnection, getEndpointSelection(),
+ new OutgoingConnectionFactory.CreateConnectionCallback()
+ {
+ public void
+ setConnection(Ice.ConnectionI connection, boolean compress)
+ {
+ //
+ // If we have a router, set the object adapter for this router
+ // (if any) to the new connection, so that callbacks from the
+ // router can be received over this new connection.
+ //
+ if(_routerInfo != null)
+ {
+ connection.setAdapter(_routerInfo.getAdapter());
+ }
+ callback.setConnection(connection, compress);
+ }
+
+ public void
+ setException(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
+ }
+ else
+ {
+ //
+ // Go through the list of endpoints and try to create the
+ // connection until it succeeds. This is different from just
+ // calling create() with the given endpoints since this might
+ // create a new connection even if there's an existing
+ // connection for one of the endpoints.
+ //
+
+ factory.create(new EndpointI[]{ endpoints[0] }, true, _threadPerConnection, getEndpointSelection(),
+ new OutgoingConnectionFactory.CreateConnectionCallback()
+ {
+ public void
+ setConnection(Ice.ConnectionI connection, boolean compress)
+ {
+ //
+ // If we have a router, set the object adapter for this router
+ // (if any) to the new connection, so that callbacks from the
+ // router can be received over this new connection.
+ //
+ if(_routerInfo != null)
+ {
+ connection.setAdapter(_routerInfo.getAdapter());
+ }
+ callback.setConnection(connection, compress);
+ }
+
+ public void
+ setException(final Ice.LocalException ex)
+ {
+ if(_exception == null)
+ {
+ _exception = ex;
+ }
+
+ if(++_i == endpoints.length)
+ {
+ callback.setException(_exception);
+ return;
+ }
+
+ final boolean more = _i != endpoints.length - 1;
+ final EndpointI[] endpoint = new EndpointI[]{ endpoints[_i] };
+ factory.create(endpoint, more, _threadPerConnection, getEndpointSelection(), this);
+ }
+
+ private int _i = 0;
+ private Ice.LocalException _exception = null;
+ });
}
}
diff --git a/java/src/IceInternal/RouterInfo.java b/java/src/IceInternal/RouterInfo.java
index d9e6c6f6839..cf4180a7a0f 100644
--- a/java/src/IceInternal/RouterInfo.java
+++ b/java/src/IceInternal/RouterInfo.java
@@ -11,6 +11,18 @@ package IceInternal;
public final class RouterInfo
{
+ interface GetClientEndpointsCallback
+ {
+ void setEndpoints(EndpointI[] endpoints);
+ void setException(Ice.LocalException ex);
+ }
+
+ interface AddProxyCallback
+ {
+ void addedProxy();
+ void setException(Ice.LocalException ex);
+ }
+
RouterInfo(Ice.RouterPrx router)
{
_router = router;
@@ -52,12 +64,136 @@ public final class RouterInfo
return _router;
}
- public synchronized EndpointI[]
+ public EndpointI[]
getClientEndpoints()
{
- if(_clientEndpoints == null) // Lazy initialization.
+ synchronized(this)
+ {
+ if(_clientEndpoints != null) // Lazy initialization.
+ {
+ return _clientEndpoints;
+ }
+ }
+
+ return setClientEndpoints(_router.getClientProxy());
+ }
+
+ public void
+ getClientEndpoints(final GetClientEndpointsCallback callback)
+ {
+ EndpointI[] clientEndpoints = null;
+ synchronized(this)
+ {
+ clientEndpoints = _clientEndpoints;
+ }
+
+ if(clientEndpoints != null)
+ {
+ callback.setEndpoints(clientEndpoints);
+ return;
+ }
+
+ final RouterInfo self = this;
+ _router.getClientProxy_async(new Ice.AMI_Router_getClientProxy()
+ {
+ public void
+ ice_response(Ice.ObjectPrx clientProxy)
+ {
+ callback.setEndpoints(setClientEndpoints(clientProxy));
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ });
+ }
+
+ public EndpointI[]
+ getServerEndpoints()
+ {
+ synchronized(this)
+ {
+ if(_serverEndpoints != null) // Lazy initialization.
+ {
+ return _serverEndpoints;
+ }
+ }
+
+ return setServerEndpoints(_router.getServerProxy());
+ }
+
+ public void
+ addProxy(Ice.ObjectPrx proxy)
+ {
+ assert(proxy != null);
+ synchronized(this)
+ {
+ if(_identities.contains(proxy.ice_getIdentity()))
+ {
+ //
+ // Only add the proxy to the router if it's not already in our local map.
+ //
+ return;
+ }
+ }
+
+ addAndEvictProxies(proxy, _router.addProxies(new Ice.ObjectPrx[] { proxy }));
+ }
+
+ public boolean
+ addProxy(final Ice.ObjectPrx proxy, final AddProxyCallback callback)
+ {
+ assert(proxy != null);
+ synchronized(this)
+ {
+ if(_identities.contains(proxy.ice_getIdentity()))
+ {
+ //
+ // Only add the proxy to the router if it's not already in our local map.
+ //
+ return true;
+ }
+ }
+
+ _router.addProxies_async(new Ice.AMI_Router_addProxies()
+ {
+ public void
+ ice_response(Ice.ObjectPrx[] evictedProxies)
+ {
+ addAndEvictProxies(proxy, evictedProxies);
+ callback.addedProxy();
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ callback.setException(ex);
+ }
+ },
+ new Ice.ObjectPrx[] { proxy });
+
+ return false;
+ }
+
+ public synchronized void
+ setAdapter(Ice.ObjectAdapter adapter)
+ {
+ _adapter = adapter;
+ }
+
+ public synchronized Ice.ObjectAdapter
+ getAdapter()
+ {
+ return _adapter;
+ }
+
+ private synchronized EndpointI[]
+ setClientEndpoints(Ice.ObjectPrx clientProxy)
+ {
+ if(_clientEndpoints == null)
{
- Ice.ObjectPrx clientProxy = _router.getClientProxy();
if(clientProxy == null)
{
//
@@ -82,76 +218,69 @@ public final class RouterInfo
{
// Ignore - collocated router.
}
-
+
_clientEndpoints = ((Ice.ObjectPrxHelperBase)clientProxy).__reference().getEndpoints();
}
}
-
return _clientEndpoints;
}
- public synchronized EndpointI[]
- getServerEndpoints()
+ private synchronized EndpointI[]
+ setServerEndpoints(Ice.ObjectPrx serverProxy)
{
- if(_serverEndpoints == null) // Lazy initialization.
+ if(serverProxy == null)
{
- Ice.ObjectPrx serverProxy = _router.getServerProxy();
- if(serverProxy == null)
- {
- throw new Ice.NoEndpointException();
- }
-
- serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed.
- _serverEndpoints = ((Ice.ObjectPrxHelperBase)serverProxy).__reference().getEndpoints();
+ throw new Ice.NoEndpointException();
}
-
+
+ serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed.
+ _serverEndpoints = ((Ice.ObjectPrxHelperBase)serverProxy).__reference().getEndpoints();
return _serverEndpoints;
}
- public synchronized void
- addProxy(Ice.ObjectPrx proxy)
+ private synchronized void
+ addAndEvictProxies(Ice.ObjectPrx proxy, Ice.ObjectPrx[] evictedProxies)
{
- assert(proxy != null);
-
- if(!_identities.contains(proxy.ice_getIdentity()))
+ //
+ // Check if the proxy hasn't already been evicted by a
+ // concurrent addProxies call. If it's the case, don't
+ // add it to our local map.
+ //
+ int index = _evictedIdentities.indexOf(proxy.ice_getIdentity());
+ if(index >= 0)
+ {
+ _evictedIdentities.remove(index);
+ }
+ else
{
//
- // Only add the proxy to the router if it's not already in our local map.
- //
- Ice.ObjectPrx[] proxies = new Ice.ObjectPrx[1];
- proxies[0] = proxy;
- Ice.ObjectPrx[] evictedProxies = _router.addProxies(proxies);
-
- //
- // If we successfully added the proxy to the router, we add it to our local map.
+ // If we successfully added the proxy to the router,
+ // we add it to our local map.
//
_identities.add(proxy.ice_getIdentity());
+ }
- //
- // We also must remove whatever proxies the router evicted.
- //
- for(int i = 0; i < evictedProxies.length; ++i)
+ //
+ // We also must remove whatever proxies the router evicted.
+ //
+ for(int i = 0; i < evictedProxies.length; ++i)
+ {
+ if(!_identities.remove(evictedProxies[i].ice_getIdentity()))
{
- _identities.remove(evictedProxies[i].ice_getIdentity());
+ //
+ // It's possible for the proxy to not have been
+ // added yet in the local map if two threads
+ // concurrently call addProxies.
+ //
+ _evictedIdentities.add(evictedProxies[i].ice_getIdentity());
}
}
}
- public synchronized void
- setAdapter(Ice.ObjectAdapter adapter)
- {
- _adapter = adapter;
- }
-
- public synchronized Ice.ObjectAdapter
- getAdapter()
- {
- return _adapter;
- }
-
private final Ice.RouterPrx _router;
private EndpointI[] _clientEndpoints;
private EndpointI[] _serverEndpoints;
private Ice.ObjectAdapter _adapter;
private java.util.HashSet _identities = new java.util.HashSet();
+ private java.util.List _evictedIdentities = new java.util.ArrayList();
}
diff --git a/java/src/IceInternal/RouterManager.java b/java/src/IceInternal/RouterManager.java
index a34091fd479..9aad2116754 100644
--- a/java/src/IceInternal/RouterManager.java
+++ b/java/src/IceInternal/RouterManager.java
@@ -39,7 +39,10 @@ public final class RouterManager
return null;
}
- Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null)); // The router cannot be routed.
+ //
+ // The router cannot be routed.
+ //
+ Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null));
synchronized(this)
{
diff --git a/java/src/IceInternal/SelectorThread.java b/java/src/IceInternal/SelectorThread.java
new file mode 100644
index 00000000000..6a291e36926
--- /dev/null
+++ b/java/src/IceInternal/SelectorThread.java
@@ -0,0 +1,511 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class SelectorThread
+{
+ public interface SocketReadyCallback
+ {
+ //
+ // The selector thread unregisters the callback when socketReady returns SocketStatus.Finished.
+ //
+ SocketStatus socketReady(boolean finished);
+
+ //
+ // The selector thread doesn't unregister the callback when sockectTimeout is called; socketTimeout
+ // must unregister the callback either explicitly with unregister() or by shutting down the socket
+ // (if necessary).
+ //
+ void socketTimeout();
+ }
+
+ SelectorThread(Instance instance)
+ {
+ _instance = instance;
+ _destroyed = false;
+
+ Network.SocketPair pair = Network.createPipe();
+ _fdIntrRead = (java.nio.channels.ReadableByteChannel)pair.source;
+ _fdIntrWrite = pair.sink;
+
+ try
+ {
+ _selector = java.nio.channels.Selector.open();
+ pair.source.configureBlocking(false);
+ _fdIntrReadKey = pair.source.register(_selector, java.nio.channels.SelectionKey.OP_READ);
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.SyscallException sys = new Ice.SyscallException();
+ sys.initCause(ex);
+ throw sys;
+ }
+
+ //
+ // The Selector holds a Set representing the selected keys. The
+ // Set reference doesn't change, so we obtain it once here.
+ //
+ _keys = _selector.selectedKeys();
+
+ _thread = new HelperThread();
+ _thread.start();
+
+ _timer = _instance.timer();
+ }
+
+ protected synchronized void
+ finalize()
+ throws Throwable
+ {
+ IceUtil.Assert.FinalizerAssert(_destroyed);
+ }
+
+ public synchronized void
+ destroy()
+ {
+ assert(!_destroyed);
+ _destroyed = true;
+ setInterrupt();
+ }
+
+ public synchronized void
+ _register(java.nio.channels.SelectableChannel fd, SocketReadyCallback cb, SocketStatus status, int timeout)
+ {
+ assert(!_destroyed); // The selector thread is destroyed after the incoming/outgoing connection factories.
+ assert(status != SocketStatus.Finished);
+
+ SocketInfo info = new SocketInfo(fd, cb, status, timeout);
+ _changes.add(info);
+ if(info.timeout >= 0)
+ {
+ _timer.schedule(info, info.timeout);
+ }
+ setInterrupt();
+ }
+
+ //
+ // Unregister the given file descriptor. The registered callback will be notified with socketReady()
+ // upon registration to allow some cleanup to be done.
+ //
+ public synchronized void
+ unregister(java.nio.channels.SelectableChannel fd)
+ {
+ assert(!_destroyed); // The selector thread is destroyed after the incoming/outgoing connection factories.
+ _changes.add(new SocketInfo(fd, null, SocketStatus.Finished, 0));
+ setInterrupt();
+ }
+
+ public void
+ joinWithThread()
+ {
+ if(_thread != null)
+ {
+ try
+ {
+ _thread.join();
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+ }
+
+ private void
+ clearInterrupt()
+ {
+ byte b = 0;
+
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(1);
+ try
+ {
+ while(true)
+ {
+ buf.rewind();
+ if(_fdIntrRead.read(buf) != 1)
+ {
+ break;
+ }
+
+ b = buf.get(0);
+ break;
+ }
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
+
+ private void
+ setInterrupt()
+ {
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(1);
+ buf.put(0, (byte)0);
+ while(buf.hasRemaining())
+ {
+ try
+ {
+ _fdIntrWrite.write(buf);
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
+ }
+
+ public void
+ run()
+ {
+ java.util.HashMap socketMap = new java.util.HashMap();
+ java.util.LinkedList readyList = new java.util.LinkedList();
+ java.util.LinkedList finishedList = new java.util.LinkedList();
+ while(true)
+ {
+ int ret = 0;
+
+ while(true)
+ {
+ try
+ {
+ ret = _selector.select();
+ }
+ catch(java.io.IOException ex)
+ {
+ //
+ // Pressing Ctrl-C causes select() to raise an
+ // IOException, which seems like a JDK bug. We trap
+ // for that special case here and ignore it.
+ // Hopefully we're not masking something important!
+ //
+ if(Network.interrupted(ex))
+ {
+ continue;
+ }
+
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ //throw se;
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ se.printStackTrace(pw);
+ pw.flush();
+ String s = "exception in selector thread:\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ continue;
+ }
+
+ break;
+ }
+
+ assert(readyList.isEmpty() && finishedList.isEmpty());
+
+ if(_keys.contains(_fdIntrReadKey) && _fdIntrReadKey.isReadable())
+ {
+ synchronized(this)
+ {
+ //
+ // There are two possiblities for an interrupt:
+ //
+ // 1. The selector thread has been destroyed.
+ // 2. A socket was registered or unregistered.
+ //
+
+ //
+ // Thread destroyed?
+ //
+ if(_destroyed)
+ {
+ break;
+ }
+
+ //
+ // Remove the interrupt channel from the selected key set.
+ //
+ _keys.remove(_fdIntrReadKey);
+
+ clearInterrupt();
+ SocketInfo info = (SocketInfo)_changes.removeFirst();
+ if(info.cb != null) // Registration
+ {
+ try
+ {
+ info.key = info.fd.register(_selector, convertStatus(info.status), info);
+ }
+ catch(java.nio.channels.ClosedChannelException ex)
+ {
+ assert(false);
+ }
+ assert(!socketMap.containsKey(info.fd));
+ socketMap.put(info.fd, info);
+ }
+ else // Unregistration
+ {
+ info = (SocketInfo)socketMap.get(info.fd);
+ if(info != null && info.status != SocketStatus.Finished)
+ {
+ if(info.timeout >= 0)
+ {
+ _timer.cancel(info);
+ }
+
+ try
+ {
+ info.key.cancel();
+ }
+ catch(java.nio.channels.CancelledKeyException ex)
+ {
+ assert(false);
+ }
+ info.status = SocketStatus.Finished;
+ readyList.add(info);
+ }
+ }
+ }
+ }
+ else
+ {
+ //
+ // Examine the selection key set.
+ //
+ java.util.Iterator iter = _keys.iterator();
+ while(iter.hasNext())
+ {
+ //
+ // Ignore selection keys that have been cancelled or timed out.
+ //
+ java.nio.channels.SelectionKey key = (java.nio.channels.SelectionKey)iter.next();
+ iter.remove();
+ assert(key != _fdIntrReadKey);
+ SocketInfo info = (SocketInfo)key.attachment();
+ if(info.timeout >= 0)
+ {
+ _timer.cancel(info);
+ }
+ assert(key.isValid());
+ readyList.add(info);
+ }
+ }
+
+ java.util.Iterator iter = readyList.iterator();
+ while(iter.hasNext())
+ {
+ SocketInfo info = (SocketInfo)iter.next();
+ SocketStatus status;
+ try
+ {
+ status = info.cb.socketReady(info.status == SocketStatus.Finished);
+ }
+ catch(Ice.LocalException ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "exception in selector thread " + _thread.getName() +
+ " while calling socketReady():\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ status = SocketStatus.Finished;
+ }
+
+ if(status == SocketStatus.Finished)
+ {
+ finishedList.add(info);
+ }
+ else
+ {
+ assert(info.status != SocketStatus.Finished);
+ try
+ {
+ info.status = status;
+ info.key.interestOps(convertStatus(status));
+ if(info.timeout >= 0)
+ {
+ _timer.schedule(info, info.timeout);
+ }
+ }
+ catch(java.nio.channels.CancelledKeyException ex)
+ {
+ assert(false);
+ }
+ }
+ }
+ readyList.clear();
+
+ if(finishedList.isEmpty())
+ {
+ continue;
+ }
+
+ iter = finishedList.iterator();
+ while(iter.hasNext())
+ {
+ SocketInfo info = (SocketInfo)iter.next();
+ if(info.status != SocketStatus.Finished)
+ {
+ try
+ {
+ info.key.cancel();
+ }
+ catch(java.nio.channels.CancelledKeyException ex)
+ {
+ //assert(false); // The channel might already be closed at this point so we can't assert.
+ }
+ }
+ socketMap.remove(info.fd);
+ }
+ finishedList.clear();
+ }
+
+ assert(_destroyed);
+
+ try
+ {
+ _selector.close();
+ }
+ catch(java.io.IOException ex)
+ {
+ // Ignore.
+ }
+
+ try
+ {
+ _fdIntrWrite.close();
+ }
+ catch(java.io.IOException ex)
+ {
+ //
+ // BUGFIX:
+ //
+ // Ignore this exception. This shouldn't happen
+ // but for some reasons the close() call raises
+ // "java.io.IOException: No such file or
+ // directory" under Linux with JDK 1.4.2.
+ //
+ }
+ _fdIntrWrite = null;
+
+ try
+ {
+ _fdIntrRead.close();
+ }
+ catch(java.io.IOException ex)
+ {
+ }
+ _fdIntrRead = null;
+ }
+
+ private int
+ convertStatus(SocketStatus status)
+ {
+ if(status == SocketStatus.NeedConnect)
+ {
+ return java.nio.channels.SelectionKey.OP_CONNECT;
+ }
+ else if(status == SocketStatus.NeedRead)
+ {
+ return java.nio.channels.SelectionKey.OP_READ;
+ }
+ else
+ {
+ assert(status == SocketStatus.NeedWrite);
+ return java.nio.channels.SelectionKey.OP_WRITE;
+ }
+ }
+
+ private Instance _instance;
+ private boolean _destroyed;
+ private java.nio.channels.ReadableByteChannel _fdIntrRead;
+ private java.nio.channels.SelectionKey _fdIntrReadKey;
+ private java.nio.channels.WritableByteChannel _fdIntrWrite;
+ private java.nio.channels.Selector _selector;
+ private java.util.Set _keys;
+ private java.util.LinkedList _changes = new java.util.LinkedList();
+
+ private final class SocketInfo implements TimerTask
+ {
+ java.nio.channels.SelectableChannel fd;
+ SocketReadyCallback cb;
+ SocketStatus status;
+ int timeout;
+ java.nio.channels.SelectionKey key;
+
+ public void
+ runTimerTask()
+ {
+ this.cb.socketTimeout(); // Exceptions will be reported by the timer thread.
+ }
+
+ SocketInfo(java.nio.channels.SelectableChannel fd, SocketReadyCallback cb, SocketStatus status, int timeout)
+ {
+ this.fd = fd;
+ this.cb = cb;
+ this.status = status;
+ this.timeout = timeout;
+ }
+ }
+
+ private final class HelperThread extends Thread
+ {
+ HelperThread()
+ {
+ String threadName = _instance.initializationData().properties.getProperty("Ice.ProgramName");
+ if(threadName.length() > 0)
+ {
+ threadName += "-";
+ }
+ setName(threadName + "Ice.SelectorThread");
+ }
+
+ public void
+ run()
+ {
+ if(_instance.initializationData().threadHook != null)
+ {
+ _instance.initializationData().threadHook.start();
+ }
+
+ try
+ {
+ SelectorThread.this.run();
+ }
+ catch(Ice.LocalException ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "exception in selector thread " + getName() + ":\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ }
+ catch(java.lang.Exception ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "unknown exception in selector thread " + getName() + ":\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ }
+
+ if(_instance.initializationData().threadHook != null)
+ {
+ _instance.initializationData().threadHook.stop();
+ }
+ }
+ }
+
+ private HelperThread _thread;
+ private Timer _timer;
+}
diff --git a/java/src/IceInternal/SocketStatus.java b/java/src/IceInternal/SocketStatus.java
new file mode 100644
index 00000000000..dc3bed4a735
--- /dev/null
+++ b/java/src/IceInternal/SocketStatus.java
@@ -0,0 +1,39 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public final class SocketStatus
+{
+ private static SocketStatus[] _values = new SocketStatus[4];
+
+ public static final int _Finished = 0;
+ public static final SocketStatus Finished = new SocketStatus(_Finished);
+ public static final int _NeedConnect = 1;
+ public static final SocketStatus NeedConnect = new SocketStatus(_NeedConnect);
+ public static final int _NeedRead = 2;
+ public static final SocketStatus NeedRead = new SocketStatus(_NeedRead);
+ public static final int _NeedWrite = 3;
+ public static final SocketStatus NeedWrite = new SocketStatus(_NeedWrite);
+
+ public int
+ value()
+ {
+ return _value;
+ }
+
+ private
+ SocketStatus(int val)
+ {
+ _value = val;
+ _values[val] = this;
+ }
+
+ private int _value;
+}
diff --git a/java/src/IceInternal/TcpAcceptor.java b/java/src/IceInternal/TcpAcceptor.java
index 21d56732fc6..72eaec50cf9 100644
--- a/java/src/IceInternal/TcpAcceptor.java
+++ b/java/src/IceInternal/TcpAcceptor.java
@@ -160,7 +160,7 @@ class TcpAcceptor implements Acceptor
_logger.trace(_traceLevels.networkCat, s);
}
- return new TcpTransceiver(_instance, fd);
+ return new TcpTransceiver(_instance, fd, true);
}
public void
diff --git a/java/src/IceInternal/TcpConnector.java b/java/src/IceInternal/TcpConnector.java
index 2635d9ad881..ab2a2a877e3 100644
--- a/java/src/IceInternal/TcpConnector.java
+++ b/java/src/IceInternal/TcpConnector.java
@@ -11,8 +11,6 @@ package IceInternal;
final class TcpConnector implements Connector, java.lang.Comparable
{
- final static short TYPE = 1;
-
public Transceiver
connect(int timeout)
{
@@ -25,21 +23,22 @@ final class TcpConnector implements Connector, java.lang.Comparable
java.nio.channels.SocketChannel fd = Network.createTcpSocket();
Network.setBlock(fd, false);
Network.setTcpBufSize(fd, _instance.initializationData().properties, _logger);
- Network.doConnect(fd, _addr, timeout);
-
- if(_traceLevels.network >= 1)
+ boolean connected = Network.doConnect(fd, _addr, timeout);
+ if(connected)
{
- String s = "tcp connection established\n" + Network.fdToString(fd);
- _logger.trace(_traceLevels.networkCat, s);
+ if(_traceLevels.network >= 1)
+ {
+ String s = "tcp connection established\n" + Network.fdToString(fd);
+ _logger.trace(_traceLevels.networkCat, s);
+ }
}
-
- return new TcpTransceiver(_instance, fd);
+ return new TcpTransceiver(_instance, fd, connected);
}
public short
type()
{
- return TYPE;
+ return TcpEndpointI.TYPE;
}
public String
@@ -54,21 +53,6 @@ final class TcpConnector implements Connector, java.lang.Comparable
return _hashCode;
}
- public final boolean
- equivalent(String host, int port)
- {
- java.net.InetSocketAddress addr;
- try
- {
- addr = Network.getAddress(host, port);
- }
- catch(Ice.DNSException ex)
- {
- return false;
- }
- return addr.equals(_addr);
- }
-
//
// Only for use by TcpEndpoint
//
@@ -149,6 +133,13 @@ final class TcpConnector implements Connector, java.lang.Comparable
return Network.compareAddress(_addr, p._addr);
}
+ protected synchronized void
+ finalize()
+ throws Throwable
+ {
+ super.finalize();
+ }
+
private Instance _instance;
private TraceLevels _traceLevels;
private Ice.Logger _logger;
diff --git a/java/src/IceInternal/TcpEndpointI.java b/java/src/IceInternal/TcpEndpointI.java
index 941b1ee0cc3..90b3073b3ce 100644
--- a/java/src/IceInternal/TcpEndpointI.java
+++ b/java/src/IceInternal/TcpEndpointI.java
@@ -332,17 +332,16 @@ final class TcpEndpointI extends EndpointI
// Return connectors for this endpoint, or empty list if no connector
// is available.
//
- public java.util.ArrayList
+ public java.util.List
connectors()
{
- java.util.ArrayList connectors = new java.util.ArrayList();
- java.util.ArrayList addresses = Network.getAddresses(_host, _port);
- java.util.Iterator p = addresses.iterator();
- while(p.hasNext())
- {
- connectors.add(new TcpConnector(_instance, (java.net.InetSocketAddress)p.next(), _timeout, _connectionId));
- }
- return connectors;
+ return connectors(Network.getAddresses(_host, _port));
+ }
+
+ public void
+ connectors_async(EndpointI_connectors callback)
+ {
+ _instance.endpointHostResolver().resolve(_host, _port, this, callback);
}
//
@@ -364,7 +363,7 @@ final class TcpEndpointI extends EndpointI
// Expand endpoint out in to separate endpoints for each local
// host if listening on INADDR_ANY.
//
- public java.util.ArrayList
+ public java.util.List
expand()
{
java.util.ArrayList endps = new java.util.ArrayList();
@@ -389,21 +388,21 @@ final class TcpEndpointI extends EndpointI
}
//
- // Check whether the endpoint is equivalent to a specific Connector
+ // Check whether the endpoint is equivalent to another one.
//
public boolean
- equivalent(Connector connector)
+ equivalent(EndpointI endpoint)
{
- TcpConnector tcpConnector = null;
+ TcpEndpointI tcpEndpointI = null;
try
{
- tcpConnector = (TcpConnector)connector;
+ tcpEndpointI = (TcpEndpointI)endpoint;
}
catch(ClassCastException ex)
{
return false;
}
- return tcpConnector.equivalent(_host, _port);
+ return tcpEndpointI._host.equals(_host) && tcpEndpointI._port == _port;
}
public int
@@ -489,6 +488,18 @@ final class TcpEndpointI extends EndpointI
return false;
}
+ public java.util.List
+ connectors(java.util.List addresses)
+ {
+ java.util.ArrayList connectors = new java.util.ArrayList();
+ java.util.Iterator p = addresses.iterator();
+ while(p.hasNext())
+ {
+ connectors.add(new TcpConnector(_instance, (java.net.InetSocketAddress)p.next(), _timeout, _connectionId));
+ }
+ return connectors;
+ }
+
private void
calcHashValue()
{
diff --git a/java/src/IceInternal/TcpTransceiver.java b/java/src/IceInternal/TcpTransceiver.java
index f07bff3a62c..533b91adfc7 100644
--- a/java/src/IceInternal/TcpTransceiver.java
+++ b/java/src/IceInternal/TcpTransceiver.java
@@ -18,6 +18,29 @@ final class TcpTransceiver implements Transceiver
return _fd;
}
+ public SocketStatus
+ initialize(int timeout)
+ {
+ if(_state == StateNeedConnect && timeout == 0)
+ {
+ _state = StateConnectPending;
+ return SocketStatus.NeedConnect;
+ }
+ else if(_state <= StateConnectPending)
+ {
+ Network.doFinishConnect(_fd, timeout);
+ _state = StateConnected;
+ _desc = Network.fdToString(_fd);
+ if(_traceLevels.network >= 1)
+ {
+ String s = "tcp connection established\n" + _desc;
+ _logger.trace(_traceLevels.networkCat, s);
+ }
+ }
+ assert(_state == StateConnected);
+ return SocketStatus.Finished;
+ }
+
public void
close()
{
@@ -74,6 +97,11 @@ final class TcpTransceiver implements Transceiver
public void
shutdownWrite()
{
+ if(_state < StateConnected)
+ {
+ return;
+ }
+
if(_traceLevels.network >= 2)
{
String s = "shutting down tcp connection for writing\n" + toString();
@@ -110,6 +138,11 @@ final class TcpTransceiver implements Transceiver
public void
shutdownReadWrite()
{
+ if(_state < StateConnected)
+ {
+ return;
+ }
+
if(_traceLevels.network >= 2)
{
String s = "shutting down tcp connection for reading and writing\n" + toString();
@@ -144,125 +177,78 @@ final class TcpTransceiver implements Transceiver
}
}
- public void
- write(BasicStream stream, int timeout)
+ public boolean
+ write(Buffer buf, int timeout)
throws LocalExceptionWrapper
{
- java.nio.ByteBuffer buf = stream.prepareWrite();
- int size = buf.limit();
- int packetSize = 0;
- if(_maxPacketSize > 0 && size > _maxPacketSize)
+ while(writeBuffer(buf.b))
{
- packetSize = _maxPacketSize;
- buf.limit(buf.position() + packetSize);
- }
+ //
+ // There is more data to write but the socket would block; now we
+ // must deal with timeouts.
+ //
+ assert(buf.b.hasRemaining());
- while(buf.hasRemaining())
- {
+ if(timeout == 0)
+ {
+ return false;
+ }
+
try
{
- assert(_fd != null);
- int ret = _fd.write(buf);
-
- if(ret == -1)
+ if(_writeSelector == null)
{
- throw new Ice.ConnectionLostException();
+ _writeSelector = java.nio.channels.Selector.open();
+ _fd.register(_writeSelector, java.nio.channels.SelectionKey.OP_WRITE, null);
}
- if(ret == 0)
+ try
{
- if(timeout == 0)
+ if(timeout > 0)
{
- throw new Ice.TimeoutException();
- }
-
- if(_writeSelector == null)
- {
- _writeSelector = java.nio.channels.Selector.open();
- _fd.register(_writeSelector, java.nio.channels.SelectionKey.OP_WRITE, null);
- }
-
- try
- {
- if(timeout > 0)
- {
- long start = IceInternal.Time.currentMonotonicTimeMillis();
- int n = _writeSelector.select(timeout);
- if(n == 0 && IceInternal.Time.currentMonotonicTimeMillis() >= start + timeout)
- {
- throw new Ice.TimeoutException();
- }
- }
- else
+ long start = IceInternal.Time.currentMonotonicTimeMillis();
+ int n = _writeSelector.select(timeout);
+ if(n == 0 && IceInternal.Time.currentMonotonicTimeMillis() >= start + timeout)
{
- _writeSelector.select();
+ throw new Ice.TimeoutException();
}
}
- catch(java.io.InterruptedIOException ex)
+ else
{
- // Ignore.
+ _writeSelector.select();
}
-
- continue;
}
-
-
- if(_traceLevels.network >= 3)
- {
- String s = "sent " + ret + " of " + buf.limit() + " bytes via tcp\n" + toString();
- _logger.trace(_traceLevels.networkCat, s);
- }
-
- if(_stats != null)
- {
- _stats.bytesSent(type(), ret);
- }
-
- if(packetSize > 0)
+ catch(java.io.InterruptedIOException ex)
{
- assert(buf.position() == buf.limit());
- int position = buf.position();
- if(size - position > packetSize)
- {
- buf.limit(position + packetSize);
- }
- else
- {
- packetSize = 0;
- buf.limit(size);
- }
+ // Ignore.
}
}
- catch(java.io.InterruptedIOException ex)
- {
- continue;
- }
catch(java.io.IOException ex)
{
Ice.SocketException se = new Ice.SocketException();
se.initCause(ex);
throw se;
}
- }
+ }
+ return true;
}
public boolean
- read(BasicStream stream, int timeout)
+ read(Buffer buf, int timeout, Ice.BooleanHolder moreData)
{
- java.nio.ByteBuffer buf = stream.prepareRead();
-
int remaining = 0;
if(_traceLevels.network >= 3)
{
- remaining = buf.remaining();
+ remaining = buf.b.remaining();
}
+ moreData.value = false;
- while(buf.hasRemaining())
+ while(buf.b.hasRemaining())
{
try
{
assert(_fd != null);
- int ret = _fd.read(buf);
+ int ret = _fd.read(buf.b);
if(ret == -1)
{
@@ -273,7 +259,7 @@ final class TcpTransceiver implements Transceiver
{
if(timeout == 0)
{
- throw new Ice.TimeoutException();
+ return false;
}
if(_readSelector == null)
@@ -339,7 +325,7 @@ final class TcpTransceiver implements Transceiver
}
}
- return false;
+ return true;
}
public String
@@ -355,9 +341,9 @@ final class TcpTransceiver implements Transceiver
}
public void
- checkSendSize(BasicStream stream, int messageSizeMax)
+ checkSendSize(Buffer buf, int messageSizeMax)
{
- if(stream.size() > messageSizeMax)
+ if(buf.size() > messageSizeMax)
{
throw new Ice.MemoryLimitException();
}
@@ -366,12 +352,13 @@ final class TcpTransceiver implements Transceiver
//
// Only for use by TcpConnector, TcpAcceptor
//
- TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd)
+ TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd, boolean connected)
{
_fd = fd;
_traceLevels = instance.traceLevels();
_logger = instance.initializationData().logger;
_stats = instance.initializationData().stats;
+ _state = connected ? StateConnected : StateNeedConnect;
_desc = Network.fdToString(_fd);
_maxPacketSize = 0;
@@ -399,12 +386,89 @@ final class TcpTransceiver implements Transceiver
super.finalize();
}
+ private boolean
+ writeBuffer(java.nio.ByteBuffer buf)
+ {
+ final int size = buf.limit();
+ int packetSize = size - buf.position();
+ if(_maxPacketSize > 0 && packetSize > _maxPacketSize)
+ {
+ packetSize = _maxPacketSize;
+ buf.limit(buf.position() + packetSize);
+ }
+
+ while(buf.hasRemaining())
+ {
+ try
+ {
+ assert(_fd != null);
+ int ret = _fd.write(buf);
+
+ if(ret == -1)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ else if(ret == 0)
+ {
+ //
+ // Writing would block, so we reset the limit (if necessary) and return true to indicate
+ // that more data must be sent.
+ //
+ if(packetSize == _maxPacketSize)
+ {
+ buf.limit(size);
+ }
+ return true;
+ }
+
+ if(_traceLevels.network >= 3)
+ {
+ String s = "sent " + ret + " of " + size + " bytes via tcp\n" + toString();
+ _logger.trace(_traceLevels.networkCat, s);
+ }
+
+ if(_stats != null)
+ {
+ _stats.bytesSent(type(), ret);
+ }
+
+ if(packetSize == _maxPacketSize)
+ {
+ assert(buf.position() == buf.limit());
+ packetSize = size - buf.position();
+ if(packetSize > _maxPacketSize)
+ {
+ packetSize = _maxPacketSize;
+ }
+ buf.limit(buf.position() + packetSize);
+ }
+ }
+ catch(java.io.InterruptedIOException ex)
+ {
+ continue;
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
+
+ return false; // No more data to send.
+ }
+
private java.nio.channels.SocketChannel _fd;
private TraceLevels _traceLevels;
private Ice.Logger _logger;
private Ice.Stats _stats;
private String _desc;
+ private int _state;
private java.nio.channels.Selector _readSelector;
private java.nio.channels.Selector _writeSelector;
private int _maxPacketSize;
+
+ private static final int StateNeedConnect = 0;
+ private static final int StateConnectPending = 1;
+ private static final int StateConnected = 2;
}
diff --git a/java/src/IceInternal/ThreadPool.java b/java/src/IceInternal/ThreadPool.java
index 30ed86a3082..6306ca10475 100644
--- a/java/src/IceInternal/ThreadPool.java
+++ b/java/src/IceInternal/ThreadPool.java
@@ -146,6 +146,7 @@ public final class ThreadPool
assert(!_destroyed);
assert(_handlerMap.isEmpty());
assert(_changes.isEmpty());
+ assert(_workItems.isEmpty());
_destroyed = true;
setInterrupt();
}
@@ -193,6 +194,14 @@ public final class ThreadPool
setInterrupt();
}
+ public synchronized void
+ execute(ThreadPoolWorkItem workItem)
+ {
+ assert(!_destroyed);
+ _workItems.add(workItem);
+ setInterrupt();
+ }
+
public void
promoteFollower()
{
@@ -468,6 +477,7 @@ public final class ThreadPool
}
EventHandler handler = null;
+ ThreadPoolWorkItem workItem = null;
//
// Only call select() if there are no pending handlers with additional data
@@ -510,14 +520,15 @@ public final class ThreadPool
}
//
- // There are two possiblities for an interrupt:
+ // There are three possiblities for an interrupt:
//
// 1. The thread pool has been destroyed.
//
// 2. An event handler was registered or unregistered.
//
-
+ // 3. A work item has been scheduled.
//
+
// Thread pool destroyed?
//
if(_destroyed)
@@ -547,57 +558,79 @@ public final class ThreadPool
// An event handler must have been registered
// or unregistered.
//
- assert(!_changes.isEmpty());
- FdHandlerPair change = (FdHandlerPair)_changes.removeFirst();
-
- if(change.handler != null) // Addition if handler is set.
+ if(!_changes.isEmpty())
{
- int op;
- if((change.fd.validOps() & java.nio.channels.SelectionKey.OP_READ) > 0)
- {
- op = java.nio.channels.SelectionKey.OP_READ;
- }
- else
+ FdHandlerPair change = (FdHandlerPair)_changes.removeFirst();
+
+ if(change.handler != null) // Addition if handler is set.
{
- op = java.nio.channels.SelectionKey.OP_ACCEPT;
- }
+ int op;
+ if((change.fd.validOps() & java.nio.channels.SelectionKey.OP_READ) > 0)
+ {
+ op = java.nio.channels.SelectionKey.OP_READ;
+ }
+ else
+ {
+ op = java.nio.channels.SelectionKey.OP_ACCEPT;
+ }
- java.nio.channels.SelectionKey key = null;
- try
- {
- key = change.fd.register(_selector, op, change.handler);
+ java.nio.channels.SelectionKey key = null;
+ try
+ {
+ key = change.fd.register(_selector, op, change.handler);
+ }
+ catch(java.nio.channels.ClosedChannelException ex)
+ {
+ //
+ // This is expected if the transceiver finishConnect() call failed
+ // and the connection is a background connection.
+ //
+ }
+ _handlerMap.put(change.fd, new HandlerKeyPair(change.handler, key));
+
+ //
+ // If the handler is readable and already has some data to read add it
+ // to the _pendingHandlers list to ensure it will be processed.
+ //
+ if(change.handler.readable() && change.handler.hasMoreData())
+ {
+ _pendingHandlers.add(change.handler);
+ }
+
+ if(TRACE_REGISTRATION)
+ {
+ trace("added handler (" + change.handler.getClass().getName() + ") for fd " +
+ change.fd);
+ }
+
+ continue;
}
- catch(java.nio.channels.ClosedChannelException ex)
+ else // Removal if handler is not set.
{
- assert(false);
- }
- _handlerMap.put(change.fd, new HandlerKeyPair(change.handler, key));
+ HandlerKeyPair pair = (HandlerKeyPair)_handlerMap.remove(change.fd);
+ assert(pair != null);
+ handler = pair.handler;
+ finished = true;
+ if(pair.key != null)
+ {
+ pair.key.cancel();
+ }
- if(TRACE_REGISTRATION)
- {
- trace("added handler (" + change.handler.getClass().getName() + ") for fd " +
- change.fd);
- }
+ if(TRACE_REGISTRATION)
+ {
+ trace("removed handler (" + handler.getClass().getName() + ") for fd " +
+ change.fd);
+ }
- continue;
+ // Don't continue; we have to call
+ // finished() on the event handler below,
+ // outside the thread synchronization.
+ }
}
- else // Removal if handler is not set.
+ else
{
- HandlerKeyPair pair = (HandlerKeyPair)_handlerMap.remove(change.fd);
- assert(pair != null);
- handler = pair.handler;
- finished = true;
- pair.key.cancel();
-
- if(TRACE_REGISTRATION)
- {
- trace("removed handler (" + handler.getClass().getName() + ") for fd " +
- change.fd);
- }
-
- // Don't continue; we have to call
- // finished() on the event handler below,
- // outside the thread synchronization.
+ assert(!_workItems.isEmpty());
+ workItem = (ThreadPoolWorkItem)_workItems.removeFirst();
}
}
else
@@ -672,6 +705,29 @@ public final class ThreadPool
// promoteFollower().
//
}
+ else if(workItem != null)
+ {
+ try
+ {
+ workItem.execute(this);
+ }
+ catch(Ice.LocalException ex)
+ {
+ java.io.StringWriter sw = new java.io.StringWriter();
+ java.io.PrintWriter pw = new java.io.PrintWriter(sw);
+ ex.printStackTrace(pw);
+ pw.flush();
+ String s = "exception in `" + _prefix + "' while calling execute():\n" + sw.toString();
+ _instance.initializationData().logger.error(s);
+ }
+
+ //
+ // No "continue", because we want execute() to
+ // be called in its own thread from this
+ // pool. Note that this means that execute()
+ // must call promoteFollower().
+ //
+ }
else
{
assert(handler != null);
@@ -716,17 +772,23 @@ public final class ThreadPool
{
try
{
+ if(!read(handler))
+ {
+ continue; // Can't read without blocking.
+ }
+
//
- // If read returns true, the handler has more data for the thread pool
- // to process.
+ // If the handler has more data to process add it to the _pendingHandlers list
+ // to ensure it will be processed.
//
- if(read(handler))
+ if(handler.hasMoreData())
{
_pendingHandlers.add(handler);
}
}
- catch(Ice.TimeoutException ex) // Expected.
+ catch(Ice.TimeoutException ex)
{
+ assert(false); // This shouldn't occur as we only perform non-blocking reads.
continue;
}
catch(Ice.DatagramLimitException ex) // Expected.
@@ -914,8 +976,6 @@ public final class ThreadPool
private boolean
read(EventHandler handler)
{
- boolean moreData = false;
-
BasicStream stream = handler._stream;
if(stream.size() == 0)
@@ -926,7 +986,10 @@ public final class ThreadPool
if(stream.pos() != stream.size())
{
- moreData = handler.read(stream);
+ if(!handler.read(stream))
+ {
+ return false;
+ }
assert(stream.pos() == stream.size());
}
@@ -1008,12 +1071,15 @@ public final class ThreadPool
}
else
{
- moreData = handler.read(stream);
+ if(!handler.read(stream))
+ {
+ return false;
+ }
assert(stream.pos() == stream.size());
}
}
- return moreData;
+ return true;
}
/*
@@ -1205,6 +1271,7 @@ public final class ThreadPool
private java.util.Set _keys;
private java.util.LinkedList _changes = new java.util.LinkedList();
+ private java.util.LinkedList _workItems = new java.util.LinkedList();
private java.util.HashMap _handlerMap = new java.util.HashMap();
diff --git a/java/src/IceInternal/ThreadPoolWorkItem.java b/java/src/IceInternal/ThreadPoolWorkItem.java
new file mode 100644
index 00000000000..ba917b67708
--- /dev/null
+++ b/java/src/IceInternal/ThreadPoolWorkItem.java
@@ -0,0 +1,15 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public interface ThreadPoolWorkItem
+{
+ void execute(ThreadPool threadPool);
+}
diff --git a/java/src/IceInternal/Time.java b/java/src/IceInternal/Time.java
index d77879ef836..04059a31fff 100644
--- a/java/src/IceInternal/Time.java
+++ b/java/src/IceInternal/Time.java
@@ -16,4 +16,4 @@ final public class Time
{
return System.nanoTime() / 1000000;
}
-};
+}
diff --git a/java/src/IceInternal/Timer.java b/java/src/IceInternal/Timer.java
index 44e8ba0f6eb..7646409a16c 100644
--- a/java/src/IceInternal/Timer.java
+++ b/java/src/IceInternal/Timer.java
@@ -11,8 +11,8 @@ package IceInternal;
interface TimerTask
{
- void run();
-};
+ void runTimerTask();
+}
public final class Timer extends Thread
{
@@ -224,7 +224,7 @@ public final class Timer extends Thread
{
try
{
- token.task.run();
+ token.task.runTimerTask();
}
catch(Exception ex)
{
diff --git a/java/src/IceInternal/TraceUtil.java b/java/src/IceInternal/TraceUtil.java
index 7a81793ffdc..6a85917a7c4 100644
--- a/java/src/IceInternal/TraceUtil.java
+++ b/java/src/IceInternal/TraceUtil.java
@@ -12,77 +12,41 @@ package IceInternal;
public final class TraceUtil
{
public static void
- traceHeader(String heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
+ traceSend(BasicStream str, Ice.Logger logger, TraceLevels tl)
{
if(tl.protocol >= 1)
{
int p = str.pos();
str.pos(0);
-
+
java.io.StringWriter s = new java.io.StringWriter();
- s.write(heading);
- printHeader(s, str);
+ byte type = printMessage(s, str);
- logger.trace(tl.protocolCat, s.toString());
- str.pos(p);
- }
- }
+ logger.trace(tl.protocolCat, "sending " + getMessageTypeAsString(type) + " " + s.toString());
- public static void
- traceRequest(String heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
- {
- if(tl.protocol >= 1)
- {
- int p = str.pos();
- str.pos(0);
-
- java.io.StringWriter s = new java.io.StringWriter();
- s.write(heading);
- printHeader(s, str);
-
- int requestId = str.readInt();
- s.write("\nrequest id = " + requestId);
- if(requestId == 0)
- {
- s.write(" (oneway)");
- }
-
- printRequestHeader(s, str);
-
- logger.trace(tl.protocolCat, s.toString());
str.pos(p);
}
}
public static void
- traceBatchRequest(String heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
+ traceRecv(BasicStream str, Ice.Logger logger, TraceLevels tl)
{
if(tl.protocol >= 1)
{
int p = str.pos();
str.pos(0);
-
+
java.io.StringWriter s = new java.io.StringWriter();
- s.write(heading);
- printHeader(s, str);
+ byte type = printMessage(s, str);
- int batchRequestNum = str.readInt();
- s.write("\nnumber of requests = " + batchRequestNum);
-
- for(int i = 0; i < batchRequestNum; ++i)
- {
- s.write("\nrequest #" + i + ':');
- printRequestHeader(s, str);
- str.skipEncaps();
- }
+ logger.trace(tl.protocolCat, "received " + getMessageTypeAsString(type) + " " + s.toString());
- logger.trace(tl.protocolCat, s.toString());
str.pos(p);
}
}
public static void
- traceReply(String heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
+ trace(String heading, BasicStream str, Ice.Logger logger, TraceLevels tl)
{
if(tl.protocol >= 1)
{
@@ -91,105 +55,7 @@ public final class TraceUtil
java.io.StringWriter s = new java.io.StringWriter();
s.write(heading);
- printHeader(s, str);
-
- int requestId = str.readInt();
- s.write("\nrequest id = " + requestId);
-
- byte replyStatus = str.readByte();
- s.write("\nreply status = " + (int)replyStatus + ' ');
-
- switch(replyStatus)
- {
- case ReplyStatus.replyOK:
- {
- s.write("(ok)");
- break;
- }
-
- case ReplyStatus.replyUserException:
- {
- s.write("(user exception)");
- break;
- }
-
- case ReplyStatus.replyObjectNotExist:
- case ReplyStatus.replyFacetNotExist:
- case ReplyStatus.replyOperationNotExist:
- {
- switch(replyStatus)
- {
- case ReplyStatus.replyObjectNotExist:
- {
- s.write("(object not exist)");
- break;
- }
-
- case ReplyStatus.replyFacetNotExist:
- {
- s.write("(facet not exist)");
- break;
- }
-
- case ReplyStatus.replyOperationNotExist:
- {
- s.write("(operation not exist)");
- break;
- }
-
- default:
- {
- assert(false);
- break;
- }
- }
-
- printIdentityFacetOperation(s, str);
- break;
- }
-
- case ReplyStatus.replyUnknownException:
- case ReplyStatus.replyUnknownLocalException:
- case ReplyStatus.replyUnknownUserException:
- {
- switch(replyStatus)
- {
- case ReplyStatus.replyUnknownException:
- {
- s.write("(unknown exception)");
- break;
- }
-
- case ReplyStatus.replyUnknownLocalException:
- {
- s.write("(unknown local exception)");
- break;
- }
-
- case ReplyStatus.replyUnknownUserException:
- {
- s.write("(unknown user exception)");
- break;
- }
-
- default:
- {
- assert(false);
- break;
- }
- }
-
- String unknown = str.readString();
- s.write("\nunknown = " + unknown);
- break;
- }
-
- default:
- {
- s.write("(unknown)");
- break;
- }
- }
+ printMessage(s, str);
logger.trace(tl.protocolCat, s.toString());
str.pos(p);
@@ -304,6 +170,135 @@ public final class TraceUtil
}
private static void
+ printRequest(java.io.StringWriter s, BasicStream str)
+ {
+ int requestId = str.readInt();
+ s.write("\nrequest id = " + requestId);
+ if(requestId == 0)
+ {
+ s.write(" (oneway)");
+ }
+
+ printRequestHeader(s, str);
+ }
+
+ private static void
+ printBatchRequest(java.io.StringWriter s, BasicStream str)
+ {
+ int batchRequestNum = str.readInt();
+ s.write("\nnumber of requests = " + batchRequestNum);
+
+ for(int i = 0; i < batchRequestNum; ++i)
+ {
+ s.write("\nrequest #" + i + ':');
+ printRequestHeader(s, str);
+ str.skipEncaps();
+ }
+ }
+
+ private static void
+ printReply(java.io.StringWriter s, BasicStream str)
+ {
+ int requestId = str.readInt();
+ s.write("\nrequest id = " + requestId);
+
+ byte replyStatus = str.readByte();
+ s.write("\nreply status = " + (int)replyStatus + ' ');
+
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyOK:
+ {
+ s.write("(ok)");
+ break;
+ }
+
+ case ReplyStatus.replyUserException:
+ {
+ s.write("(user exception)");
+ break;
+ }
+
+ case ReplyStatus.replyObjectNotExist:
+ case ReplyStatus.replyFacetNotExist:
+ case ReplyStatus.replyOperationNotExist:
+ {
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyObjectNotExist:
+ {
+ s.write("(object not exist)");
+ break;
+ }
+
+ case ReplyStatus.replyFacetNotExist:
+ {
+ s.write("(facet not exist)");
+ break;
+ }
+
+ case ReplyStatus.replyOperationNotExist:
+ {
+ s.write("(operation not exist)");
+ break;
+ }
+
+ default:
+ {
+ assert(false);
+ break;
+ }
+ }
+
+ printIdentityFacetOperation(s, str);
+ break;
+ }
+
+ case ReplyStatus.replyUnknownException:
+ case ReplyStatus.replyUnknownLocalException:
+ case ReplyStatus.replyUnknownUserException:
+ {
+ switch(replyStatus)
+ {
+ case ReplyStatus.replyUnknownException:
+ {
+ s.write("(unknown exception)");
+ break;
+ }
+
+ case ReplyStatus.replyUnknownLocalException:
+ {
+ s.write("(unknown local exception)");
+ break;
+ }
+
+ case ReplyStatus.replyUnknownUserException:
+ {
+ s.write("(unknown user exception)");
+ break;
+ }
+
+ default:
+ {
+ assert(false);
+ break;
+ }
+ }
+
+ String unknown = str.readString();
+ s.write("\nunknown = " + unknown);
+ break;
+ }
+
+ default:
+ {
+ s.write("(unknown)");
+ break;
+ }
+ }
+ }
+
+ private static void
printRequestHeader(java.io.Writer out, BasicStream stream)
{
printIdentityFacetOperation(out, stream);
@@ -358,66 +353,28 @@ public final class TraceUtil
}
}
- private static void
+ private static byte
printHeader(java.io.Writer out, BasicStream stream)
{
- try
- {
- byte magic;
- magic = stream.readByte(); // Don't bother printing the magic number
- magic = stream.readByte();
- magic = stream.readByte();
- magic = stream.readByte();
-
- byte pMajor = stream.readByte();
- byte pMinor = stream.readByte();
+ byte magic;
+ magic = stream.readByte(); // Don't bother printing the magic number
+ magic = stream.readByte();
+ magic = stream.readByte();
+ magic = stream.readByte();
+
+ byte pMajor = stream.readByte();
+ byte pMinor = stream.readByte();
// out.write("\nprotocol version = " + (int)pMajor + "." + (int)pMinor);
-
- byte eMajor = stream.readByte();
- byte eMinor = stream.readByte();
+
+ byte eMajor = stream.readByte();
+ byte eMinor = stream.readByte();
// out.write("\nencoding version = " + (int)eMajor + "." + (int)eMinor);
+
+ byte type = stream.readByte();
- byte type = stream.readByte();
- out.write("\nmessage type = " + (int)type + ' ');
- switch(type)
- {
- case Protocol.requestMsg:
- {
- out.write("(request)");
- break;
- }
-
- case Protocol.requestBatchMsg:
- {
- out.write("(batch request)");
- break;
- }
-
- case Protocol.replyMsg:
- {
- out.write("(reply)");
- break;
- }
-
- case Protocol.closeConnectionMsg:
- {
- out.write("(close connection)");
- break;
- }
-
- case Protocol.validateConnectionMsg:
- {
- out.write("(validate connection)");
- break;
- }
-
- default:
- {
- out.write("(unknown)");
- break;
- }
- }
-
+ try
+ {
+ out.write("\nmessage type = " + (int)type + " (" + getMessageTypeAsString(type) + ')');
byte compress = stream.readByte();
out.write("\ncompression status = " + (int)compress + ' ');
switch(compress)
@@ -449,10 +406,73 @@ public final class TraceUtil
int size = stream.readInt();
out.write("\nmessage size = " + size);
+ return type;
}
catch(java.io.IOException ex)
{
assert(false);
+ return 0;
+ }
+ }
+
+ static private byte
+ printMessage(java.io.StringWriter s, BasicStream str)
+ {
+ byte type = printHeader(s, str);
+
+ switch(type)
+ {
+ case Protocol.closeConnectionMsg:
+ case Protocol.validateConnectionMsg:
+ {
+ // We're done.
+ break;
+ }
+
+ case Protocol.requestMsg:
+ {
+ printRequest(s, str);
+ break;
+ }
+
+ case Protocol.requestBatchMsg:
+ {
+ printBatchRequest(s, str);
+ break;
+ }
+
+ case Protocol.replyMsg:
+ {
+ printReply(s, str);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+
+ return type;
+ }
+
+ static private String
+ getMessageTypeAsString(byte type)
+ {
+ switch(type)
+ {
+ case Protocol.requestMsg:
+ return "request";
+ case Protocol.requestBatchMsg:
+ return "batch request";
+ case Protocol.replyMsg:
+ return "reply";
+ case Protocol.closeConnectionMsg:
+ return "close connection";
+ case Protocol.validateConnectionMsg:
+ return "validate connection";
+ default:
+ return "unknown";
}
}
}
diff --git a/java/src/IceInternal/Transceiver.java b/java/src/IceInternal/Transceiver.java
index 260d59bde77..7dce61206b8 100644
--- a/java/src/IceInternal/Transceiver.java
+++ b/java/src/IceInternal/Transceiver.java
@@ -12,23 +12,60 @@ package IceInternal;
public interface Transceiver
{
java.nio.channels.SelectableChannel fd();
+
+ //
+ // Initialize the transceiver.
+ //
+ // Returns the status if the initialize operation. If timeout is != 0,
+ // the status will always be SocketStatus.Finished. If timeout is 0,
+ // the operation won't block and will return SocketStatus.NeedRead or
+ // SocketStatus.NeedWrite if the initialization couldn't be completed
+ // without blocking. This operation should be called again once the
+ // socket is ready for reading or writing and until it returns
+ // SocketStatus.Finished.
+ //
+ SocketStatus initialize(int timeout);
+
void close();
void shutdownWrite();
void shutdownReadWrite();
+
+ //
+ // Write data.
+ //
+ // Returns true if all the data was written, false otherwise. If
+ // timeout is -1, this operation will block until all the data is
+ // written. If timeout is 0, it will return when the write can't
+ // be completed without blocking. If the timeout is > 0, it will
+ // block until all the data is written or the specified timeout
+ // expires.
//
// NOTE: In Java, write() can raise LocalExceptionWrapper to indicate that
// retrying may not be safe, which is necessary to address an issue
// in the IceSSL implementation for JDK 1.4. We can remove this if
// we ever drop support for JDK 1.4 (also see Ice.ConnectionI).
//
- void write(BasicStream stream, int timeout)
+ boolean write(Buffer buf, int timeout)
throws LocalExceptionWrapper;
+
//
- // NOTE: In Java, read() returns a boolean to indicate whether the transceiver
- // has read more data than requested.
+ // Read data.
//
- boolean read(BasicStream stream, int timeout);
+ // Returns true if all the requested data was read, false otherwise.
+ // If timeout is -1, this operation will block until all the data
+ // is read. If timeout is 0, it will return when the read can't be
+ // completed without blocking. If the timeout is > 0, it will
+ // block until all the data is read or the specified timeout
+ // expires.
+ //
+ // NOTE: In Java, read() returns a boolean in moreData to indicate
+ // whether the transceiver has read more data than requested.
+ // If moreData is true, read should be called again without
+ // calling select on the FD.
+ //
+ boolean read(Buffer buf, int timeout, Ice.BooleanHolder moreData);
+
String type();
String toString();
- void checkSendSize(BasicStream stream, int messageSizeMax);
+ void checkSendSize(Buffer buf, int messageSizeMax);
}
diff --git a/java/src/IceInternal/UdpConnector.java b/java/src/IceInternal/UdpConnector.java
index e3c49b6955b..37964024236 100644
--- a/java/src/IceInternal/UdpConnector.java
+++ b/java/src/IceInternal/UdpConnector.java
@@ -11,18 +11,23 @@ package IceInternal;
final class UdpConnector implements Connector, java.lang.Comparable
{
- final static short TYPE = 3;
-
public Transceiver
connect(int timeout)
{
return new UdpTransceiver(_instance, _addr, _mcastInterface, _mcastTtl);
}
+ public java.nio.channels.SelectableChannel
+ fd()
+ {
+ assert(false); // Shouldn't be called, startConnect always completes immediately.
+ return null;
+ }
+
public short
type()
{
- return TYPE;
+ return UdpEndpointI.TYPE;
}
public String
@@ -37,21 +42,6 @@ final class UdpConnector implements Connector, java.lang.Comparable
return _hashCode;
}
- final public boolean
- equivalent(String host, int port)
- {
- java.net.InetSocketAddress addr;
- try
- {
- addr = Network.getAddress(host, port);
- }
- catch(Ice.DNSException ex)
- {
- return false;
- }
- return addr.equals(_addr);
- }
-
//
// Only for use by TcpEndpoint
//
diff --git a/java/src/IceInternal/UdpEndpointI.java b/java/src/IceInternal/UdpEndpointI.java
index a87c6d9bed1..1d635a7dff2 100644
--- a/java/src/IceInternal/UdpEndpointI.java
+++ b/java/src/IceInternal/UdpEndpointI.java
@@ -501,19 +501,16 @@ final class UdpEndpointI extends EndpointI
// Return connectors for this endpoint, or empty list if no connector
// is available.
//
- public java.util.ArrayList
+ public java.util.List
connectors()
{
- java.util.ArrayList connectors = new java.util.ArrayList();
- java.util.ArrayList addresses = Network.getAddresses(_host, _port);
- java.util.Iterator p = addresses.iterator();
- while(p.hasNext())
- {
- connectors.add(
- new UdpConnector(_instance, (java.net.InetSocketAddress)p.next(), _mcastInterface, _mcastTtl,
- _protocolMajor, _protocolMinor, _encodingMajor, _encodingMinor, _connectionId));
- }
- return connectors;
+ return connectors(Network.getAddresses(_host, _port));
+ }
+
+ public void
+ connectors_async(EndpointI_connectors callback)
+ {
+ _instance.endpointHostResolver().resolve(_host, _port, this, callback);
}
//
@@ -534,7 +531,7 @@ final class UdpEndpointI extends EndpointI
// Expand endpoint out in to separate endpoints for each local
// host if listening on INADDR_ANY.
//
- public java.util.ArrayList
+ public java.util.List
expand()
{
java.util.ArrayList endps = new java.util.ArrayList();
@@ -561,21 +558,21 @@ final class UdpEndpointI extends EndpointI
}
//
- // Check whether the endpoint is equivalent to a specific Conenctor.
+ // Check whether the endpoint is equivalent to another one.
//
public boolean
- equivalent(Connector connector)
+ equivalent(EndpointI endpoint)
{
- UdpConnector udpConnector = null;
+ UdpEndpointI udpEndpointI = null;
try
{
- udpConnector = (UdpConnector)connector;
+ udpEndpointI = (UdpEndpointI)endpoint;
}
catch(ClassCastException ex)
{
return false;
}
- return udpConnector.equivalent(_host, _port);
+ return udpEndpointI._host.equals(_host) && udpEndpointI._port == _port;
}
public int
@@ -712,6 +709,20 @@ final class UdpEndpointI extends EndpointI
return false;
}
+ public java.util.List
+ connectors(java.util.List addresses)
+ {
+ java.util.ArrayList connectors = new java.util.ArrayList();
+ java.util.Iterator p = addresses.iterator();
+ while(p.hasNext())
+ {
+ connectors.add(
+ new UdpConnector(_instance, (java.net.InetSocketAddress)p.next(), _mcastInterface, _mcastTtl,
+ _protocolMajor, _protocolMinor, _encodingMajor, _encodingMinor, _connectionId));
+ }
+ return connectors;
+ }
+
private void
calcHashValue()
{
diff --git a/java/src/IceInternal/UdpTransceiver.java b/java/src/IceInternal/UdpTransceiver.java
index 408379547f6..e04d4f0b84b 100644
--- a/java/src/IceInternal/UdpTransceiver.java
+++ b/java/src/IceInternal/UdpTransceiver.java
@@ -18,6 +18,15 @@ final class UdpTransceiver implements Transceiver
return _fd;
}
+ public SocketStatus
+ initialize(int timeout)
+ {
+ //
+ // Nothing to do.
+ //
+ return SocketStatus.Finished;
+ }
+
public synchronized void
close()
{
@@ -38,6 +47,19 @@ final class UdpTransceiver implements Transceiver
}
_readSelector = null;
}
+
+ if(_writeSelector != null)
+ {
+ try
+ {
+ _writeSelector.close();
+ }
+ catch(java.io.IOException ex)
+ {
+ // Ignore.
+ }
+ _writeSelector = null;
+ }
}
public void
@@ -64,17 +86,19 @@ final class UdpTransceiver implements Transceiver
{
_readSelector.wakeup();
}
+ if(_writeSelector != null)
+ {
+ _writeSelector.wakeup();
+ }
}
- public void
- write(BasicStream stream, int timeout) // NOTE: timeout is not used
+ public boolean
+ write(Buffer buf, int timeout)
throws LocalExceptionWrapper
{
- java.nio.ByteBuffer buf = stream.prepareWrite();
-
- assert(buf.position() == 0);
+ assert(buf.b.position() == 0);
final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead);
- if(packetSize < buf.limit())
+ if(packetSize < buf.size())
{
//
// We don't log a warning here because the client gets an exception anyway.
@@ -82,12 +106,52 @@ final class UdpTransceiver implements Transceiver
throw new Ice.DatagramLimitException();
}
- while(buf.hasRemaining())
+ while(buf.b.hasRemaining())
{
try
{
assert(_fd != null);
- int ret = _fd.write(buf);
+
+ int ret = _fd.write(buf.b);
+
+ if(ret == 0)
+ {
+ if(timeout == 0)
+ {
+ return false;
+ }
+
+ synchronized(this)
+ {
+ if(_writeSelector == null)
+ {
+ _writeSelector = java.nio.channels.Selector.open();
+ _fd.register(_writeSelector, java.nio.channels.SelectionKey.OP_WRITE, null);
+ }
+ }
+
+ try
+ {
+ if(timeout > 0)
+ {
+ long start = IceInternal.Time.currentMonotonicTimeMillis();
+ int n = _writeSelector.select(timeout);
+ if(n == 0 && IceInternal.Time.currentMonotonicTimeMillis() >= start + timeout)
+ {
+ throw new Ice.TimeoutException();
+ }
+ }
+ else
+ {
+ _writeSelector.select();
+ }
+ }
+ catch(java.io.InterruptedIOException ex)
+ {
+ // Ignore.
+ }
+ continue;
+ }
if(_traceLevels.network >= 3)
{
@@ -100,7 +164,7 @@ final class UdpTransceiver implements Transceiver
_stats.bytesSent(type(), ret);
}
- assert(ret == buf.limit());
+ assert(ret == buf.b.limit());
break;
}
catch(java.nio.channels.AsynchronousCloseException ex)
@@ -126,15 +190,18 @@ final class UdpTransceiver implements Transceiver
throw se;
}
}
+
+ return true;
}
public boolean
- read(BasicStream stream, int timeout) // NOTE: timeout is not used
+ read(Buffer buf, int timeout, Ice.BooleanHolder moreData)
{
- assert(stream.pos() == 0);
+ assert(buf.b.position() == 0);
+ moreData.value = false;
final int packetSize = java.lang.Math.min(_maxPacketSize, _rcvSize - _udpOverhead);
- if(packetSize < stream.size())
+ if(packetSize < buf.size())
{
//
// We log a warning here because this is the server side -- without the
@@ -146,41 +213,8 @@ final class UdpTransceiver implements Transceiver
}
throw new Ice.DatagramLimitException();
}
- stream.resize(packetSize, true);
- java.nio.ByteBuffer buf = stream.prepareRead();
- buf.position(0);
-
- synchronized(this)
- {
- //
- // Check for shutdown.
- //
- if(_fd == null)
- {
- throw new Ice.ConnectionLostException();
- }
- if(_readSelector == null)
- {
- try
- {
- _readSelector = java.nio.channels.Selector.open();
- _fd.register(_readSelector, java.nio.channels.SelectionKey.OP_READ, null);
- }
- catch(java.io.IOException ex)
- {
- if(Network.connectionLost(ex))
- {
- Ice.ConnectionLostException se = new Ice.ConnectionLostException();
- se.initCause(ex);
- throw se;
- }
-
- Ice.SocketException se = new Ice.SocketException();
- se.initCause(ex);
- throw se;
- }
- }
- }
+ buf.resize(packetSize, true);
+ buf.b.position(0);
int ret = 0;
while(true)
@@ -200,17 +234,48 @@ final class UdpTransceiver implements Transceiver
try
{
- java.net.InetSocketAddress sender = (java.net.InetSocketAddress)fd.receive(buf);
- if(sender == null || buf.position() == 0)
+ java.net.InetSocketAddress sender = (java.net.InetSocketAddress)fd.receive(buf.b);
+
+ if(sender == null || buf.b.position() == 0)
{
- //
- // Wait until packet arrives or socket is closed.
- //
- _readSelector.select();
+ if(timeout == 0)
+ {
+ return false;
+ }
+
+ synchronized(this)
+ {
+ if(_readSelector == null)
+ {
+ _readSelector = java.nio.channels.Selector.open();
+ _fd.register(_readSelector, java.nio.channels.SelectionKey.OP_READ, null);
+ }
+ }
+
+ try
+ {
+ if(timeout > 0)
+ {
+ long start = IceInternal.Time.currentMonotonicTimeMillis();
+ int n = _readSelector.select(timeout);
+ if(n == 0 && IceInternal.Time.currentMonotonicTimeMillis() >= start + timeout)
+ {
+ throw new Ice.TimeoutException();
+ }
+ }
+ else
+ {
+ _readSelector.select();
+ }
+ }
+ catch(java.io.InterruptedIOException ex)
+ {
+ // Ignore.
+ }
continue;
}
- ret = buf.position();
+ ret = buf.b.position();
if(_connect)
{
@@ -272,10 +337,10 @@ final class UdpTransceiver implements Transceiver
_stats.bytesReceived(type(), ret);
}
- stream.resize(ret, true);
- stream.pos(ret);
+ buf.resize(ret, true);
+ buf.b.position(ret);
- return false;
+ return true;
}
public String
@@ -299,14 +364,14 @@ final class UdpTransceiver implements Transceiver
}
public void
- checkSendSize(BasicStream stream, int messageSizeMax)
+ checkSendSize(Buffer buf, int messageSizeMax)
{
- if(stream.size() > messageSizeMax)
+ if(buf.size() > messageSizeMax)
{
throw new Ice.MemoryLimitException();
}
final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead);
- if(packetSize < stream.size())
+ if(packetSize < buf.size())
{
throw new Ice.DatagramLimitException();
}
@@ -608,6 +673,7 @@ final class UdpTransceiver implements Transceiver
private java.nio.channels.DatagramChannel _fd;
private java.net.InetSocketAddress _addr;
private java.nio.channels.Selector _readSelector;
+ private java.nio.channels.Selector _writeSelector;
private boolean mcastServer = false;
//
diff --git a/java/src/IceInternal/UnknownEndpointI.java b/java/src/IceInternal/UnknownEndpointI.java
index 226fe8f4bd0..638a81b52e9 100644
--- a/java/src/IceInternal/UnknownEndpointI.java
+++ b/java/src/IceInternal/UnknownEndpointI.java
@@ -238,12 +238,18 @@ final class UnknownEndpointI extends EndpointI
// Return connectors for this endpoint, or empty list if no connector
// is available.
//
- public java.util.ArrayList
+ public java.util.List
connectors()
{
return new java.util.ArrayList();
}
+ public void
+ connectors_async(EndpointI_connectors callback)
+ {
+ callback.connectors(new java.util.ArrayList());
+ }
+
//
// Return an acceptor for this endpoint, or null if no acceptors
// is available. In case an acceptor is created, this operation
@@ -262,7 +268,7 @@ final class UnknownEndpointI extends EndpointI
// Expand endpoint out in to separate endpoints for each local
// host if listening on INADDR_ANY.
//
- public java.util.ArrayList
+ public java.util.List
expand()
{
java.util.ArrayList endps = new java.util.ArrayList();
@@ -271,10 +277,10 @@ final class UnknownEndpointI extends EndpointI
}
//
- // Check whether the endpoint is equivalent to a specific Conenctor.
+ // Check whether the endpoint is equivalent to another one.
//
public boolean
- equivalent(Connector connector)
+ equivalent(EndpointI endpoint)
{
return false;
}
diff --git a/java/src/IceSSL/AcceptorI.java b/java/src/IceSSL/AcceptorI.java
index 04f2b3331ab..3d1ea382f35 100644
--- a/java/src/IceSSL/AcceptorI.java
+++ b/java/src/IceSSL/AcceptorI.java
@@ -37,14 +37,7 @@ final class AcceptorI implements IceInternal.Acceptor
}
if(fd != null)
{
- try
- {
- fd.close();
- }
- catch(java.io.IOException ex)
- {
- // Ignore.
- }
+ IceInternal.Network.closeSocketNoThrow(fd);
}
if(selector != null)
{
@@ -149,33 +142,6 @@ final class AcceptorI implements IceInternal.Acceptor
}
}
- //
- // Check whether this socket is the result of a call to connectToSelf.
- // Despite the fact that connectToSelf immediately closes the socket,
- // the server-side handshake process does not raise an exception.
- // Furthermore, we can't simply proceed with the regular handshake
- // process because we don't want to pass such a socket to the
- // certificate verifier (if any).
- //
- // In order to detect a call to connectToSelf, we compare the remote
- // address of the newly-accepted socket to that in _connectToSelfAddr.
- //
- java.net.SocketAddress remoteAddr = fd.socket().getRemoteSocketAddress();
- synchronized(this)
- {
- if(remoteAddr.equals(_connectToSelfAddr))
- {
- try
- {
- fd.close();
- }
- catch(java.io.IOException e)
- {
- }
- return null;
- }
- }
-
javax.net.ssl.SSLEngine engine = null;
try
{
@@ -199,24 +165,17 @@ final class AcceptorI implements IceInternal.Acceptor
}
catch(RuntimeException ex)
{
- try
- {
- fd.close();
- }
- catch(java.io.IOException e)
- {
- // Ignore.
- }
+ IceInternal.Network.closeSocketNoThrow(fd);
throw ex;
}
if(_instance.networkTraceLevel() >= 1)
{
- _logger.trace(_instance.networkTraceCategory(), "attempting to accept ssl connection\n" +
+ _logger.trace(_instance.networkTraceCategory(), "accepting ssl connection\n" +
IceInternal.Network.fdToString(fd));
}
- return new TransceiverI(_instance, engine, fd, "", true, _adapterName);
+ return new TransceiverI(_instance, engine, fd, "", true, true, _adapterName);
}
public void
@@ -224,17 +183,8 @@ final class AcceptorI implements IceInternal.Acceptor
{
java.nio.channels.SocketChannel fd = IceInternal.Network.createTcpSocket();
IceInternal.Network.setBlock(fd, false);
- synchronized(this)
- {
- //
- // connectToSelf is called to wake up the thread blocked in
- // accept. We remember the originating address for use in
- // accept. See accept for details.
- //
- IceInternal.Network.doConnect(fd, _addr, -1);
- _connectToSelfAddr = (java.net.InetSocketAddress)fd.socket().getLocalSocketAddress();
- }
- IceInternal.Network.closeSocket(fd);
+ IceInternal.Network.doConnect(fd, _addr, -1);
+ IceInternal.Network.closeSocketNoThrow(fd);
}
public String
@@ -314,5 +264,4 @@ final class AcceptorI implements IceInternal.Acceptor
private int _backlog;
private java.net.InetSocketAddress _addr;
private java.nio.channels.Selector _selector;
- private java.net.InetSocketAddress _connectToSelfAddr;
}
diff --git a/java/src/IceSSL/ConnectorI.java b/java/src/IceSSL/ConnectorI.java
index 9836a78753a..e2d25283302 100644
--- a/java/src/IceSSL/ConnectorI.java
+++ b/java/src/IceSSL/ConnectorI.java
@@ -11,8 +11,6 @@ package IceSSL;
final class ConnectorI implements IceInternal.Connector, java.lang.Comparable
{
- final static short TYPE = 2;
-
public IceInternal.Transceiver
connect(int timeout)
{
@@ -35,73 +33,24 @@ final class ConnectorI implements IceInternal.Connector, java.lang.Comparable
java.nio.channels.SocketChannel fd = IceInternal.Network.createTcpSocket();
IceInternal.Network.setBlock(fd, false);
IceInternal.Network.setTcpBufSize(fd, _instance.communicator().getProperties(), _logger);
- IceInternal.Network.doConnect(fd, _addr, timeout);
+ boolean connected = IceInternal.Network.doConnect(fd, _addr, timeout);
- TransceiverI transceiver = null;
try
{
javax.net.ssl.SSLEngine engine = _instance.createSSLEngine(false);
-
- transceiver = new TransceiverI(_instance, engine, fd, _host, false, "");
-/*
- transceiver.waitForHandshake(timeout);
-
- //
- // Check IceSSL.VerifyPeer.
- //
- int verifyPeer =
- _instance.communicator().getProperties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2);
- if(verifyPeer > 0)
- {
- try
- {
- engine.getSession().getPeerCertificates();
- }
- catch(javax.net.ssl.SSLPeerUnverifiedException ex)
- {
- Ice.SecurityException e = new Ice.SecurityException();
- e.reason = "IceSSL: server did not supply a certificate";
- e.initCause(ex);
- throw e;
- }
- }
-*/
-
-/*
- if(!ctx.verifyPeer(fd, _host, false))
- {
- Ice.SecurityException ex = new Ice.SecurityException();
- ex.reason = "IceSSL: outgoing connection rejected by certificate verifier";
- throw ex;
- }
-*/
+ return new TransceiverI(_instance, engine, fd, _host, connected, false, "");
}
catch(RuntimeException ex)
{
- try
- {
- fd.close();
- }
- catch(java.io.IOException e)
- {
- // Ignore.
- }
+ IceInternal.Network.closeSocketNoThrow(fd);
throw ex;
}
-
- if(_instance.networkTraceLevel() >= 1)
- {
- String s = "ssl connection established\n" + IceInternal.Network.fdToString(fd);
- _logger.trace(_instance.networkTraceCategory(), s);
- }
-
- return transceiver;
}
public short
type()
{
- return TYPE;
+ return EndpointI.TYPE;
}
public String
@@ -116,21 +65,6 @@ final class ConnectorI implements IceInternal.Connector, java.lang.Comparable
return _hashCode;
}
- final boolean
- equivalent(String host, int port)
- {
- java.net.InetSocketAddress addr;
- try
- {
- addr = IceInternal.Network.getAddress(host, port);
- }
- catch(Ice.DNSException ex)
- {
- return false;
- }
- return addr.equals(_addr);
- }
-
//
// Only for use by EndpointI.
//
@@ -211,6 +145,13 @@ final class ConnectorI implements IceInternal.Connector, java.lang.Comparable
return IceInternal.Network.compareAddress(_addr, p._addr);
}
+ protected synchronized void
+ finalize()
+ throws Throwable
+ {
+ super.finalize();
+ }
+
private Instance _instance;
private Ice.Logger _logger;
private String _host;
diff --git a/java/src/IceSSL/EndpointI.java b/java/src/IceSSL/EndpointI.java
index 8cf0f559fa4..f2a66c95f13 100644
--- a/java/src/IceSSL/EndpointI.java
+++ b/java/src/IceSSL/EndpointI.java
@@ -332,17 +332,16 @@ final class EndpointI extends IceInternal.EndpointI
// Return connectors for this endpoint, or empty list if no connector
// is available.
//
- public java.util.ArrayList
+ public java.util.List
connectors()
{
- java.util.ArrayList connectors = new java.util.ArrayList();
- java.util.ArrayList addresses = IceInternal.Network.getAddresses(_host, _port);
- java.util.Iterator p = addresses.iterator();
- while(p.hasNext())
- {
- connectors.add(new ConnectorI(_instance, (java.net.InetSocketAddress)p.next(), _timeout, _connectionId));
- }
- return connectors;
+ return connectors(IceInternal.Network.getAddresses(_host, _port));
+ }
+
+ public void
+ connectors_async(IceInternal.EndpointI_connectors callback)
+ {
+ _instance.endpointHostResolver().resolve(_host, _port, this, callback);
}
//
@@ -364,7 +363,7 @@ final class EndpointI extends IceInternal.EndpointI
// Expand endpoint out in to separate endpoints for each local
// host if listening on INADDR_ANY.
//
- public java.util.ArrayList
+ public java.util.List
expand()
{
java.util.ArrayList endps = new java.util.ArrayList();
@@ -393,18 +392,18 @@ final class EndpointI extends IceInternal.EndpointI
// Check whether the endpoint is equivalent to a specific Connector.
//
public boolean
- equivalent(IceInternal.Connector connector)
+ equivalent(IceInternal.EndpointI endpoint)
{
- ConnectorI sslConnector = null;
+ EndpointI sslEndpointI = null;
try
{
- sslConnector = (ConnectorI)connector;
+ sslEndpointI = (EndpointI)endpoint;
}
catch(ClassCastException ex)
{
return false;
}
- return sslConnector.equivalent(_host, _port);
+ return sslEndpointI._host.equals(_host) && sslEndpointI._port == _port;
}
public int
@@ -490,6 +489,18 @@ final class EndpointI extends IceInternal.EndpointI
return false;
}
+ public java.util.List
+ connectors(java.util.List addresses)
+ {
+ java.util.ArrayList connectors = new java.util.ArrayList();
+ java.util.Iterator p = addresses.iterator();
+ while(p.hasNext())
+ {
+ connectors.add(new ConnectorI(_instance, (java.net.InetSocketAddress)p.next(), _timeout, _connectionId));
+ }
+ return connectors;
+ }
+
private void
calcHashValue()
{
diff --git a/java/src/IceSSL/Instance.java b/java/src/IceSSL/Instance.java
index 0e6bb03a571..9d0251c5c13 100644
--- a/java/src/IceSSL/Instance.java
+++ b/java/src/IceSSL/Instance.java
@@ -507,6 +507,12 @@ class Instance
return _facade.getCommunicator();
}
+ IceInternal.EndpointHostResolver
+ endpointHostResolver()
+ {
+ return _facade.getEndpointHostResolver();
+ }
+
String
defaultHost()
{
@@ -702,6 +708,7 @@ class Instance
return _protocols;
}
+ // TODO: Remove
void
traceConnection(java.nio.channels.SocketChannel fd, javax.net.ssl.SSLEngine engine, boolean incoming)
{
diff --git a/java/src/IceSSL/TransceiverI.java b/java/src/IceSSL/TransceiverI.java
index b43a340c703..94d32b9f881 100644
--- a/java/src/IceSSL/TransceiverI.java
+++ b/java/src/IceSSL/TransceiverI.java
@@ -22,6 +22,48 @@ final class TransceiverI implements IceInternal.Transceiver
return _fd;
}
+ //
+ // All methods that can write to the socket are synchronized.
+ //
+ public synchronized IceInternal.SocketStatus
+ initialize(int timeout)
+ {
+ if(_state == StateNeedConnect && timeout == 0)
+ {
+ _state = StateConnectPending;
+ return IceInternal.SocketStatus.NeedConnect;
+ }
+ else if(_state <= StateConnectPending)
+ {
+ IceInternal.Network.doFinishConnect(_fd, timeout);
+ _state = StateConnected;
+ _desc = IceInternal.Network.fdToString(_fd);
+ }
+ assert(_state == StateConnected);
+
+ IceInternal.SocketStatus status;
+ do
+ {
+ status = handshakeNonBlocking();
+ if(timeout == 0)
+ {
+ return status;
+ }
+
+ if(status != IceInternal.SocketStatus.Finished)
+ {
+ handleSocketStatus(status, timeout);
+ }
+ }
+ while(status != IceInternal.SocketStatus.Finished);
+
+ return status;
+ }
+
+ //
+ // All methods that can write to the socket are synchronized.
+ //
+
public void
close()
{
@@ -78,13 +120,7 @@ final class TransceiverI implements IceInternal.Transceiver
try
{
- _fd.close();
- }
- catch(java.io.IOException ex)
- {
- Ice.SocketException se = new Ice.SocketException();
- se.initCause(ex);
- throw se;
+ IceInternal.Network.closeSocket(_fd);
}
finally
{
@@ -98,6 +134,11 @@ final class TransceiverI implements IceInternal.Transceiver
public synchronized void
shutdownWrite()
{
+ if(_state < StateConnected)
+ {
+ return;
+ }
+
if(_instance.networkTraceLevel() >= 2)
{
String s = "shutting down ssl connection for writing\n" + toString();
@@ -139,6 +180,11 @@ final class TransceiverI implements IceInternal.Transceiver
public synchronized void
shutdownReadWrite()
{
+ if(_state < StateConnected)
+ {
+ return;
+ }
+
if(_instance.networkTraceLevel() >= 2)
{
String s = "shutting down ssl connection for reading and writing\n" + toString();
@@ -178,112 +224,58 @@ final class TransceiverI implements IceInternal.Transceiver
//
// All methods that can write to the socket are synchronized.
//
- public synchronized void
- write(IceInternal.BasicStream stream, int timeout)
+ public synchronized boolean
+ write(IceInternal.Buffer buf, int timeout)
throws IceInternal.LocalExceptionWrapper
{
- //
- // Complete handshaking first if necessary.
- //
- if(!_handshakeComplete)
- {
- handshake(timeout);
- }
-
- ByteBuffer buf = stream.prepareWrite();
+ assert(_state == StateHandshakeComplete);
- //
- // Write any pending data to the socket.
- //
- flush(timeout);
-
- try
+ IceInternal.SocketStatus status;
+ do
{
- while(buf.hasRemaining())
+ status = writeNonBlocking(buf.b);
+ if(status != IceInternal.SocketStatus.Finished)
{
- final int rem = buf.remaining();
-
- //
- // Encrypt the buffer.
- //
- SSLEngineResult result = _engine.wrap(buf, _netOutput);
- switch(result.getStatus())
+ if(timeout == 0)
{
- case BUFFER_OVERFLOW:
- assert(false);
- break;
- case BUFFER_UNDERFLOW:
- assert(false);
- break;
- case CLOSED:
- throw new Ice.ConnectionLostException();
- case OK:
- break;
+ assert(status == IceInternal.SocketStatus.NeedWrite);
+ return false;
}
- //
- // Write the encrypted data to the socket.
- //
- if(result.bytesProduced() > 0)
- {
- flush(timeout);
-
- if(_instance.networkTraceLevel() >= 3)
- {
- String s = "sent " + result.bytesConsumed() + " of " + rem + " bytes via ssl\n" + toString();
- _logger.trace(_instance.networkTraceCategory(), s);
- }
-
- if(_stats != null)
- {
- _stats.bytesSent(type(), result.bytesConsumed());
- }
- }
+ handleSocketStatus(status, timeout);
}
- }
- catch(SSLException ex)
- {
- Ice.SecurityException e = new Ice.SecurityException();
- e.reason = "IceSSL: error while encoding message";
- e.initCause(ex);
- throw e;
- }
+ }
+ while(status != IceInternal.SocketStatus.Finished);
+
+ return true;
}
public boolean
- read(IceInternal.BasicStream stream, int timeout)
+ read(IceInternal.Buffer buf, int timeout, Ice.BooleanHolder moreData)
{
- ByteBuffer buf = stream.prepareRead();
+ assert(_state == StateHandshakeComplete);
int rem = 0;
if(_instance.networkTraceLevel() >= 3)
{
- rem = buf.remaining();
- }
-
- //
- // Complete handshaking first if necessary.
- //
- if(!_handshakeComplete)
- {
- handshake(timeout);
+ rem = buf.b.remaining();
}
//
// Try to satisfy the request from data we've already decrypted.
//
- int pos = buf.position();
- fill(buf);
+ int pos = buf.b.position();
+ fill(buf.b);
- if(_instance.networkTraceLevel() >= 3 && buf.position() > pos)
+ if(_instance.networkTraceLevel() >= 3 && buf.b.position() > pos)
{
- String s = "received " + (buf.position() - pos) + " of " + rem + " bytes via ssl\n" + toString();
+ String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via ssl\n" + toString();
_logger.trace(_instance.networkTraceCategory(), s);
}
- if(_stats != null && buf.position() > pos)
+ if(_stats != null && buf.b.position() > pos)
{
- _stats.bytesReceived(type(), buf.position() - pos);
+ _stats.bytesReceived(type(), buf.b.position() - pos);
}
//
@@ -293,7 +285,7 @@ final class TransceiverI implements IceInternal.Transceiver
//
try
{
- while(buf.hasRemaining())
+ while(buf.b.hasRemaining())
{
_netInput.flip();
SSLEngineResult result = _engine.unwrap(_netInput, _appInput);
@@ -301,29 +293,53 @@ final class TransceiverI implements IceInternal.Transceiver
switch(result.getStatus())
{
case BUFFER_OVERFLOW:
+ {
assert(false);
break;
+ }
case BUFFER_UNDERFLOW:
- read(timeout);
+ {
+ IceInternal.SocketStatus status;
+ do
+ {
+ status = readNonBlocking();
+ if(status != IceInternal.SocketStatus.Finished)
+ {
+ if(timeout == 0)
+ {
+ assert(status == IceInternal.SocketStatus.NeedRead);
+ moreData.value = false;
+ return false;
+ }
+
+ handleSocketStatus(status, timeout);
+ }
+ }
+ while(status != IceInternal.SocketStatus.Finished);
continue;
+ }
case CLOSED:
+ {
throw new Ice.ConnectionLostException();
+ }
case OK:
+ {
break;
}
+ }
- pos = buf.position();
- fill(buf);
+ pos = buf.b.position();
+ fill(buf.b);
- if(_instance.networkTraceLevel() >= 3 && buf.position() > pos)
+ if(_instance.networkTraceLevel() >= 3 && buf.b.position() > pos)
{
- String s = "received " + (buf.position() - pos) + " of " + rem + " bytes via ssl\n" + toString();
+ String s = "received " + (buf.b.position() - pos) + " of " + rem + " bytes via ssl\n" + toString();
_logger.trace(_instance.networkTraceCategory(), s);
}
- if(_stats != null && buf.position() > pos)
+ if(_stats != null && buf.b.position() > pos)
{
- _stats.bytesReceived(type(), buf.position() - pos);
+ _stats.bytesReceived(type(), buf.b.position() - pos);
}
}
}
@@ -338,7 +354,8 @@ final class TransceiverI implements IceInternal.Transceiver
//
// Return a boolean to indicate whether more data is available.
//
- return _netInput.position() > 0;
+ moreData.value = _netInput.position() > 0;
+ return true;
}
public String
@@ -354,9 +371,9 @@ final class TransceiverI implements IceInternal.Transceiver
}
public void
- checkSendSize(IceInternal.BasicStream stream, int messageSizeMax)
+ checkSendSize(IceInternal.Buffer buf, int messageSizeMax)
{
- if(stream.size() > messageSizeMax)
+ if(buf.size() > messageSizeMax)
{
throw new Ice.MemoryLimitException();
}
@@ -376,7 +393,7 @@ final class TransceiverI implements IceInternal.Transceiver
// Only for use by ConnectorI, AcceptorI.
//
TransceiverI(Instance instance, javax.net.ssl.SSLEngine engine, java.nio.channels.SocketChannel fd,
- String host, boolean incoming, String adapterName)
+ String host, boolean connected, boolean incoming, String adapterName)
{
_instance = instance;
_engine = engine;
@@ -384,6 +401,7 @@ final class TransceiverI implements IceInternal.Transceiver
_host = host;
_adapterName = adapterName;
_incoming = incoming;
+ _state = connected ? StateConnected : StateNeedConnect;
_logger = instance.communicator().getLogger();
try
{
@@ -409,11 +427,9 @@ final class TransceiverI implements IceInternal.Transceiver
}
}
- // TODO: Buffer cache?
_appInput = ByteBuffer.allocateDirect(engine.getSession().getApplicationBufferSize() * 2);
_netInput = ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize() * 2);
_netOutput = ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize() * 2);
- _handshakeComplete = false;
}
protected void
@@ -425,185 +441,13 @@ final class TransceiverI implements IceInternal.Transceiver
super.finalize();
}
- private void
- flush(int timeout)
- {
- _netOutput.flip();
-
- int size = _netOutput.limit();
- int packetSize = 0;
- if(_maxPacketSize > 0 && size > _maxPacketSize)
- {
- packetSize = _maxPacketSize;
- _netOutput.limit(_netOutput.position() + packetSize);
- }
-
- while(_netOutput.hasRemaining())
- {
- try
- {
- assert(_fd != null);
- int ret = _fd.write(_netOutput);
-
- if(ret == -1)
- {
- throw new Ice.ConnectionLostException();
- }
-
- if(ret == 0)
- {
- if(timeout == 0)
- {
- throw new Ice.TimeoutException();
- }
-
- if(_writeSelector == null)
- {
- _writeSelector = java.nio.channels.Selector.open();
- _fd.register(_writeSelector, java.nio.channels.SelectionKey.OP_WRITE, null);
- }
-
- try
- {
- if(timeout > 0)
- {
- long start = System.currentTimeMillis();
- int n = _writeSelector.select(timeout);
- if(n == 0 && System.currentTimeMillis() >= start + timeout)
- {
- throw new Ice.TimeoutException();
- }
- }
- else
- {
- _writeSelector.select();
- }
- }
- catch(java.io.InterruptedIOException ex)
- {
- // Ignore.
- }
-
- continue;
- }
- }
- catch(java.io.InterruptedIOException ex)
- {
- continue;
- }
- catch(java.io.IOException ex)
- {
- if(IceInternal.Network.connectionLost(ex))
- {
- Ice.ConnectionLostException se = new Ice.ConnectionLostException();
- se.initCause(ex);
- throw se;
- }
-
- Ice.SocketException se = new Ice.SocketException();
- se.initCause(ex);
- throw se;
- }
-
- if(packetSize > 0)
- {
- assert(_netOutput.position() == _netOutput.limit());
- int position = _netOutput.position();
- if(size - position > packetSize)
- {
- _netOutput.limit(position + packetSize);
- }
- else
- {
- packetSize = 0;
- _netOutput.limit(size);
- }
- }
- }
- _netOutput.clear();
- }
-
- private void
- read(int timeout)
- {
- while(true)
- {
- try
- {
- assert(_fd != null);
- int ret = _fd.read(_netInput);
-
- if(ret == -1)
- {
- throw new Ice.ConnectionLostException();
- }
-
- if(ret == 0)
- {
- if(timeout == 0)
- {
- throw new Ice.TimeoutException();
- }
-
- if(_readSelector == null)
- {
- _readSelector = java.nio.channels.Selector.open();
- _fd.register(_readSelector, java.nio.channels.SelectionKey.OP_READ, null);
- }
-
- try
- {
- if(timeout > 0)
- {
- long start = System.currentTimeMillis();
- int n = _readSelector.select(timeout);
- if(n == 0 && System.currentTimeMillis() >= start + timeout)
- {
- throw new Ice.TimeoutException();
- }
- }
- else
- {
- _readSelector.select();
- }
- }
- catch(java.io.InterruptedIOException ex)
- {
- // Ignore.
- }
-
- continue;
- }
-
- break;
- }
- catch(java.io.InterruptedIOException ex)
- {
- continue;
- }
- catch(java.io.IOException ex)
- {
- if(IceInternal.Network.connectionLost(ex))
- {
- Ice.ConnectionLostException se = new Ice.ConnectionLostException();
- se.initCause(ex);
- throw se;
- }
-
- Ice.SocketException se = new Ice.SocketException();
- se.initCause(ex);
- throw se;
- }
- }
- }
-
- private void
- handshake(int timeout)
+ private IceInternal.SocketStatus
+ handshakeNonBlocking()
{
try
{
HandshakeStatus status = _engine.getHandshakeStatus();
- while(!_handshakeComplete)
+ while(_state != StateHandshakeComplete)
{
SSLEngineResult result = null;
switch(status)
@@ -613,7 +457,6 @@ final class TransceiverI implements IceInternal.Transceiver
break;
case NEED_TASK:
{
- // TODO: Use separate threads & join with timeout?
Runnable task;
while((task = _engine.getDelegatedTask()) != null)
{
@@ -642,9 +485,15 @@ final class TransceiverI implements IceInternal.Transceiver
assert(false);
break;
case BUFFER_UNDERFLOW:
+ {
assert(status == javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
- read(timeout);
+ IceInternal.SocketStatus ss = readNonBlocking();
+ if(ss != IceInternal.SocketStatus.Finished)
+ {
+ return ss;
+ }
break;
+ }
case CLOSED:
throw new Ice.ConnectionLostException();
case OK:
@@ -660,7 +509,11 @@ final class TransceiverI implements IceInternal.Transceiver
result = _engine.wrap(_emptyBuffer, _netOutput);
if(result.bytesProduced() > 0)
{
- flush(timeout);
+ IceInternal.SocketStatus ss = flushNonBlocking();
+ if(ss != IceInternal.SocketStatus.Finished)
+ {
+ return ss;
+ }
}
//
// FINISHED is only returned from wrap or unwrap, not from engine.getHandshakeResult().
@@ -699,6 +552,314 @@ final class TransceiverI implements IceInternal.Transceiver
e.initCause(ex);
throw e;
}
+
+ return IceInternal.SocketStatus.Finished;
+ }
+
+ private void
+ handshakeCompleted()
+ {
+ _state = StateHandshakeComplete;
+
+ //
+ // IceSSL.VerifyPeer is translated into the proper SSLEngine configuration
+ // for a server, but we have to do it ourselves for a client.
+ //
+ if(!_incoming)
+ {
+ int verifyPeer =
+ _instance.communicator().getProperties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2);
+ if(verifyPeer > 0)
+ {
+ try
+ {
+ _engine.getSession().getPeerCertificates();
+ }
+ catch(javax.net.ssl.SSLPeerUnverifiedException ex)
+ {
+ Ice.SecurityException e = new Ice.SecurityException();
+ e.reason = "IceSSL: server did not supply a certificate";
+ e.initCause(ex);
+ throw e;
+ }
+ }
+ }
+
+ //
+ // Additional verification.
+ //
+ _info = Util.populateConnectionInfo(_engine.getSession(), _fd.socket(), _adapterName, _incoming);
+ _instance.verifyPeer(_info, _fd, _host, _incoming);
+
+ if(_instance.networkTraceLevel() >= 1)
+ {
+ String s;
+ if(_incoming)
+ {
+ s = "accepted ssl connection\n" + _desc;
+ }
+ else
+ {
+ s = "ssl connection established\n" + _desc;
+ }
+ _logger.trace(_instance.networkTraceCategory(), s);
+ }
+
+ if(_instance.securityTraceLevel() >= 1)
+ {
+ _instance.traceConnection(_fd, _engine, _incoming);
+ }
+ }
+
+ private void
+ shutdown()
+ {
+ //
+ // Send the close_notify message.
+ //
+ _engine.closeOutbound();
+ try
+ {
+ _netOutput.clear();
+ while(!_engine.isOutboundDone())
+ {
+ _engine.wrap(_emptyBuffer, _netOutput);
+ try
+ {
+ //
+ // We can't block to send the close_notify message as this is called from
+ // shutdownWrite and shutdownReadWrite which aren't suppose to block. In
+ // some cases, the close_notify message might therefore not be receieved
+ // by the peer. This is not a big issue since the Ice protocol isn't
+ // subject to truncation attacks.
+ //
+// IceInternal.SocketStatus status;
+// do
+// {
+// status = flushNonBlocking();
+// if(status != IceInternal.SocketStatus.Finished)
+// {
+// handleSocketStatus(status, -1); // TODO: Is waiting indefinitely really correct?
+// }
+// }
+// while(status != IceInternal.SocketStatus.Finished);
+ flushNonBlocking();
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ // Ignore.
+ }
+ }
+ }
+ catch(SSLException ex)
+ {
+ Ice.SecurityException se = new Ice.SecurityException();
+ se.reason = "IceSSL: SSL failure while shutting down socket";
+ se.initCause(ex);
+ throw se;
+ }
+ }
+
+ private IceInternal.SocketStatus
+ writeNonBlocking(ByteBuffer buf)
+ {
+ //
+ // This method has two purposes: encrypt the application's message buffer into our
+ // _netOutput buffer, and write the contents of _netOutput to the socket without
+ // blocking.
+ //
+ try
+ {
+ while(buf.hasRemaining() || _netOutput.position() > 0)
+ {
+ final int rem = buf.remaining();
+
+ if(rem > 0)
+ {
+ //
+ // Encrypt the buffer.
+ //
+ SSLEngineResult result = _engine.wrap(buf, _netOutput);
+ switch(result.getStatus())
+ {
+ case BUFFER_OVERFLOW:
+ //
+ // Need to make room in _netOutput.
+ //
+ break;
+ case BUFFER_UNDERFLOW:
+ assert(false);
+ break;
+ case CLOSED:
+ throw new Ice.ConnectionLostException();
+ case OK:
+ break;
+ }
+
+ //
+ // If the SSL engine consumed any of the application's message buffer,
+ // then log it.
+ //
+ if(result.bytesConsumed() > 0)
+ {
+ if(_instance.networkTraceLevel() >= 3)
+ {
+ String s = "sent " + result.bytesConsumed() + " of " + rem + " bytes via ssl\n" +
+ toString();
+ _logger.trace(_instance.networkTraceCategory(), s);
+ }
+
+ if(_stats != null)
+ {
+ _stats.bytesSent(type(), result.bytesConsumed());
+ }
+ }
+ }
+
+ //
+ // Write the encrypted data to the socket. We continue writing until we've written
+ // all of _netOutput, or until flushNonBlocking indicates that it cannot write
+ // (i.e., by returning NeedWrite).
+ //
+ if(_netOutput.position() > 0)
+ {
+ IceInternal.SocketStatus ss = flushNonBlocking();
+ if(ss != IceInternal.SocketStatus.Finished)
+ {
+ assert(ss == IceInternal.SocketStatus.NeedWrite);
+ return ss;
+ }
+ }
+ }
+ }
+ catch(SSLException ex)
+ {
+ Ice.SecurityException e = new Ice.SecurityException();
+ e.reason = "IceSSL: error while encoding message";
+ e.initCause(ex);
+ throw e;
+ }
+
+ assert(_netOutput.position() == 0);
+ return IceInternal.SocketStatus.Finished;
+ }
+
+ private IceInternal.SocketStatus
+ flushNonBlocking()
+ {
+ _netOutput.flip();
+
+ final int size = _netOutput.limit();
+ int packetSize = size - _netOutput.position();
+ if(_maxPacketSize > 0 && packetSize > _maxPacketSize)
+ {
+ packetSize = _maxPacketSize;
+ _netOutput.limit(_netOutput.position() + packetSize);
+ }
+
+ IceInternal.SocketStatus status = IceInternal.SocketStatus.Finished;
+ while(_netOutput.hasRemaining())
+ {
+ try
+ {
+ assert(_fd != null);
+ int ret = _fd.write(_netOutput);
+
+ if(ret == -1)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ else if(ret == 0)
+ {
+ status = IceInternal.SocketStatus.NeedWrite;
+ break;
+ }
+
+ if(packetSize == _maxPacketSize)
+ {
+ assert(_netOutput.position() == _netOutput.limit());
+ packetSize = size - _netOutput.position();
+ if(packetSize > _maxPacketSize)
+ {
+ packetSize = _maxPacketSize;
+ }
+ _netOutput.limit(_netOutput.position() + packetSize);
+ }
+ }
+ catch(java.io.InterruptedIOException ex)
+ {
+ continue;
+ }
+ catch(java.io.IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ Ice.ConnectionLostException se = new Ice.ConnectionLostException();
+ se.initCause(ex);
+ throw se;
+ }
+
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
+
+ if(status == IceInternal.SocketStatus.Finished)
+ {
+ _netOutput.clear();
+ }
+ else
+ {
+ _netOutput.limit(size);
+ _netOutput.compact();
+ }
+
+ return status;
+ }
+
+
+ private IceInternal.SocketStatus
+ readNonBlocking()
+ {
+ while(true)
+ {
+ try
+ {
+ assert(_fd != null);
+ int ret = _fd.read(_netInput);
+
+ if(ret == -1)
+ {
+ throw new Ice.ConnectionLostException();
+ }
+ else if(ret == 0)
+ {
+ return IceInternal.SocketStatus.NeedRead;
+ }
+
+ break;
+ }
+ catch(java.io.InterruptedIOException ex)
+ {
+ continue;
+ }
+ catch(java.io.IOException ex)
+ {
+ if(IceInternal.Network.connectionLost(ex))
+ {
+ Ice.ConnectionLostException se = new Ice.ConnectionLostException();
+ se.initCause(ex);
+ throw se;
+ }
+
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
+ }
+ }
+
+ return IceInternal.SocketStatus.Finished;
}
private void
@@ -747,89 +908,70 @@ final class TransceiverI implements IceInternal.Transceiver
}
private void
- shutdown()
+ handleSocketStatus(IceInternal.SocketStatus status, int timeout)
{
- //
- // Send the close_notify message.
- //
- _engine.closeOutbound();
+ assert(timeout != 0);
try
{
- _netOutput.clear();
- while(!_engine.isOutboundDone())
+ java.nio.channels.Selector selector;
+ if(status == IceInternal.SocketStatus.NeedRead)
{
- _engine.wrap(_emptyBuffer, _netOutput);
- try
+ if(_readSelector == null)
{
- flush(-1);
+ _readSelector = java.nio.channels.Selector.open();
+ _fd.register(_readSelector, java.nio.channels.SelectionKey.OP_READ, null);
}
- catch(Ice.ConnectionLostException ex)
+ selector = _readSelector;
+ }
+ else
+ {
+ assert(status == IceInternal.SocketStatus.NeedWrite);
+ if(_writeSelector == null)
{
- // Ignore.
+ _writeSelector = java.nio.channels.Selector.open();
+ _fd.register(_writeSelector, java.nio.channels.SelectionKey.OP_WRITE, null);
}
+ selector = _writeSelector;
}
- }
- catch(SSLException ex)
- {
- Ice.SecurityException se = new Ice.SecurityException();
- se.reason = "IceSSL: SSL failure while shutting down socket";
- se.initCause(ex);
- throw se;
- }
- }
- private void
- handshakeCompleted()
- {
- _handshakeComplete = true;
-
- //
- // IceSSL.VerifyPeer is translated into the proper SSLEngine configuration
- // for a server, but we have to do it ourselves for a client.
- //
- if(!_incoming)
- {
- int verifyPeer =
- _instance.communicator().getProperties().getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2);
- if(verifyPeer > 0)
+ while(true)
{
try
{
- _engine.getSession().getPeerCertificates();
+ if(timeout > 0)
+ {
+ long start = System.currentTimeMillis();
+ int n = selector.select(timeout);
+ if(n == 0 && System.currentTimeMillis() >= start + timeout)
+ {
+ throw new Ice.TimeoutException();
+ }
+ }
+ else
+ {
+ selector.select();
+ }
+
+ break;
}
- catch(javax.net.ssl.SSLPeerUnverifiedException ex)
+ catch(java.io.InterruptedIOException ex)
{
- Ice.SecurityException e = new Ice.SecurityException();
- e.reason = "IceSSL: server did not supply a certificate";
- e.initCause(ex);
- throw e;
+ // Ignore.
}
}
}
-
- //
- // Additional verification.
- //
- _info = Util.populateConnectionInfo(_engine.getSession(), _fd.socket(), _adapterName, _incoming);
- _instance.verifyPeer(_info, _fd, _host, _incoming);
-
- if(_instance.networkTraceLevel() >= 1)
+ catch(java.io.IOException ex)
{
- String s;
- if(_incoming)
- {
- s = "accepted ssl connection\n" + IceInternal.Network.fdToString(_fd);
- }
- else
+ if(IceInternal.Network.connectionLost(ex))
{
- s = "ssl connection established\n" + IceInternal.Network.fdToString(_fd);
+ Ice.ConnectionLostException se = new Ice.ConnectionLostException();
+ se.initCause(ex);
+ throw se;
}
- _logger.trace(_instance.networkTraceCategory(), s);
- }
- if(_instance.securityTraceLevel() >= 1)
- {
- _instance.traceConnection(_fd, _engine, _incoming);
+ Ice.SocketException se = new Ice.SocketException();
+ se.initCause(ex);
+ throw se;
}
}
@@ -839,6 +981,7 @@ final class TransceiverI implements IceInternal.Transceiver
private String _host;
private String _adapterName;
private boolean _incoming;
+ private int _state;
private Ice.Logger _logger;
private Ice.Stats _stats;
private String _desc;
@@ -847,8 +990,12 @@ final class TransceiverI implements IceInternal.Transceiver
private ByteBuffer _netInput; // Holds encrypted data read from the socket.
private ByteBuffer _netOutput; // Holds encrypted data to be written to the socket.
private static ByteBuffer _emptyBuffer = ByteBuffer.allocate(0); // Used during handshaking.
- private boolean _handshakeComplete;
private java.nio.channels.Selector _readSelector;
private java.nio.channels.Selector _writeSelector;
private ConnectionInfo _info;
+
+ private static final int StateNeedConnect = 0;
+ private static final int StateConnectPending = 1;
+ private static final int StateConnected = 2;
+ private static final int StateHandshakeComplete = 3;
}