IceInternal.IncomingConnectionFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice-compat Show documentation
Show all versions of ice-compat Show documentation
Ice is a comprehensive RPC framework that helps you build distributed applications with minimal effort using familiar object-oriented idioms
// **********************************************************************
//
// Copyright (c) 2003-2018 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 IncomingConnectionFactory extends EventHandler implements Ice.ConnectionI.StartCallback
{
public synchronized void
startAcceptor()
{
if(_state >= StateClosed || _acceptorStarted)
{
return;
}
try
{
createAcceptor();
}
catch(Exception ex)
{
String s = "acceptor creation failed:\n" + ex.getCause().getMessage() + '\n' + _acceptor.toString();
_instance.initializationData().logger.error(s);
_instance.timer().schedule(new Runnable()
{
public void run()
{
startAcceptor();
}
}, 1, java.util.concurrent.TimeUnit.SECONDS);
}
}
public synchronized void
activate()
{
setState(StateActive);
}
public synchronized void
hold()
{
setState(StateHolding);
}
public synchronized void
destroy()
{
setState(StateClosed);
}
public synchronized void
updateConnectionObservers()
{
for(Ice.ConnectionI connection : _connections)
{
connection.updateObserver();
}
}
public void
waitUntilHolding()
throws InterruptedException
{
java.util.LinkedList connections;
synchronized(this)
{
//
// First we wait until the connection factory itself is in holding
// state.
//
while(_state < StateHolding)
{
wait();
}
//
// We want to wait until all connections are in holding state
// outside the thread synchronization.
//
connections = new java.util.LinkedList(_connections);
}
//
// Now we wait until each connection is in holding state.
//
for(Ice.ConnectionI connection : connections)
{
connection.waitUntilHolding();
}
}
public void
waitUntilFinished()
throws InterruptedException
{
java.util.LinkedList connections = null;
synchronized(this)
{
//
// First we wait until the factory is destroyed. If we are using
// an acceptor, we also wait for it to be closed.
//
while(_state != StateFinished)
{
wait();
}
//
// Clear the OA. See bug 1673 for the details of why this is necessary.
//
_adapter = null;
//
// We want to wait until all connections are finished outside the
// thread synchronization.
//
connections = new java.util.LinkedList(_connections);
}
if(connections != null)
{
for(Ice.ConnectionI connection : connections)
{
try
{
connection.waitUntilFinished();
}
catch(InterruptedException e)
{
//
// Force close all of the connections.
//
for(Ice.ConnectionI c : connections)
{
c.close(Ice.ConnectionClose.Forcefully);
}
throw e;
}
}
}
synchronized(this)
{
if(_transceiver != null)
{
assert(_connections.size() <= 1); // The connection isn't monitored or reaped.
}
else
{
// Ensure all the connections are finished and reapable at this point.
java.util.List cons = _monitor.swapReapedConnections();
assert((cons == null ? 0 : cons.size()) == _connections.size());
if(cons != null)
{
cons.clear();
}
}
_connections.clear();
}
//
// Must be destroyed outside the synchronization since this might block waiting for
// a timer task to complete.
//
_monitor.destroy();
}
public boolean
isLocal(EndpointI endpoint)
{
if(_publishedEndpoint != null && endpoint.equivalent(_publishedEndpoint))
{
return true;
}
synchronized(this)
{
return endpoint.equivalent(_endpoint);
}
}
public EndpointI
endpoint()
{
if(_publishedEndpoint != null)
{
return _publishedEndpoint;
}
synchronized(this)
{
return _endpoint;
}
}
public synchronized java.util.LinkedList
connections()
{
java.util.LinkedList connections = new java.util.LinkedList();
//
// Only copy connections which have not been destroyed.
//
for(Ice.ConnectionI connection : _connections)
{
if(connection.isActiveOrHolding())
{
connections.add(connection);
}
}
return connections;
}
public void
flushAsyncBatchRequests(Ice.CompressBatch compressBatch, CommunicatorFlushBatch outAsync)
{
for(Ice.ConnectionI c : connections()) // connections() is synchronized, no need to synchronize here.
{
try
{
outAsync.flushConnection(c, compressBatch);
}
catch(Ice.LocalException ex)
{
// Ignore.
}
}
}
//
// Operations from EventHandler.
//
@Override
public void
message(ThreadPoolCurrent current)
{
Ice.ConnectionI connection = null;
synchronized(this)
{
if(_state >= StateClosed)
{
return;
}
else if(_state == StateHolding)
{
Thread.yield();
return;
}
//
// Reap closed connections.
//
java.util.List cons = _monitor.swapReapedConnections();
if(cons != null)
{
for(Ice.ConnectionI c : cons)
{
_connections.remove(c);
}
}
if(!_acceptorStarted)
{
return;
}
//
// Now accept a new connection.
//
Transceiver transceiver = null;
try
{
transceiver = _acceptor.accept();
if(_instance.traceLevels().network >= 2)
{
StringBuffer s = new StringBuffer("trying to accept ");
s.append(_endpoint.protocol());
s.append(" connection\n");
s.append(transceiver.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
}
catch(Ice.SocketException ex)
{
if(Network.noMoreFds(ex.getCause()))
{
try
{
String s = "can't accept more connections:\n" + ex.getCause().getMessage();
s += '\n' + _acceptor.toString();
try
{
_instance.initializationData().logger.error(s);
}
catch(Throwable ex1)
{
System.out.println(s);
}
}
catch(Throwable ex2)
{
// Ignore, could be a class loading error.
}
if(_adapter.getThreadPool().finish(this, true))
{
closeAcceptor();
}
}
// Ignore socket exceptions.
return;
}
catch(Ice.LocalException ex)
{
// Warn about other Ice local exceptions.
if(_warn)
{
warning(ex);
}
return;
}
assert(transceiver != null);
try
{
connection = new Ice.ConnectionI(_adapter.getCommunicator(), _instance, _monitor, transceiver, null,
_endpoint, _adapter);
}
catch(Ice.LocalException ex)
{
try
{
transceiver.close();
}
catch(Ice.LocalException exc)
{
// Ignore
}
if(_warn)
{
warning(ex);
}
return;
}
_connections.add(connection);
}
assert(connection != null);
connection.start(this);
}
@Override
public synchronized void
finished(ThreadPoolCurrent current, boolean close)
{
if(_state < StateClosed)
{
if(_acceptorStarted && close)
{
closeAcceptor();
}
return;
}
assert(_state == StateClosed);
setState(StateFinished);
if(_acceptorStarted && close)
{
closeAcceptor();
}
}
@Override
public synchronized String
toString()
{
if(_transceiver != null)
{
return _transceiver.toString();
}
return _acceptor.toString();
}
@Override
public java.nio.channels.SelectableChannel
fd()
{
assert(_acceptor != null);
return _acceptor.fd();
}
@Override
public void setReadyCallback(ReadyCallback readyCallback)
{
if(_acceptor != null)
{
_acceptor.setReadyCallback(readyCallback);
}
}
//
// Operations from ConnectionI.StartCallback
//
@Override
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();
}
}
@Override
public synchronized void
connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex)
{
if(_state >= StateClosed)
{
return;
}
//
// Do not warn about connection exceptions here. The connection is not yet validated.
//
}
public
IncomingConnectionFactory(Instance instance, EndpointI endpoint, EndpointI publish, Ice.ObjectAdapterI adapter)
{
_instance = instance;
_endpoint = endpoint;
_publishedEndpoint = publish;
_adapter = adapter;
_warn = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Connections") > 0 ? true : false;
_state = StateHolding;
_acceptorStarted = false;
_monitor = new FactoryACMMonitor(instance, adapter.getACM());
DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides();
if(defaultsAndOverrides.overrideTimeout)
{
_endpoint = _endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue);
}
if(defaultsAndOverrides.overrideCompress)
{
_endpoint = _endpoint.compress(defaultsAndOverrides.overrideCompressValue);
}
try
{
_transceiver = _endpoint.transceiver();
if(_transceiver != null)
{
if(_instance.traceLevels().network >= 2)
{
StringBuffer s = new StringBuffer("attempting to bind to ");
s.append(_endpoint.protocol());
s.append(" socket\n");
s.append(_transceiver.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_endpoint = _transceiver.bind();
Ice.ConnectionI connection =
new Ice.ConnectionI(_adapter.getCommunicator(), _instance, null, _transceiver, null, _endpoint,
_adapter);
connection.startAndWait();
_connections.add(connection);
}
else
{
createAcceptor();
}
}
catch(java.lang.Exception ex)
{
//
// Clean up for finalizer.
//
if(_transceiver != null)
{
try
{
_transceiver.close();
}
catch(Ice.LocalException e)
{
// Here we ignore any exceptions in close().
}
}
_state = StateFinished;
_monitor.destroy();
_connections.clear();
if(ex instanceof Ice.LocalException)
{
throw (Ice.LocalException)ex;
}
else if(ex instanceof InterruptedException)
{
throw new Ice.OperationInterruptedException();
}
else
{
throw new Ice.SyscallException(ex);
}
}
}
@SuppressWarnings("deprecation")
@Override
protected synchronized void
finalize()
throws Throwable
{
try
{
IceUtilInternal.Assert.FinalizerAssert(_state == StateFinished);
IceUtilInternal.Assert.FinalizerAssert(_connections.isEmpty());
}
catch(java.lang.Exception ex)
{
}
finally
{
super.finalize();
}
}
private static final int StateActive = 0;
private static final int StateHolding = 1;
private static final int StateClosed = 2;
private static final int StateFinished = 3;
private void
setState(int state)
{
if(_state == state) // Don't switch twice.
{
return;
}
switch(state)
{
case StateActive:
{
if(_state != StateHolding) // Can only switch from holding to active.
{
return;
}
if(_acceptor != null)
{
if(_instance.traceLevels().network >= 1)
{
StringBuffer s = new StringBuffer("accepting ");
s.append(_endpoint.protocol());
s.append(" connections at ");
s.append(_acceptor.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_adapter.getThreadPool().register(this, SocketOperation.Read);
}
for(Ice.ConnectionI connection : _connections)
{
connection.activate();
}
break;
}
case StateHolding:
{
if(_state != StateActive) // Can only switch from active to holding.
{
return;
}
if(_acceptor != null)
{
if(_instance.traceLevels().network >= 1)
{
StringBuffer s = new StringBuffer("holding ");
s.append(_endpoint.protocol());
s.append(" connections at ");
s.append(_acceptor.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_adapter.getThreadPool().unregister(this, SocketOperation.Read);
}
for(Ice.ConnectionI connection : _connections)
{
connection.hold();
}
break;
}
case StateClosed:
{
if(_acceptorStarted)
{
//
// If possible, close the acceptor now to prevent new connections from
// being accepted while we are deactivating. This is especially useful
// if there are no more threads in the thread pool available to dispatch
// the finish() call.
//
if(_adapter.getThreadPool().finish(this, true))
{
closeAcceptor();
}
}
else
{
state = StateFinished;
}
for(Ice.ConnectionI connection : _connections)
{
connection.destroy(Ice.ConnectionI.ObjectAdapterDeactivated);
}
break;
}
case StateFinished:
{
assert(_state == StateClosed);
break;
}
}
_state = state;
notifyAll();
}
private void
createAcceptor()
{
try
{
assert(!_acceptorStarted);
_acceptor = _endpoint.acceptor(_adapter.getName());
assert(_acceptor != null);
if(_instance.traceLevels().network >= 2)
{
StringBuffer s = new StringBuffer("attempting to bind to ");
s.append(_endpoint.protocol());
s.append(" socket ");
s.append(_acceptor.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_endpoint = _acceptor.listen();
if(_instance.traceLevels().network >= 1)
{
StringBuffer s = new StringBuffer("listening for ");
s.append(_endpoint.protocol());
s.append(" connections\n");
s.append(_acceptor.toDetailedString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_adapter.getThreadPool().initialize(this);
if(_state == StateActive)
{
_adapter.getThreadPool().register(this, SocketOperation.Read);
}
_acceptorStarted = true;
}
catch(Exception ex)
{
if(_acceptor != null)
{
_acceptor.close();
}
throw ex;
}
}
private void
closeAcceptor()
{
assert(_acceptor != null);
if(_instance.traceLevels().network >= 1)
{
StringBuffer s = new StringBuffer("stopping to accept ");
s.append(_endpoint.protocol());
s.append(" connections at ");
s.append(_acceptor.toString());
_instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString());
}
_acceptorStarted = false;
_acceptor.close();
if(_state == StateHolding || _state == StateActive)
{
_instance.timer().schedule(new Runnable()
{
public void run()
{
startAcceptor();
}
}, 1, java.util.concurrent.TimeUnit.SECONDS);
}
}
private void
warning(Ice.LocalException ex)
{
String s = "connection exception:\n" + Ex.toString(ex) + '\n' + _acceptor.toString();
_instance.initializationData().logger.warning(s);
}
private final Instance _instance;
private final FactoryACMMonitor _monitor;
private Acceptor _acceptor;
private Transceiver _transceiver;
private EndpointI _endpoint;
private final EndpointI _publishedEndpoint;
private Ice.ObjectAdapterI _adapter;
private final boolean _warn;
private java.util.Set _connections = new java.util.HashSet();
private int _state;
private boolean _acceptorStarted;
}