@Override
	public void close() {
		boolean enqueueOnSocketContextClose;
		synchronized(closeLock) {
			if(!closed) {
				closed = true;
				enqueueOnSocketContextClose = true;
			} else {
				enqueueOnSocketContextClose = false;
			}
		}
		List<S> socketsToClose;
		synchronized(sockets) {
			// Gets a copy of the sockets to avoid concurrent modification exception and avoid holding lock
			socketsToClose = new ArrayList<>(sockets.values());
			// Each will be removed from socket.close() below: sockets.clear();
		}
		for(S socket : socketsToClose) {
			try {
				socket.close();
			} catch(Exception exc) {
				logger.log(Level.SEVERE, null, exc);
			}
		}
		if(enqueueOnSocketContextClose) {
			Future<?> future = listenerManager.enqueueEvent(
				new ConcurrentListenerManager.Event<SocketContextListener>() {
					@Override
					public Runnable createCall(final SocketContextListener listener) {
						return new Runnable() {
							@Override
							public void run() {
								listener.onSocketContextClose(AbstractSocketContext.this);
							}
						};
					}
				}
			);
			try {
				future.get();
			} catch(ExecutionException e) {
				logger.log(Level.SEVERE, null, e);
			} catch(InterruptedException e) {
				logger.log(Level.SEVERE, null, e);
				// Restore the interrupted status
				Thread.currentThread().interrupt();
			}
		}
		listenerManager.close();
		synchronized(sockets) {
			if(!sockets.isEmpty()) throw new AssertionError("Not all sockets closed");
		}
	}
@ Override public void close ( ) { boolean enqueueOnSocketContextClose ; synchronized ( closeLock ) { if ( ! closed ) { closed = true ; enqueueOnSocketContextClose = true ; } else { enqueueOnSocketContextClose = false ; } } List < S > socketsToClose ; synchronized ( sockets ) { socketsToClose = new ArrayList < > ( sockets . values ( ) ) ; } for ( S socket : socketsToClose ) { try { socket . close ( ) ; } catch ( Exception exc ) { logger . log ( Level . SEVERE , null , exc ) ; } } if ( enqueueOnSocketContextClose ) { Future < ? > future = listenerManager . enqueueEvent ( new ConcurrentListenerManager . Event < SocketContextListener > ( ) { @ Override public Runnable createCall ( final SocketContextListener listener ) { return new Runnable ( ) { @ Override public void run ( ) { listener . onSocketContextClose ( AbstractSocketContext . this ) ; } } ; } } ) ; try { future . get ( ) ; } catch ( ExecutionException e ) { logger . log ( Level . SEVERE , null , e ) ; } catch ( InterruptedException e ) { logger . log ( Level . SEVERE , null , e ) ; Thread . currentThread ( ) . interrupt ( ) ; } } listenerManager . close ( ) ; synchronized ( sockets ) { if ( ! sockets . isEmpty ( ) ) throw new AssertionError ( "Not all sockets closed" ) ; } }
Any overriding implementation must call super.close() first.