// ********************************************************************** // // 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 IceInternal; public final class IncomingConnectionFactory extends EventHandler implements Ice.ConnectionI.StartCallback { public synchronized void activate() { setState(StateActive); } public synchronized void hold() { setState(StateHolding); } public synchronized void destroy() { setState(StateClosed); } public void waitUntilHolding() { java.util.LinkedList<Ice.ConnectionI> connections; synchronized(this) { // // First we wait until the connection factory itself is in holding // state. // while(_state < StateHolding) { try { wait(); } catch(InterruptedException ex) { } } // // We want to wait until all connections are in holding state // outside the thread synchronization. // connections = new java.util.LinkedList<Ice.ConnectionI>(_connections); } // // Now we wait until each connection is in holding state. // for(Ice.ConnectionI connection : connections) { connection.waitUntilHolding(); } } public void waitUntilFinished() { java.util.LinkedList<Ice.ConnectionI> 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) { try { wait(); } catch(InterruptedException ex) { } } // // 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<Ice.ConnectionI>(_connections); } if(connections != null) { for(Ice.ConnectionI connection : connections) { connection.waitUntilFinished(); } } synchronized(this) { // Ensure all the connections are finished and reapable at this point. java.util.List<Ice.ConnectionI> cons = _reaper.swapConnections(); assert((cons == null ? 0 : cons.size()) == _connections.size()); if(cons != null) { cons.clear(); } _connections.clear(); } } public EndpointI endpoint() { // No mutex protection necessary, _endpoint is immutable. return _endpoint; } public synchronized java.util.LinkedList<Ice.ConnectionI> connections() { java.util.LinkedList<Ice.ConnectionI> connections = new java.util.LinkedList<Ice.ConnectionI>(); // // Only copy connections which have not been destroyed. // for(Ice.ConnectionI connection : _connections) { if(connection.isActiveOrHolding()) { connections.add(connection); } } return connections; } public void flushAsyncBatchRequests(CommunicatorBatchOutgoingAsync outAsync) { for(Ice.ConnectionI c : connections()) // connections() is synchronized, no need to synchronize here. { try { outAsync.flushConnection(c); } catch(Ice.LocalException ex) { // Ignore. } } } // // Operations from EventHandler. // 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<Ice.ConnectionI> cons = _reaper.swapConnections(); if(cons != null) { for(Ice.ConnectionI c : cons) { _connections.remove(c); } } // // Now accept a new connection. // Transceiver transceiver = null; try { transceiver = _acceptor.accept(); } catch(Ice.SocketException ex) { if(Network.noMoreFds(ex.getCause())) { try { String s = "fatal error: can't accept more connections:\n" + ex.getCause().getMessage(); s += '\n' + _acceptor.toString(); _instance.initializationData().logger.error(s); } finally { Runtime.getRuntime().halt(1); } } // 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(_instance, _reaper, 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); } public synchronized void finished(ThreadPoolCurrent current) { assert(_state == StateClosed); setState(StateFinished); } public synchronized String toString() { if(_transceiver != null) { return _transceiver.toString(); } assert(_acceptor != null); return _acceptor.toString(); } public java.nio.channels.SelectableChannel fd() { assert(_acceptor != null); return _acceptor.fd(); } public boolean hasMoreData() { assert(_acceptor != null); return false; } // // 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); } } public IncomingConnectionFactory(Instance instance, EndpointI endpoint, Ice.ObjectAdapter adapter, String adapterName) { _instance = instance; _endpoint = endpoint; _adapter = adapter; _warn = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Connections") > 0 ? true : false; _state = StateHolding; DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); if(defaultsAndOverrides.overrideTimeout) { _endpoint = _endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue); } if(defaultsAndOverrides.overrideCompress) { _endpoint = _endpoint.compress(defaultsAndOverrides.overrideCompressValue); } try { EndpointIHolder h = new EndpointIHolder(); h.value = _endpoint; _transceiver = _endpoint.transceiver(h); if(_transceiver != null) { _endpoint = h.value; Ice.ConnectionI connection = new Ice.ConnectionI(_instance, _reaper, _transceiver, null, _endpoint, _adapter); connection.start(null); _connections.add(connection); } else { h.value = _endpoint; _acceptor = _endpoint.acceptor(h, adapterName); _endpoint = h.value; assert(_acceptor != null); _acceptor.listen(); ((Ice.ObjectAdapterI)_adapter).getThreadPool().initialize(this); } } 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(). } } if(_acceptor != null) { try { _acceptor.close(); } catch(Ice.LocalException e) { // Here we ignore any exceptions in close(). } } _state = StateFinished; _connections.clear(); if(ex instanceof Ice.LocalException) { throw (Ice.LocalException)ex; } else { Ice.SyscallException e = new Ice.SyscallException(); e.initCause(ex); throw e; } } } protected synchronized void finalize() throws Throwable { IceUtilInternal.Assert.FinalizerAssert(_state == StateFinished); IceUtilInternal.Assert.FinalizerAssert(_connections.isEmpty()); 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) { ((Ice.ObjectAdapterI)_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) { ((Ice.ObjectAdapterI)_adapter).getThreadPool().unregister(this, SocketOperation.Read); } for(Ice.ConnectionI connection : _connections) { connection.hold(); } break; } case StateClosed: { if(_acceptor != null) { ((Ice.ObjectAdapterI)_adapter).getThreadPool().finish(this); } else { state = StateFinished; } for(Ice.ConnectionI connection : _connections) { connection.destroy(Ice.ConnectionI.ObjectAdapterDeactivated); } break; } case StateFinished: { assert(_state == StateClosed); if(_acceptor != null) { _acceptor.close(); } break; } } _state = state; notifyAll(); } 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 ConnectionReaper _reaper = new ConnectionReaper(); private Acceptor _acceptor; private Transceiver _transceiver; private EndpointI _endpoint; private Ice.ObjectAdapter _adapter; private final boolean _warn; private java.util.Set<Ice.ConnectionI> _connections = new java.util.HashSet<Ice.ConnectionI>(); private int _state; }