// **********************************************************************
//
// Copyright (c) 2003-2010 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 final class ConnectionI extends IceInternal.EventHandler implements Connection
{
public interface StartCallback
{
void connectionStartCompleted(ConnectionI connection);
void connectionStartFailed(ConnectionI connection, Ice.LocalException ex);
}
private class TimeoutCallback implements IceInternal.TimerTask
{
public void
runTimerTask()
{
timedOut();
}
}
public void
start(StartCallback callback)
{
try
{
synchronized(this)
{
if(_state >= StateClosed) // The connection might already be closed if the communicator was destroyed.
{
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(!initialize(IceInternal.SocketOperation.None) || !validate(IceInternal.SocketOperation.None))
{
if(callback != null)
{
_startCallback = callback;
return;
}
//
// Wait for the connection to be validated.
//
while(_state <= StateNotValidated)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
if(_state >= StateClosing)
{
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
}
//
// We start out in holding state.
//
setState(StateHolding);
}
}
catch(Ice.LocalException ex)
{
exception(ex);
if(callback != null)
{
callback.connectionStartFailed(this, _exception);
return;
}
else
{
waitUntilFinished();
throw ex;
}
}
if(callback != null)
{
callback.connectionStartCompleted(this);
}
}
public synchronized void
activate()
{
if(_state <= StateNotValidated)
{
return;
}
if(_acmTimeout > 0)
{
_acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
}
setState(StateActive);
}
public synchronized void
hold()
{
if(_state <= StateNotValidated)
{
return;
}
setState(StateHolding);
}
// DestructionReason.
public final static int ObjectAdapterDeactivated = 0;
public final static int CommunicatorDestroyed = 1;
synchronized public void
destroy(int reason)
{
switch(reason)
{
case ObjectAdapterDeactivated:
{
setState(StateClosing, new ObjectAdapterDeactivatedException());
break;
}
case CommunicatorDestroyed:
{
setState(StateClosing, new CommunicatorDestroyedException());
break;
}
}
}
synchronized public void
close(boolean force)
{
if(force)
{
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)
{
}
}
setState(StateClosing, new CloseConnectionException());
}
}
public synchronized boolean
isActiveOrHolding()
{
return _state > StateNotValidated && _state < StateClosing;
}
public synchronized boolean
isFinished()
{
if(_state != StateFinished || _dispatchCount != 0)
{
return false;
}
assert(_state == StateFinished);
return true;
}
public synchronized void
throwException()
{
if(_exception != null)
{
assert(_state >= StateClosing);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
}
public synchronized void
waitUntilHolding()
{
while(_state < StateHolding || _dispatchCount > 0)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
}
public synchronized void
waitUntilFinished()
{
//
// We wait indefinitely until the connection is finished and all
// outstanding requests are completed. Otherwise we couldn't
// guarantee that there are no outstanding calls when deactivate()
// is called on the servant locators.
//
while(_state < StateFinished || _dispatchCount > 0)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
assert(_state == StateFinished);
//
// Clear the OA. See bug 1673 for the details of why this is necessary.
//
_adapter = null;
}
synchronized public void
monitor(long now)
{
if(_state != StateActive)
{
return;
}
//
// Active connection management for idle connections.
//
if(_acmTimeout <= 0 ||
!_requests.isEmpty() || !_asyncRequests.isEmpty() || _dispatchCount > 0 ||
_readStream.size() > IceInternal.Protocol.headerSize || !_writeStream.isEmpty() || !_batchStream.isEmpty())
{
return;
}
if(now >= _acmAbsoluteTimeoutMillis)
{
setState(StateClosing, new ConnectionTimeoutException());
}
}
synchronized public boolean
sendRequest(IceInternal.Outgoing out, boolean compress, boolean response)
throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
final IceInternal.BasicStream os = out.os();
if(_exception != null)
{
//
// If the connection is closed before we even have a chance
// to send our request, we always try to send the request
// again.
//
throw new IceInternal.LocalExceptionWrapper((Ice.LocalException)_exception.fillInStackTrace(), true);
}
assert(_state > StateNotValidated);
assert(_state < StateClosing);
//
// Ensure the message isn't bigger than what we can send with the
// transport.
//
_transceiver.checkSendSize(os.getBuffer(), _instance.messageSizeMax());
if(response)
{
//
// 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);
}
//
// 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.
//
boolean sent = false;
try
{
OutgoingMessage message = new OutgoingMessage(out, out.os(), compress, requestId);
sent = (sendMessage(message) & IceInternal.AsyncStatus.Sent) > 0;
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(response)
{
//
// Add to the requests map.
//
_requests.put(requestId, out);
}
return sent; // The request was sent.
}
synchronized public int
sendAsyncRequest(IceInternal.OutgoingAsync out, boolean compress, boolean response)
throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
final IceInternal.BasicStream os = out.__os();
if(_exception != null)
{
//
// If the connection is closed before we even have a chance
// to send our request, we always try to send the request
// again.
//
throw new IceInternal.LocalExceptionWrapper((Ice.LocalException)_exception.fillInStackTrace(), true);
}
assert(_state > StateNotValidated);
assert(_state < StateClosing);
//
// Ensure the message isn't bigger than what we can send with the
// transport.
//
_transceiver.checkSendSize(os.getBuffer(), _instance.messageSizeMax());
if(response)
{
//
// 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);
}
int status;
try
{
status = sendMessage(new OutgoingMessage(out, out.__os(), compress, requestId));
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(response)
{
//
// Add to the async requests map.
//
_asyncRequests.put(requestId, out);
}
return status;
}
public synchronized void
prepareBatchRequest(IceInternal.BasicStream os)
throws IceInternal.LocalExceptionWrapper
{
//
// Wait if flushing is currently in progress.
//
while(_batchStreamInUse && _exception == null)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
if(_exception != null)
{
//
// If there were no batch requests queued when the connection failed, we can safely
// retry with a new connection. Otherwise, we must throw to notify the caller that
// some previous batch requests were not sent.
//
if(_batchStream.isEmpty())
{
throw new IceInternal.LocalExceptionWrapper((Ice.LocalException)_exception.fillInStackTrace(), true);
}
else
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
}
assert(_state > StateNotValidated);
assert(_state < StateClosing);
if(_batchStream.isEmpty())
{
try
{
_batchStream.writeBlob(IceInternal.Protocol.requestBatchHdr);
}
catch(LocalException ex)
{
setState(StateClosed, ex);
throw ex;
}
}
_batchStreamInUse = true;
_batchMarker = _batchStream.size();
_batchStream.swap(os);
//
// The batch stream now belongs to the caller, until
// finishBatchRequest() or abortBatchRequest() is called.
//
}
public void
finishBatchRequest(IceInternal.BasicStream os, boolean compress)
{
try
{
synchronized(this)
{
//
// Get the batch stream back.
//
_batchStream.swap(os);
if(_exception != null)
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
boolean flush = false;
if(_batchAutoFlush)
{
//
// 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.getBuffer(), _instance.messageSizeMax());
}
catch(Ice.LocalException ex)
{
if(_batchRequestNum > 0)
{
flush = true;
}
else
{
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);
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);
sendMessage(message);
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
//
// 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())
{
IceInternal.Ex.throwMemoryLimitException(
IceInternal.Protocol.requestBatchHdr.length + lastRequest.length,
_instance.messageSizeMax());
}
//
// Start a new batch with the last message that caused us to go over the limit.
//
_batchStream.writeBlob(IceInternal.Protocol.requestBatchHdr);
_batchStream.writeBlob(lastRequest);
}
//
// Increment the number of requests in the batch.
//
++_batchRequestNum;
//
// We compress the whole batch if there is at least one compressed
// message.
//
if(compress)
{
_batchRequestCompress = true;
}
//
// Notify about the batch stream not being in use anymore.
//
assert(_batchStreamInUse);
_batchStreamInUse = false;
notifyAll();
}
}
catch(Ice.LocalException ex)
{
abortBatchRequest();
throw ex;
}
}
public synchronized void
abortBatchRequest()
{
_batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
_batchRequestNum = 0;
_batchRequestCompress = false;
_batchMarker = 0;
assert(_batchStreamInUse);
_batchStreamInUse = false;
notifyAll();
}
public void
flushBatchRequests()
{
IceInternal.BatchOutgoing out = new IceInternal.BatchOutgoing(this, _instance);
out.invoke();
}
private static final String __flushBatchRequests_name = "flushBatchRequests";
public Ice.AsyncResult
begin_flushBatchRequests()
{
return begin_flushBatchRequestsInternal(null);
}
public Ice.AsyncResult
begin_flushBatchRequests(Callback cb)
{
return begin_flushBatchRequestsInternal(cb);
}
public Ice.AsyncResult
begin_flushBatchRequests(Callback_Connection_flushBatchRequests cb)
{
return begin_flushBatchRequestsInternal(cb);
}
private Ice.AsyncResult
begin_flushBatchRequestsInternal(IceInternal.CallbackBase cb)
{
IceInternal.ConnectionBatchOutgoingAsync result =
new IceInternal.ConnectionBatchOutgoingAsync(this, _instance, __flushBatchRequests_name, cb);
try
{
result.__send();
}
catch(LocalException __ex)
{
result.__exceptionAsync(__ex);
}
return result;
}
public void
end_flushBatchRequests(AsyncResult r)
{
AsyncResult.__check(r, this, __flushBatchRequests_name);
r.__wait();
}
synchronized public boolean
flushBatchRequests(IceInternal.BatchOutgoing out)
{
while(_batchStreamInUse && _exception == null)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
if(_exception != null)
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(_batchRequestNum == 0)
{
out.sent(false);
return true;
}
//
// Fill in the number of requests in the batch.
//
_batchStream.pos(IceInternal.Protocol.headerSize);
_batchStream.writeInt(_batchRequestNum);
_batchStream.swap(out.os());
boolean sent = false;
try
{
OutgoingMessage message = new OutgoingMessage(out, out.os(), _batchRequestCompress, 0);
sent = (sendMessage(message) & IceInternal.AsyncStatus.Sent) > 0;
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
//
// Reset the batch stream.
//
_batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
_batchRequestNum = 0;
_batchRequestCompress = false;
_batchMarker = 0;
return sent;
}
synchronized public int
flushAsyncBatchRequests(IceInternal.BatchOutgoingAsync outAsync)
{
while(_batchStreamInUse && _exception == null)
{
try
{
wait();
}
catch(InterruptedException ex)
{
}
}
if(_exception != null)
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(_batchRequestNum == 0)
{
int status = IceInternal.AsyncStatus.Sent;
if(outAsync.__sent(this))
{
status |= IceInternal.AsyncStatus.InvokeSentCallback;
}
return status;
}
//
// Fill in the number of requests in the batch.
//
_batchStream.pos(IceInternal.Protocol.headerSize);
_batchStream.writeInt(_batchRequestNum);
_batchStream.swap(outAsync.__os());
int status;
try
{
OutgoingMessage message = new OutgoingMessage(outAsync, outAsync.__os(), _batchRequestCompress, 0);
status = sendMessage(message);
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
//
// Reset the batch stream.
//
_batchStream = new IceInternal.BasicStream(_instance, _batchAutoFlush);
_batchRequestNum = 0;
_batchRequestCompress = false;
_batchMarker = 0;
return status;
}
synchronized public void
sendResponse(IceInternal.BasicStream os, byte compressFlag)
{
assert(_state > StateNotValidated);
try
{
if(--_dispatchCount == 0)
{
if(_state == StateFinished)
{
_reaper.add(this);
}
notifyAll();
}
if(_state >= StateClosed)
{
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
sendMessage(new OutgoingMessage(os, compressFlag != 0, true));
if(_state == StateClosing && _dispatchCount == 0)
{
initiateShutdown();
}
}
catch(LocalException ex)
{
setState(StateClosed, ex);
}
}
synchronized public void
sendNoResponse()
{
assert(_state > StateNotValidated);
try
{
if(--_dispatchCount == 0)
{
if(_state == StateFinished)
{
_reaper.add(this);
}
notifyAll();
}
if(_state >= StateClosed)
{
assert(_exception != null);
throw (Ice.LocalException)_exception.fillInStackTrace();
}
if(_state == StateClosing && _dispatchCount == 0)
{
initiateShutdown();
}
}
catch(LocalException ex)
{
setState(StateClosed, ex);
}
}
public IceInternal.EndpointI
endpoint()
{
return _endpoint; // No mutex protection necessary, _endpoint is immutable.
}
public IceInternal.Connector
connector()
{
return _connector; // No mutex protection necessary, _connector is immutable.
}
public synchronized void
setAdapter(ObjectAdapter adapter)
{
if(_state <= StateNotValidated || _state >= StateClosing)
{
return;
}
assert(_state < StateClosing);
_adapter = adapter;
if(_adapter != null)
{
_servantManager = ((ObjectAdapterI)_adapter).getServantManager();
if(_servantManager == null)
{
_adapter = null;
}
}
else
{
_servantManager = null;
}
//
// We never change the thread pool with which we were
// initially registered, even if we add or remove an object
// adapter.
//
}
public synchronized ObjectAdapter
getAdapter()
{
return _adapter;
}
public Endpoint
getEndpoint()
{
return _endpoint; // No mutex protection necessary, _endpoint is immutable.
}
public ObjectPrx
createProxy(Identity ident)
{
//
// Create a reference and return a reverse proxy for this
// reference.
//
return _instance.proxyFactory().referenceToProxy(_instance.referenceFactory().create(ident, this));
}
//
// Operations from EventHandler
//
public void
message(IceInternal.ThreadPoolCurrent current)
{
StartCallback startCB = null;
java.util.List<OutgoingMessage> sentCBs = null;
MessageInfo info = null;
synchronized(this)
{
if(_state >= StateClosed)
{
return;
}
try
{
unscheduleTimeout(current.operation);
if((current.operation & IceInternal.SocketOperation.Write) != 0 && !_writeStream.isEmpty())
{
if(!_transceiver.write(_writeStream.getBuffer()))
{
assert(!_writeStream.isEmpty());
scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout());
return;
}
assert(!_writeStream.getBuffer().b.hasRemaining());
}
if((current.operation & IceInternal.SocketOperation.Read) != 0 && !_readStream.isEmpty())
{
if(_readHeader) // Read header if necessary.
{
if(!_transceiver.read(_readStream.getBuffer(), _hasMoreData))
{
return;
}
assert(!_readStream.getBuffer().b.hasRemaining());
_readHeader = false;
int pos = _readStream.pos();
if(pos < IceInternal.Protocol.headerSize)
{
//
// This situation is possible for small UDP packets.
//
throw new Ice.IllegalMessageSizeException();
}
_readStream.pos(0);
byte[] m = new byte[4];
m[0] = _readStream.readByte();
m[1] = _readStream.readByte();
m[2] = _readStream.readByte();
m[3] = _readStream.readByte();
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])
{
Ice.BadMagicException ex = new Ice.BadMagicException();
ex.badMagic = m;
throw ex;
}
byte pMajor = _readStream.readByte();
byte pMinor = _readStream.readByte();
if(pMajor != IceInternal.Protocol.protocolMajor || pMinor > IceInternal.Protocol.protocolMinor)
{
Ice.UnsupportedProtocolException e = new Ice.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 = _readStream.readByte();
byte eMinor = _readStream.readByte();
if(eMajor != IceInternal.Protocol.encodingMajor || eMinor > IceInternal.Protocol.encodingMinor)
{
Ice.UnsupportedEncodingException e = new Ice.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;
}
_readStream.readByte(); // messageType
_readStream.readByte(); // compress
int size = _readStream.readInt();
if(size < IceInternal.Protocol.headerSize)
{
throw new Ice.IllegalMessageSizeException();
}
if(size > _instance.messageSizeMax())
{
IceInternal.Ex.throwMemoryLimitException(size, _instance.messageSizeMax());
}
if(size > _readStream.size())
{
_readStream.resize(size, true);
}
_readStream.pos(pos);
}
if(_readStream.pos() != _readStream.size())
{
if(_endpoint.datagram())
{
throw new Ice.DatagramLimitException(); // The message was truncated.
}
else
{
if(!_transceiver.read(_readStream.getBuffer(), _hasMoreData))
{
assert(!_readStream.isEmpty());
scheduleTimeout(IceInternal.SocketOperation.Read, _endpoint.timeout());
return;
}
assert(!_readStream.getBuffer().b.hasRemaining());
}
}
}
if(_state <= StateNotValidated)
{
if(_state == StateNotInitialized && !initialize(current.operation))
{
return;
}
if(_state <= StateNotValidated && !validate(current.operation))
{
return;
}
_threadPool.unregister(this, current.operation);
//
// We start out in holding state.
//
setState(StateHolding);
startCB = _startCallback;
_startCallback = null;
}
else
{
assert(_state <= StateClosing);
if((current.operation & IceInternal.SocketOperation.Write) != 0)
{
sentCBs = sendNextMessage();
}
if((current.operation & IceInternal.SocketOperation.Read) != 0)
{
info = parseMessage(current.stream); // Optimization: use the thread's stream.
}
}
}
catch(DatagramLimitException ex) // Expected.
{
if(_warnUdp)
{
_logger.warning("maximum datagram size of " + _readStream.pos() + " exceeded");
}
_readStream.resize(IceInternal.Protocol.headerSize, true);
_readStream.pos(0);
_readHeader = true;
return;
}
catch(SocketException ex)
{
setState(StateClosed, ex);
return;
}
catch(LocalException ex)
{
if(_endpoint.datagram())
{
if(_warn)
{
String s = "datagram connection exception:\n" + ex + '\n' + _desc;
_logger.warning(s);
}
_readStream.resize(IceInternal.Protocol.headerSize, true);
_readStream.pos(0);
_readHeader = true;
}
else
{
setState(StateClosed, ex);
}
return;
}
if(_acmTimeout > 0)
{
_acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
}
current.ioCompleted();
}
if(_dispatcher != null)
{
if(info != null)
{
//
// Create a new stream for the dispatch instead of using the thread
// pool's thread stream.
//
assert(info.stream == current.stream);
IceInternal.BasicStream stream = info.stream;
info.stream = new IceInternal.BasicStream(_instance);
info.stream.swap(stream);
}
final StartCallback finalStartCB = startCB;
final java.util.List<OutgoingMessage> finalSentCBs = sentCBs;
final MessageInfo finalInfo = info;
try
{
_dispatcher.dispatch(new Runnable()
{
public void
run()
{
dispatch(finalStartCB, finalSentCBs, finalInfo);
}
}, this);
}
catch(java.lang.Exception ex)
{
if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
{
warning("dispatch exception", ex);
}
}
}
else
{
dispatch(startCB, sentCBs, info);
}
}
protected void
dispatch(StartCallback startCB, java.util.List<OutgoingMessage> sentCBs, MessageInfo info)
{
//
// Notify the factory that the connection establishment and
// validation has completed.
//
if(startCB != null)
{
startCB.connectionStartCompleted(this);
}
//
// Notify AMI calls that the message was sent.
//
if(sentCBs != null)
{
for(OutgoingMessage msg : sentCBs)
{
msg.outAsync.__sent();
}
}
if(info != null)
{
//
// Asynchronous replies must be handled outside the thread
// synchronization, so that nested calls are possible.
//
if(info.outAsync != null)
{
info.outAsync.__finished(info.stream);
}
if(info.invokeNum > 0)
{
//
// Method invocation (or multiple invocations for batch messages)
// must be done outside the thread synchronization, so that nested
// calls are possible.
//
invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager,
info.adapter);
}
}
}
public void
finished(IceInternal.ThreadPoolCurrent current)
{
//
// Check if the connection needs to call user callbacks. If it doesn't, we
// can safely run finish() from this "IO thread". Otherwise, we either run
// finish() with the dispatcher if one is set, or we promote another IO
// thread first before calling finish().
//
if(_startCallback == null && _sendStreams.isEmpty() && _asyncRequests.isEmpty())
{
finish();
return;
}
if(_dispatcher == null)
{
current.ioCompleted();
finish();
}
else
{
try
{
_dispatcher.dispatch(new Runnable()
{
public void
run()
{
finish();
}
},
this);
}
catch(java.lang.Exception ex)
{
if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
{
warning("dispatch exception", ex);
}
}
}
}
public void
finish()
{
synchronized(this)
{
assert(_state == StateClosed);
unscheduleTimeout(IceInternal.SocketOperation.Read |
IceInternal.SocketOperation.Write |
IceInternal.SocketOperation.Connect);
}
if(_startCallback != null)
{
_startCallback.connectionStartFailed(this, _exception);
_startCallback = null;
}
//
// NOTE: for twoway requests which are not sent, finished can be called twice: the
// first time because the outgoing is in the _sendStreams set and the second time
// because it's either in the _requests/_asyncRequests set. This is fine, only the
// first call should be taken into account by the implementation of finished.
//
for(OutgoingMessage p : _sendStreams)
{
if(p.requestId > 0)
{
if(p.out != null) // Make sure finished isn't called twice.
{
_requests.remove(p.requestId);
}
else
{
_asyncRequests.remove(p.requestId);
}
}
p.finished(_exception);
}
_sendStreams.clear();
for(IceInternal.Outgoing p : _requests.values())
{
p.finished(_exception, true);
}
_requests.clear();
for(IceInternal.OutgoingAsync p : _asyncRequests.values())
{
p.__finished(_exception, true);
}
_asyncRequests.clear();
//
// This must be done last as this will cause waitUntilFinished() to return (and communicator
// objects such as the timer might be destroyed too).
//
synchronized(this)
{
setState(StateFinished);
if(_dispatchCount == 0)
{
_reaper.add(this);
}
}
}
public String
toString()
{
return _toString();
}
public java.nio.channels.SelectableChannel
fd()
{
return _transceiver.fd();
}
public boolean
hasMoreData()
{
return _hasMoreData.value;
}
public synchronized void
timedOut()
{
if(_state <= StateNotValidated)
{
setState(StateClosed, new ConnectTimeoutException());
}
else if(_state < StateClosing)
{
setState(StateClosed, new TimeoutException());
}
else if(_state == StateClosing)
{
setState(StateClosed, new CloseTimeoutException());
}
}
public String
type()
{
return _type; // No mutex lock, _type is immutable.
}
public int
timeout()
{
return _endpoint.timeout(); // No mutex protection necessary, _endpoint is immutable.
}
public synchronized ConnectionInfo
getInfo()
{
if(_state >= StateClosed)
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
ConnectionInfo info = _transceiver.getInfo();
info.adapterName = _adapter != null ? _adapter.getName() : "";
info.incoming = _connector == null;
return info;
}
public String
_toString()
{
return _desc; // No mutex lock, _desc is immutable.
}
public synchronized void
exception(LocalException ex)
{
setState(StateClosed, ex);
}
public synchronized void
invokeException(LocalException ex, int invokeNum)
{
//
// Fatal exception while invoking a request. Since sendResponse/sendNoResponse isn't
// called in case of a fatal exception we decrement _dispatchCount here.
//
setState(StateClosed, ex);
if(invokeNum > 0)
{
assert(_dispatchCount > 0);
_dispatchCount -= invokeNum;
assert(_dispatchCount >= 0);
if(_dispatchCount == 0)
{
if(_state == StateFinished)
{
_reaper.add(this);
}
notifyAll();
}
}
}
public ConnectionI(IceInternal.Instance instance, IceInternal.ConnectionReaper reaper,
IceInternal.Transceiver transceiver, IceInternal.Connector connector,
IceInternal.EndpointI endpoint, ObjectAdapter adapter)
{
_instance = instance;
_reaper = reaper;
_transceiver = transceiver;
_desc = transceiver.toString();
_type = transceiver.type();
_connector = connector;
_endpoint = endpoint;
_adapter = adapter;
final Ice.InitializationData initData = instance.initializationData();
_dispatcher = initData.dispatcher; // Cached for better performance.
_logger = initData.logger; // Cached for better performance.
_traceLevels = instance.traceLevels(); // Cached for better performance.
_timer = instance.timer();
_writeTimeout = new TimeoutCallback();
_writeTimeoutScheduled = false;
_readTimeout = new TimeoutCallback();
_readTimeoutScheduled = false;
_warn = initData.properties.getPropertyAsInt("Ice.Warn.Connections") > 0;
_warnUdp = instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0;
_cacheBuffers = instance.cacheMessageBuffers();
_acmAbsoluteTimeoutMillis = 0;
_nextRequestId = 1;
_batchAutoFlush = initData.properties.getPropertyAsIntWithDefault("Ice.BatchAutoFlush", 1) > 0 ? true : false;
_batchStream = new IceInternal.BasicStream(instance, _batchAutoFlush);
_batchStreamInUse = false;
_batchRequestNum = 0;
_batchRequestCompress = false;
_batchMarker = 0;
_readStream = new IceInternal.BasicStream(instance);
_readHeader = false;
_writeStream = new IceInternal.BasicStream(instance);
_dispatchCount = 0;
_state = StateNotInitialized;
int compressionLevel = initData.properties.getPropertyAsIntWithDefault("Ice.Compression.Level", 1);
if(compressionLevel < 1)
{
compressionLevel = 1;
}
else if(compressionLevel > 9)
{
compressionLevel = 9;
}
_compressionLevel = compressionLevel;
if(_adapter != null)
{
_servantManager = ((ObjectAdapterI)_adapter).getServantManager();
}
else
{
_servantManager = null;
}
try
{
if(_endpoint.datagram())
{
_acmTimeout = 0;
}
else
{
if(_adapter != null)
{
_acmTimeout = ((ObjectAdapterI)_adapter).getACM();
}
else
{
_acmTimeout = _instance.clientACM();
}
}
if(_adapter != null)
{
_threadPool = ((ObjectAdapterI)_adapter).getThreadPool();
}
else
{
_threadPool = _instance.clientThreadPool();
}
_threadPool.initialize(this);
}
catch(Ice.LocalException ex)
{
throw ex;
}
catch(java.lang.Exception ex)
{
Ice.SyscallException e = new Ice.SyscallException();
e.initCause(ex);
throw e;
}
}
protected synchronized void
finalize()
throws Throwable
{
IceUtilInternal.Assert.FinalizerAssert(_startCallback == null);
IceUtilInternal.Assert.FinalizerAssert(_state == StateFinished);
IceUtilInternal.Assert.FinalizerAssert(_dispatchCount == 0);
IceUtilInternal.Assert.FinalizerAssert(_sendStreams.isEmpty());
IceUtilInternal.Assert.FinalizerAssert(_requests.isEmpty());
IceUtilInternal.Assert.FinalizerAssert(_asyncRequests.isEmpty());
super.finalize();
}
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;
private static final int StateFinished = 6;
private void
setState(int state, LocalException ex)
{
//
// If setState() is called with an exception, then only closed
// and closing states are permissible.
//
assert(state >= StateClosing);
if(_state == state) // Don't switch twice.
{
return;
}
if(_exception == null)
{
_exception = ex;
if(_warn)
{
//
// We don't warn if we are not validated.
//
if(_state > StateNotValidated)
{
//
// Don't warn about certain expected exceptions.
//
if(!(_exception instanceof CloseConnectionException ||
_exception instanceof ForcedCloseConnectionException ||
_exception instanceof ConnectionTimeoutException ||
_exception instanceof CommunicatorDestroyedException ||
_exception instanceof ObjectAdapterDeactivatedException ||
(_exception instanceof ConnectionLostException && _state == StateClosing)))
{
warning("connection exception", _exception);
}
}
}
}
//
// We must set the new state before we notify requests of any
// exceptions. Otherwise new requests may retry on a
// connection that is not yet marked as closed or closing.
//
setState(state);
}
private void
setState(int state)
{
//
// We don't want to send close connection messages if the endpoint
// only supports oneway transmission from client to server.
//
if(_endpoint.datagram() && state == StateClosing)
{
state = StateClosed;
}
//
// Skip graceful shutdown if we are destroyed before validation.
//
if(_state <= StateNotValidated && state == StateClosing)
{
state = StateClosed;
}
if(_state == state) // Don't switch twice.
{
return;
}
try
{
switch(state)
{
case StateNotInitialized:
{
assert(false);
break;
}
case StateNotValidated:
{
if(_state != StateNotInitialized)
{
assert(_state == StateClosed);
return;
}
break;
}
case StateActive:
{
//
// Can only switch from holding or not validated to
// active.
//
if(_state != StateHolding && _state != StateNotValidated)
{
return;
}
_threadPool.register(this, IceInternal.SocketOperation.Read);
break;
}
case StateHolding:
{
//
// Can only switch from active or not validated to
// holding.
//
if(_state != StateActive && _state != StateNotValidated)
{
return;
}
if(_state == StateActive)
{
_threadPool.unregister(this, IceInternal.SocketOperation.Read);
}
break;
}
case StateClosing:
{
//
// Can't change back from closed.
//
if(_state >= StateClosed)
{
return;
}
if(_state == StateHolding)
{
// We need to continue to read in closing state.
_threadPool.register(this, IceInternal.SocketOperation.Read);
}
break;
}
case StateClosed:
{
if(_state == StateFinished)
{
return;
}
_threadPool.finish(this);
break;
}
case StateFinished:
{
assert(_state == StateClosed);
_transceiver.close();
break;
}
}
}
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 = "unexpected connection exception:\n " + _desc + "\n" + sw.toString();
_instance.initializationData().logger.error(s);
}
//
// We only register with the connection monitor if our new state
// is StateActive. Otherwise we unregister with the connection
// monitor, but only if we were registered before, i.e., if our
// old state was StateActive.
//
if(_acmTimeout > 0)
{
if(state == StateActive)
{
_instance.connectionMonitor().add(this);
}
else if(_state == StateActive)
{
_instance.connectionMonitor().remove(this);
}
}
_state = state;
notifyAll();
if(_state == StateClosing && _dispatchCount == 0)
{
try
{
initiateShutdown();
}
catch(LocalException ex)
{
setState(StateClosed, ex);
}
}
}
private void
initiateShutdown()
{
assert(_state == StateClosing);
assert(_dispatchCount == 0);
if(!_endpoint.datagram())
{
//
// Before we shut down, we send a close connection
// message.
//
IceInternal.BasicStream os = new IceInternal.BasicStream(_instance, false, false);
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((byte)0); // compression status: always report 0 for CloseConnection in Java.
os.writeInt(IceInternal.Protocol.headerSize); // Message size.
if((sendMessage(new OutgoingMessage(os, false, false)) & IceInternal.AsyncStatus.Sent) > 0)
{
//
// Schedule the close timeout to wait for the peer to close the connection. If
// the message was queued for sending, sendNextMessage will schedule the timeout
// once all messages were sent.
//
scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout());
}
//
// 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();
}
}
private boolean
initialize(int operation)
{
int s = _transceiver.initialize();
if(s != IceInternal.SocketOperation.None)
{
scheduleTimeout(s, connectTimeout());
_threadPool.update(this, operation, s);
return false;
}
//
// Update the connection description once the transceiver is initialized.
//
_desc = _transceiver.toString();
setState(StateNotValidated);
return true;
}
private boolean
validate(int operation)
{
if(!_endpoint.datagram()) // Datagram connections are always implicitly validated.
{
if(_adapter != null) // The server side has the active role for connection validation.
{
if(_writeStream.size() == 0)
{
_writeStream.writeBlob(IceInternal.Protocol.magic);
_writeStream.writeByte(IceInternal.Protocol.protocolMajor);
_writeStream.writeByte(IceInternal.Protocol.protocolMinor);
_writeStream.writeByte(IceInternal.Protocol.encodingMajor);
_writeStream.writeByte(IceInternal.Protocol.encodingMinor);
_writeStream.writeByte(IceInternal.Protocol.validateConnectionMsg);
_writeStream.writeByte((byte)0); // Compression status (always zero for validate connection).
_writeStream.writeInt(IceInternal.Protocol.headerSize); // Message size.
IceInternal.TraceUtil.traceSend(_writeStream, _logger, _traceLevels);
_writeStream.prepareWrite();
}
if(_writeStream.pos() != _writeStream.size() && !_transceiver.write(_writeStream.getBuffer()))
{
scheduleTimeout(IceInternal.SocketOperation.Write, connectTimeout());
_threadPool.update(this, operation, IceInternal.SocketOperation.Write);
return false;
}
}
else // The client side has the passive role for connection validation.
{
if(_readStream.size() == 0)
{
_readStream.resize(IceInternal.Protocol.headerSize, true);
_readStream.pos(0);
}
if(_readStream.pos() != _readStream.size() && !_transceiver.read(_readStream.getBuffer(), _hasMoreData))
{
scheduleTimeout(IceInternal.SocketOperation.Read, connectTimeout());
_threadPool.update(this, operation, IceInternal.SocketOperation.Read);
return false;
}
assert(_readStream.pos() == IceInternal.Protocol.headerSize);
_readStream.pos(0);
byte[] m = _readStream.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 = _readStream.readByte();
byte pMinor = _readStream.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 = _readStream.readByte();
byte eMinor = _readStream.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 = _readStream.readByte();
if(messageType != IceInternal.Protocol.validateConnectionMsg)
{
throw new ConnectionNotValidatedException();
}
_readStream.readByte(); // Ignore compression status for validate connection.
int size = _readStream.readInt();
if(size != IceInternal.Protocol.headerSize)
{
throw new IllegalMessageSizeException();
}
IceInternal.TraceUtil.traceRecv(_readStream, _logger, _traceLevels);
}
}
_writeStream.resize(0, false);
_writeStream.pos(0);
_readStream.resize(IceInternal.Protocol.headerSize, true);
_readHeader = true;
_readStream.pos(0);
return true;
}
private java.util.List<OutgoingMessage>
sendNextMessage()
{
assert(!_sendStreams.isEmpty());
assert(!_writeStream.isEmpty() && _writeStream.pos() == _writeStream.size());
java.util.List<OutgoingMessage> callbacks = new java.util.LinkedList<OutgoingMessage>();
try
{
while(true)
{
//
// Notify the message that it was sent.
//
OutgoingMessage message = _sendStreams.getFirst();
_writeStream.swap(message.stream);
if(message.sent(this, true))
{
callbacks.add(message);
}
_sendStreams.removeFirst();
//
// If there's nothing left to send, we're done.
//
if(_sendStreams.isEmpty())
{
break;
}
//
// Otherwise, prepare the next message stream for writing.
//
message = _sendStreams.getFirst();
assert(!message.prepared);
IceInternal.BasicStream stream = message.stream;
message.stream = doCompress(stream, message.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);
}
_writeStream.swap(message.stream);
//
// Send the message.
//
if(_writeStream.pos() != _writeStream.size() && !_transceiver.write(_writeStream.getBuffer()))
{
assert(!_writeStream.isEmpty());
scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout());
return callbacks;
}
}
}
catch(Ice.LocalException ex)
{
setState(StateClosed, ex);
return callbacks;
}
assert(_writeStream.isEmpty());
_threadPool.unregister(this, IceInternal.SocketOperation.Write);
//
// If all the messages were sent and we are in the closing state, we schedule
// the close timeout to wait for the peer to close the connection.
//
if(_state == StateClosing)
{
scheduleTimeout(IceInternal.SocketOperation.Write, closeTimeout());
}
return callbacks;
}
private int
sendMessage(OutgoingMessage message)
{
assert(_state < StateClosed);
if(!_sendStreams.isEmpty())
{
message.adopt();
_sendStreams.addLast(message);
return IceInternal.AsyncStatus.Queued;
}
//
// 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;
message.stream = doCompress(stream, message.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);
}
if(_transceiver.write(message.stream.getBuffer()))
{
int status = IceInternal.AsyncStatus.Sent;
if(message.sent(this, false))
{
status |= IceInternal.AsyncStatus.InvokeSentCallback;
}
if(_acmTimeout > 0)
{
_acmAbsoluteTimeoutMillis = IceInternal.Time.currentMonotonicTimeMillis() + _acmTimeout * 1000;
}
return status;
}
message.adopt();
_writeStream.swap(message.stream);
_sendStreams.addLast(message);
scheduleTimeout(IceInternal.SocketOperation.Write, _endpoint.timeout());
_threadPool.register(this, IceInternal.SocketOperation.Write);
return IceInternal.AsyncStatus.Queued;
}
private IceInternal.BasicStream
doCompress(IceInternal.BasicStream uncompressed, boolean compress)
{
boolean compressionSupported = false;
if(compress)
{
//
// Don't check whether compression support is available unless the proxy
// is configured for compression.
//
compressionSupported = IceInternal.BasicStream.compressible();
}
if(compressionSupported && uncompressed.size() >= 100)
{
//
// Do compression.
//
IceInternal.BasicStream cstream = uncompressed.compress(IceInternal.Protocol.headerSize, _compressionLevel);
if(cstream != null)
{
//
// Set compression status.
//
cstream.pos(9);
cstream.writeByte((byte)2);
//
// Write the size of the compressed stream into the header.
//
cstream.pos(10);
cstream.writeInt(cstream.size());
//
// Write the compression status and size of the compressed stream into the header of the
// uncompressed stream -- we need this to trace requests correctly.
//
uncompressed.pos(9);
uncompressed.writeByte((byte)2);
uncompressed.writeInt(cstream.size());
return cstream;
}
}
uncompressed.pos(9);
uncompressed.writeByte((byte)(compressionSupported ? 1 : 0));
//
// Not compressed, fill in the message size.
//
uncompressed.pos(10);
uncompressed.writeInt(uncompressed.size());
return uncompressed;
}
private static class MessageInfo
{
MessageInfo(IceInternal.BasicStream stream)
{
this.stream = stream;
}
IceInternal.BasicStream stream;
int invokeNum;
int requestId;
byte compress;
IceInternal.ServantManager servantManager;
ObjectAdapter adapter;
IceInternal.OutgoingAsync outAsync;
}
private MessageInfo
parseMessage(IceInternal.BasicStream stream)
{
assert(_state > StateNotValidated && _state < StateClosed);
MessageInfo info = new MessageInfo(stream);
_readStream.swap(info.stream);
_readStream.resize(IceInternal.Protocol.headerSize, true);
_readStream.pos(0);
_readHeader = true;
assert(info.stream.pos() == info.stream.size());
try
{
//
// We don't need to check magic and version here. This has already
// been done by the ThreadPool which provides us with the stream.
//
assert(info.stream.pos() == info.stream.size());
info.stream.pos(8);
byte messageType = info.stream.readByte();
info.compress = info.stream.readByte();
if(info.compress == (byte)2)
{
if(IceInternal.BasicStream.compressible())
{
info.stream = info.stream.uncompress(IceInternal.Protocol.headerSize);
}
else
{
FeatureNotSupportedException ex = new FeatureNotSupportedException();
ex.unsupportedFeature = "Cannot uncompress compressed message: "
+ "org.apache.tools.bzip2.CBZip2OutputStream was not found";
throw ex;
}
}
info.stream.pos(IceInternal.Protocol.headerSize);
switch(messageType)
{
case IceInternal.Protocol.closeConnectionMsg:
{
IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
if(_endpoint.datagram())
{
if(_warn)
{
_logger.warning("ignoring close connection message for datagram connection:\n" + _desc);
}
}
else
{
setState(StateClosed, new CloseConnectionException());
}
break;
}
case IceInternal.Protocol.requestMsg:
{
if(_state == StateClosing)
{
IceInternal.TraceUtil.trace("received request during closing\n" +
"(ignored by server, client will retry)",
info.stream, _logger, _traceLevels);
}
else
{
IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.requestId = info.stream.readInt();
info.invokeNum = 1;
info.servantManager = _servantManager;
info.adapter = _adapter;
++_dispatchCount;
}
break;
}
case IceInternal.Protocol.requestBatchMsg:
{
if(_state == StateClosing)
{
IceInternal.TraceUtil.trace("received batch request during closing\n" +
"(ignored by server, client will retry)",
info.stream, _logger, _traceLevels);
}
else
{
IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.invokeNum = info.stream.readInt();
if(info.invokeNum < 0)
{
info.invokeNum = 0;
throw new UnmarshalOutOfBoundsException();
}
info.servantManager = _servantManager;
info.adapter = _adapter;
_dispatchCount += info.invokeNum;
}
break;
}
case IceInternal.Protocol.replyMsg:
{
IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
info.requestId = info.stream.readInt();
IceInternal.Outgoing out = _requests.remove(info.requestId);
if(out != null)
{
out.finished(info.stream);
}
else
{
info.outAsync = _asyncRequests.remove(info.requestId);
if(info.outAsync == null)
{
throw new UnknownRequestIdException();
}
}
notifyAll(); // Notify threads blocked in close(false)
break;
}
case IceInternal.Protocol.validateConnectionMsg:
{
IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels);
if(_warn)
{
_logger.warning("ignoring unexpected validate connection message:\n" + _desc);
}
break;
}
default:
{
IceInternal.TraceUtil.trace("received unknown message\n(invalid, closing connection)",
info.stream, _logger, _traceLevels);
throw new UnknownMessageException();
}
}
}
catch(LocalException ex)
{
if(_endpoint.datagram())
{
if(_warn)
{
_logger.warning("datagram connection exception:\n" + ex + '\n' + _desc);
}
}
else
{
setState(StateClosed, ex);
}
}
return info;
}
private void
invokeAll(IceInternal.BasicStream stream, int invokeNum, int requestId, byte compress,
IceInternal.ServantManager servantManager, ObjectAdapter adapter)
{
//
// Note: In contrast to other private or protected methods, this
// operation must be called *without* the mutex locked.
//
IceInternal.Incoming in = null;
try
{
while(invokeNum > 0)
{
//
// Prepare the invocation.
//
boolean response = !_endpoint.datagram() && requestId != 0;
in = getIncoming(adapter, response, compress, requestId);
IceInternal.BasicStream is = in.is();
stream.swap(is);
IceInternal.BasicStream os = in.os();
//
// Prepare the response if necessary.
//
if(response)
{
assert(invokeNum == 1); // No further invocations if a response is expected.
os.writeBlob(IceInternal.Protocol.replyHdr);
//
// Add the request ID.
//
os.writeInt(requestId);
}
in.invoke(servantManager);
//
// If there are more invocations, we need the stream back.
//
if(--invokeNum > 0)
{
stream.swap(is);
}
reclaimIncoming(in);
in = null;
}
}
catch(LocalException ex)
{
invokeException(ex, invokeNum);
}
catch(java.lang.AssertionError ex) // Upon assertion, we print the stack trace.
{
UnknownException uex = new UnknownException();
java.io.StringWriter sw = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
uex.unknown = sw.toString();
_logger.error(uex.unknown);
invokeException(uex, invokeNum);
}
catch(java.lang.OutOfMemoryError ex)
{
UnknownException uex = new UnknownException();
java.io.StringWriter sw = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
uex.unknown = sw.toString();
_logger.error(uex.unknown);
invokeException(uex, invokeNum);
}
finally
{
if(in != null)
{
reclaimIncoming(in);
}
}
}
private void
scheduleTimeout(int status, int timeout)
{
if(timeout < 0)
{
return;
}
if((status & IceInternal.SocketOperation.Read) != 0)
{
_timer.schedule(_readTimeout, timeout);
_readTimeoutScheduled = true;
}
if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0)
{
_timer.schedule(_writeTimeout, timeout);
_writeTimeoutScheduled = true;
}
}
private void
unscheduleTimeout(int status)
{
if((status & IceInternal.SocketOperation.Read) != 0 && _readTimeoutScheduled)
{
_timer.cancel(_readTimeout);
_readTimeoutScheduled = false;
}
if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0 &&
_writeTimeoutScheduled)
{
_timer.cancel(_writeTimeout);
_writeTimeoutScheduled = false;
}
}
private int
connectTimeout()
{
IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
if(defaultsAndOverrides.overrideConnectTimeout)
{
return defaultsAndOverrides.overrideConnectTimeoutValue;
}
else
{
return _endpoint.timeout();
}
}
private int
closeTimeout()
{
IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
if(defaultsAndOverrides.overrideCloseTimeout)
{
return defaultsAndOverrides.overrideCloseTimeoutValue;
}
else
{
return _endpoint.timeout();
}
}
private void
warning(String msg, 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 = msg + ":\n" + _desc + "\n" + sw.toString();
_logger.warning(s);
}
private IceInternal.Incoming
getIncoming(ObjectAdapter adapter, boolean response, byte compress, int requestId)
{
IceInternal.Incoming in = null;
if(_cacheBuffers > 0)
{
synchronized(_incomingCacheMutex)
{
if(_incomingCache == null)
{
in = new IceInternal.Incoming(_instance, this, adapter, response, compress, requestId);
}
else
{
in = _incomingCache;
_incomingCache = _incomingCache.next;
in.reset(_instance, this, adapter, response, compress, requestId);
in.next = null;
}
}
}
else
{
in = new IceInternal.Incoming(_instance, this, adapter, response, compress, requestId);
}
return in;
}
private void
reclaimIncoming(IceInternal.Incoming in)
{
if(_cacheBuffers > 0)
{
synchronized(_incomingCacheMutex)
{
in.next = _incomingCache;
_incomingCache = in;
//
// Clear references to Ice objects as soon as possible.
//
_incomingCache.reclaim();
}
}
}
public IceInternal.Outgoing
getOutgoing(IceInternal.RequestHandler handler, String operation, OperationMode mode,
java.util.Map<String, String> context)
throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing out = null;
if(_cacheBuffers > 0)
{
synchronized(_outgoingCacheMutex)
{
if(_outgoingCache == null)
{
out = new IceInternal.Outgoing(handler, operation, mode, context);
}
else
{
out = _outgoingCache;
_outgoingCache = _outgoingCache.next;
out.reset(handler, operation, mode, context);
out.next = null;
}
}
}
else
{
out = new IceInternal.Outgoing(handler, operation, mode, context);
}
return out;
}
public void
reclaimOutgoing(IceInternal.Outgoing out)
{
if(_cacheBuffers > 0)
{
//
// Clear references to Ice objects as soon as possible.
//
out.reclaim();
synchronized(_outgoingCacheMutex)
{
out.next = _outgoingCache;
_outgoingCache = out;
}
}
}
private static class OutgoingMessage
{
OutgoingMessage(IceInternal.BasicStream stream, boolean compress, boolean adopt)
{
this.stream = stream;
this.compress = compress;
this.adopt = adopt;
this.isSent = false;
this.requestId = 0;
}
OutgoingMessage(IceInternal.OutgoingMessageCallback out, IceInternal.BasicStream stream, boolean compress,
int requestId)
{
this.stream = stream;
this.compress = compress;
this.out = out;
this.requestId = requestId;
this.isSent = false;
}
OutgoingMessage(IceInternal.OutgoingAsyncMessageCallback out, IceInternal.BasicStream stream, boolean compress,
int requestId)
{
this.stream = stream;
this.compress = compress;
this.outAsync = out;
this.requestId = requestId;
this.isSent = false;
}
public void
adopt()
{
if(adopt)
{
IceInternal.BasicStream stream = new IceInternal.BasicStream(this.stream.instance());
stream.swap(this.stream);
this.stream = stream;
adopt = false;
}
}
public boolean
sent(ConnectionI connection, boolean notify)
{
isSent = true; // The message is sent.
if(out != null)
{
out.sent(notify); // true = notify the waiting thread that the request was sent.
return false;
}
else if(outAsync != null)
{
return outAsync.__sent(connection);
}
else
{
return false;
}
}
public void
finished(Ice.LocalException ex)
{
if(out != null)
{
out.finished(ex, isSent);
}
else if(outAsync != null)
{
outAsync.__finished(ex, isSent);
}
}
public IceInternal.BasicStream stream;
public IceInternal.OutgoingMessageCallback out;
public IceInternal.OutgoingAsyncMessageCallback outAsync;
public boolean compress;
public int requestId;
boolean adopt;
boolean prepared;
boolean isSent;
}
private final IceInternal.Instance _instance;
private final IceInternal.ConnectionReaper _reaper;
private final IceInternal.Transceiver _transceiver;
private String _desc;
private final String _type;
private final IceInternal.Connector _connector;
private final IceInternal.EndpointI _endpoint;
private ObjectAdapter _adapter;
private IceInternal.ServantManager _servantManager;
private final Dispatcher _dispatcher;
private final Logger _logger;
private final IceInternal.TraceLevels _traceLevels;
private final IceInternal.ThreadPool _threadPool;
private final IceInternal.Timer _timer;
private final IceInternal.TimerTask _writeTimeout;
private boolean _writeTimeoutScheduled;
private final IceInternal.TimerTask _readTimeout;
private boolean _readTimeoutScheduled;
private StartCallback _startCallback = null;
private Ice.BooleanHolder _hasMoreData = new Ice.BooleanHolder(false);
private final boolean _warn;
private final boolean _warnUdp;
private final long _acmTimeout;
private long _acmAbsoluteTimeoutMillis;
private final int _compressionLevel;
private int _nextRequestId;
private java.util.Map<Integer, IceInternal.Outgoing> _requests =
new java.util.HashMap<Integer, IceInternal.Outgoing>();
private java.util.Map<Integer, IceInternal.OutgoingAsync> _asyncRequests =
new java.util.HashMap<Integer, IceInternal.OutgoingAsync>();
private LocalException _exception;
private boolean _batchAutoFlush;
private IceInternal.BasicStream _batchStream;
private boolean _batchStreamInUse;
private int _batchRequestNum;
private boolean _batchRequestCompress;
private int _batchMarker;
private java.util.LinkedList<OutgoingMessage> _sendStreams = new java.util.LinkedList<OutgoingMessage>();
private IceInternal.BasicStream _readStream;
private boolean _readHeader;
private IceInternal.BasicStream _writeStream;
private int _dispatchCount;
private int _state; // The current state.
private IceInternal.Incoming _incomingCache;
private java.lang.Object _incomingCacheMutex = new java.lang.Object();
private IceInternal.Outgoing _outgoingCache;
private java.lang.Object _outgoingCacheMutex = new java.lang.Object();
private int _cacheBuffers;
}