| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.server.jndi; |
| |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.IOException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.InetSocketAddress; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.naming.Context; |
| import javax.naming.NamingException; |
| import javax.naming.directory.Attributes; |
| import javax.naming.directory.DirContext; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.directory.server.changepw.ChangePasswordConfiguration; |
| import org.apache.directory.server.changepw.ChangePasswordServer; |
| import org.apache.directory.server.configuration.ServerStartupConfiguration; |
| import org.apache.directory.server.core.DirectoryService; |
| import org.apache.directory.server.core.jndi.CoreContextFactory; |
| import org.apache.directory.server.core.partition.PartitionNexus; |
| import org.apache.directory.server.kerberos.kdc.KdcConfiguration; |
| import org.apache.directory.server.kerberos.kdc.KerberosServer; |
| import org.apache.directory.server.kerberos.shared.store.JndiPrincipalStoreImpl; |
| import org.apache.directory.server.kerberos.shared.store.PrincipalStore; |
| import org.apache.directory.server.ldap.ExtendedOperationHandler; |
| import org.apache.directory.server.ldap.LdapProtocolProvider; |
| import org.apache.directory.server.ntp.NtpConfiguration; |
| import org.apache.directory.server.ntp.NtpServer; |
| import org.apache.directory.server.protocol.shared.LoadStrategy; |
| import org.apache.directory.server.protocol.shared.store.LdifFileLoader; |
| import org.apache.directory.shared.ldap.constants.SchemaConstants; |
| import org.apache.directory.shared.ldap.exception.LdapConfigurationException; |
| import org.apache.directory.shared.ldap.exception.LdapNamingException; |
| import org.apache.directory.shared.ldap.message.AttributesImpl; |
| import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect; |
| import org.apache.directory.shared.ldap.util.StringTools; |
| import org.apache.mina.common.DefaultIoFilterChainBuilder; |
| import org.apache.mina.common.ExecutorThreadModel; |
| import org.apache.mina.common.IoAcceptor; |
| import org.apache.mina.common.IoFilterChainBuilder; |
| import org.apache.mina.common.IoSession; |
| import org.apache.mina.common.WriteFuture; |
| import org.apache.mina.transport.socket.nio.DatagramAcceptor; |
| import org.apache.mina.transport.socket.nio.DatagramAcceptorConfig; |
| import org.apache.mina.transport.socket.nio.SocketAcceptor; |
| import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; |
| import org.apache.mina.transport.socket.nio.SocketSessionConfig; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue; |
| import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor; |
| import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; |
| |
| |
| /** |
| * Adds additional bootstrapping for server socket listeners when firing |
| * up the server. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| * @version $Rev$ |
| * @see javax.naming.spi.InitialContextFactory |
| */ |
| public class ServerContextFactory extends CoreContextFactory |
| { |
| /** Logger for this class */ |
| private static final Logger log = LoggerFactory.getLogger( ServerContextFactory.class.getName() ); |
| private static final String LDIF_FILES_DN = "ou=loadedLdifFiles,ou=configuration,ou=system"; |
| |
| protected static IoAcceptor tcpAcceptor; |
| protected static IoAcceptor udpAcceptor; |
| protected static ThreadPoolExecutor threadPoolExecutor; |
| protected static ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance( "ApacheDS" ); |
| |
| private static boolean ldapStarted; |
| private static boolean ldapsStarted; |
| private static KerberosServer tcpKdcServer; |
| private static KerberosServer udpKdcServer; |
| private static ChangePasswordServer tcpChangePasswordServer; |
| private static ChangePasswordServer udpChangePasswordServer; |
| private static NtpServer tcpNtpServer; |
| private static NtpServer udpNtpServer; |
| private DirectoryService directoryService; |
| |
| /** |
| * Initialize the SocketAcceptor so that the server can accept |
| * incomming requests. |
| * |
| * We will start N threads, spreaded on the available CPUs. |
| */ |
| public void beforeStartup( DirectoryService service ) |
| { |
| int maxThreads = service.getConfiguration().getStartupConfiguration().getMaxThreads(); |
| threadPoolExecutor = new ThreadPoolExecutor( maxThreads, maxThreads, 60, TimeUnit.SECONDS, |
| new LinkedBlockingQueue() ); |
| threadModel.setExecutor( threadPoolExecutor ); |
| |
| udpAcceptor = new DatagramAcceptor(); |
| tcpAcceptor = new SocketAcceptor( |
| Runtime.getRuntime().availableProcessors(), threadPoolExecutor ); |
| |
| this.directoryService = service; |
| } |
| |
| |
| public void afterShutdown( DirectoryService service ) |
| { |
| ServerStartupConfiguration cfg = ( ServerStartupConfiguration ) |
| service.getConfiguration().getStartupConfiguration(); |
| |
| if ( ldapStarted ) |
| { |
| stopLDAP0( cfg.getLdapPort() ); |
| ldapStarted = false; |
| } |
| |
| if ( ldapsStarted ) |
| { |
| stopLDAP0( cfg.getLdapsPort() ); |
| ldapsStarted = false; |
| } |
| |
| if ( tcpKdcServer != null ) |
| { |
| tcpKdcServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of KRB5 Service (TCP) complete: " + tcpKdcServer ); |
| } |
| |
| tcpKdcServer = null; |
| } |
| |
| if ( udpKdcServer != null ) |
| { |
| udpKdcServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of KRB5 Service (UDP) complete: " + udpKdcServer ); |
| } |
| |
| udpKdcServer = null; |
| } |
| |
| if ( tcpChangePasswordServer != null ) |
| { |
| tcpChangePasswordServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of Change Password Service (TCP) complete: " + tcpChangePasswordServer ); |
| } |
| |
| tcpChangePasswordServer = null; |
| } |
| |
| if ( udpChangePasswordServer != null ) |
| { |
| udpChangePasswordServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of Change Password Service (UDP) complete: " + udpChangePasswordServer ); |
| } |
| |
| udpChangePasswordServer = null; |
| } |
| |
| if ( tcpNtpServer != null ) |
| { |
| tcpNtpServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of NTP Service (TCP) complete: " + tcpNtpServer ); |
| } |
| |
| tcpNtpServer = null; |
| } |
| |
| if ( udpNtpServer != null ) |
| { |
| udpNtpServer.destroy(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of NTP Service complete: " + udpNtpServer ); |
| } |
| |
| udpNtpServer = null; |
| } |
| } |
| |
| |
| public void afterStartup( DirectoryService service ) throws NamingException |
| { |
| ServerStartupConfiguration cfg = ( ServerStartupConfiguration ) service.getConfiguration() |
| .getStartupConfiguration(); |
| Hashtable env = service.getConfiguration().getEnvironment(); |
| |
| loadLdifs( service ); |
| |
| if ( cfg.isEnableNetworking() ) |
| { |
| startLDAP( cfg, env ); |
| startLDAPS( cfg, env ); |
| startKerberos( cfg, env ); |
| startChangePassword( cfg, env ); |
| startNTP( cfg, env ); |
| } |
| } |
| |
| |
| private void ensureLdifFileBase( DirContext root ) |
| { |
| Attributes entry = new AttributesImpl( SchemaConstants.OU_AT, "loadedLdifFiles", true ); |
| entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC ); |
| entry.get( SchemaConstants.OBJECT_CLASS_AT ).add( SchemaConstants.ORGANIZATIONAL_UNIT_OC ); |
| |
| try |
| { |
| root.createSubcontext( LDIF_FILES_DN, entry ); |
| log.info( "Creating " + LDIF_FILES_DN ); |
| } |
| catch ( NamingException e ) |
| { |
| log.info( LDIF_FILES_DN + " exists" ); |
| } |
| } |
| |
| private final static String WINDOWSFILE_ATTR = "windowsFilePath"; |
| private final static String UNIXFILE_ATTR = "unixFilePath"; |
| private final static String WINDOWSFILE_OC = "windowsFile"; |
| private final static String UNIXFILE_OC = "unixFile"; |
| |
| private String buildProtectedFileEntry( File ldif ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| |
| buf.append( File.separatorChar == '\\' ? WINDOWSFILE_ATTR : UNIXFILE_ATTR ); |
| buf.append( "=" ); |
| |
| buf.append( StringTools.dumpHexPairs( StringTools.getBytesUtf8( getCanonical( ldif ) ) ) ); |
| |
| buf.append( "," ); |
| buf.append( LDIF_FILES_DN ); |
| |
| return buf.toString(); |
| } |
| |
| private void addFileEntry( DirContext root, File ldif ) throws NamingException |
| { |
| String rdnAttr = File.separatorChar == '\\' ? WINDOWSFILE_ATTR : UNIXFILE_ATTR; |
| String oc = File.separatorChar == '\\' ? WINDOWSFILE_OC : UNIXFILE_OC; |
| |
| Attributes entry = new AttributesImpl( rdnAttr, getCanonical( ldif ), true ); |
| entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC ); |
| entry.get( SchemaConstants.OBJECT_CLASS_AT ).add( oc ); |
| root.createSubcontext( buildProtectedFileEntry( ldif ), entry ); |
| } |
| |
| |
| private Attributes getLdifFileEntry( DirContext root, File ldif ) |
| { |
| try |
| { |
| return root.getAttributes( buildProtectedFileEntry( ldif ), new String[] |
| { SchemaConstants.CREATE_TIMESTAMP_AT } ); |
| } |
| catch ( NamingException e ) |
| { |
| return null; |
| } |
| } |
| |
| |
| private String getCanonical( File file ) |
| { |
| String canonical = null; |
| |
| try |
| { |
| canonical = file.getCanonicalPath(); |
| } |
| catch ( IOException e ) |
| { |
| log.error( "could not get canonical path", e ); |
| return null; |
| } |
| |
| return StringUtils.replace( canonical, "\\", "\\\\" ); |
| } |
| |
| |
| private void loadLdifs( DirectoryService service ) throws NamingException |
| { |
| ServerStartupConfiguration cfg = ( ServerStartupConfiguration ) service.getConfiguration() |
| .getStartupConfiguration(); |
| |
| // log and bail if property not set |
| if ( cfg.getLdifDirectory() == null ) |
| { |
| log.info( "LDIF load directory not specified. No LDIF files will be loaded." ); |
| return; |
| } |
| |
| // log and bail if LDIF directory does not exists |
| if ( !cfg.getLdifDirectory().exists() ) |
| { |
| log.warn( "LDIF load directory '" + getCanonical( cfg.getLdifDirectory() ) |
| + "' does not exist. No LDIF files will be loaded." ); |
| return; |
| } |
| |
| // get an initial context to the rootDSE for creating the LDIF entries |
| Hashtable env = ( Hashtable ) service.getConfiguration().getEnvironment().clone(); |
| env.put( Context.PROVIDER_URL, "" ); |
| DirContext root = ( DirContext ) this.getInitialContext( env ); |
| |
| // make sure the configuration area for loaded ldif files is present |
| ensureLdifFileBase( root ); |
| |
| // if ldif directory is a file try to load it |
| if ( !cfg.getLdifDirectory().isDirectory() ) |
| { |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "LDIF load directory '" + getCanonical( cfg.getLdifDirectory() ) |
| + "' is a file. Will attempt to load as LDIF." ); |
| } |
| |
| Attributes fileEntry = getLdifFileEntry( root, cfg.getLdifDirectory() ); |
| |
| if ( fileEntry != null ) |
| { |
| String time = ( String ) fileEntry.get( SchemaConstants.CREATE_TIMESTAMP_AT ).get(); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Load of LDIF file '" + getCanonical( cfg.getLdifDirectory() ) |
| + "' skipped. It has already been loaded on " + time + "." ); |
| } |
| |
| return; |
| } |
| |
| LdifFileLoader loader = new LdifFileLoader( root, cfg.getLdifDirectory(), cfg.getLdifFilters() ); |
| loader.execute(); |
| |
| addFileEntry( root, cfg.getLdifDirectory() ); |
| return; |
| } |
| |
| // get all the ldif files within the directory (should be sorted alphabetically) |
| File[] ldifFiles = cfg.getLdifDirectory().listFiles( new FileFilter() |
| { |
| public boolean accept( File pathname ) |
| { |
| boolean isLdif = pathname.getName().toLowerCase().endsWith( ".ldif" ); |
| return pathname.isFile() && pathname.canRead() && isLdif; |
| } |
| } ); |
| |
| // log and bail if we could not find any LDIF files |
| if ( ldifFiles == null || ldifFiles.length == 0 ) |
| { |
| log.warn( "LDIF load directory '" + getCanonical( cfg.getLdifDirectory() ) |
| + "' does not contain any LDIF files. No LDIF files will be loaded." ); |
| return; |
| } |
| |
| // load all the ldif files and load each one that is loaded |
| for ( int ii = 0; ii < ldifFiles.length; ii++ ) |
| { |
| Attributes fileEntry = getLdifFileEntry( root, ldifFiles[ii] ); |
| if ( fileEntry != null ) |
| { |
| String time = ( String ) fileEntry.get( SchemaConstants.CREATE_TIMESTAMP_AT ).get(); |
| log.info( "Load of LDIF file '" + getCanonical( ldifFiles[ii] ) |
| + "' skipped. It has already been loaded on " + time + "." ); |
| continue; |
| } |
| LdifFileLoader loader = new LdifFileLoader( root, ldifFiles[ii], cfg.getLdifFilters() ); |
| int count = loader.execute(); |
| log.info( "Loaded " + count + " entries from LDIF file '" + getCanonical( ldifFiles[ii] ) + "'" ); |
| if ( fileEntry == null ) |
| { |
| addFileEntry( root, ldifFiles[ii] ); |
| } |
| } |
| } |
| |
| |
| /** |
| * Starts up the LDAP protocol provider to service LDAP requests |
| * |
| * @throws NamingException if there are problems starting the LDAP provider |
| */ |
| private void startLDAP( ServerStartupConfiguration cfg, Hashtable env ) throws NamingException |
| { |
| // Skip if disabled |
| int port = cfg.getLdapPort(); |
| |
| if ( port < 0 ) |
| { |
| return; |
| } |
| |
| startLDAP0( cfg, env, port, new DefaultIoFilterChainBuilder() ); |
| } |
| |
| |
| /** |
| * Starts up the LDAPS protocol provider to service LDAPS requests |
| * |
| * @throws NamingException if there are problems starting the LDAPS provider |
| */ |
| private void startLDAPS( ServerStartupConfiguration cfg, Hashtable env ) throws NamingException |
| { |
| // Skip if disabled |
| if ( !cfg.isEnableLdaps() ) |
| { |
| return; |
| } |
| |
| // We use the reflection API in case this is not running on JDK 1.5+. |
| IoFilterChainBuilder chain; |
| |
| try |
| { |
| chain = ( IoFilterChainBuilder ) Class.forName( "org.apache.directory.server.ssl.LdapsInitializer", true, |
| ServerContextFactory.class.getClassLoader() ).getMethod( "init", new Class[] |
| { ServerStartupConfiguration.class } ).invoke( null, new Object[] |
| { cfg } ); |
| ldapsStarted = true; |
| } |
| catch ( InvocationTargetException e ) |
| { |
| if ( e.getCause() instanceof NamingException ) |
| { |
| throw ( NamingException ) e.getCause(); |
| } |
| else |
| { |
| throw ( NamingException ) new NamingException( "Failed to load LDAPS initializer." ).initCause( e |
| .getCause() ); |
| } |
| } |
| catch ( Exception e ) |
| { |
| throw ( NamingException ) new NamingException( "Failed to load LDAPS initializer." ).initCause( e ); |
| } |
| |
| startLDAP0( cfg, env, cfg.getLdapsPort(), chain ); |
| } |
| |
| |
| private void startLDAP0( ServerStartupConfiguration cfg, Hashtable env, int port, |
| IoFilterChainBuilder chainBuilder ) throws LdapNamingException, LdapConfigurationException |
| { |
| // Register all extended operation handlers. |
| LdapProtocolProvider protocolProvider = new LdapProtocolProvider( cfg, ( Hashtable ) env.clone() ); |
| |
| for ( Iterator i = cfg.getExtendedOperationHandlers().iterator(); i.hasNext(); ) |
| { |
| ExtendedOperationHandler h = ( ExtendedOperationHandler ) i.next(); |
| protocolProvider.addExtendedOperationHandler( h ); |
| log.info( "Added Extended Request Handler: " + h.getOid() ); |
| h.setLdapProvider( protocolProvider ); |
| PartitionNexus nexus = directoryService.getConfiguration().getPartitionNexus(); |
| nexus.registerSupportedExtensions( h.getExtensionOids() ); |
| } |
| |
| try |
| { |
| // Disable the disconnection of the clients on unbind |
| SocketAcceptorConfig acceptorCfg = new SocketAcceptorConfig(); |
| acceptorCfg.setDisconnectOnUnbind( false ); |
| acceptorCfg.setReuseAddress( true ); |
| acceptorCfg.setFilterChainBuilder( chainBuilder ); |
| acceptorCfg.setThreadModel( threadModel ); |
| |
| ((SocketSessionConfig)(acceptorCfg.getSessionConfig())).setTcpNoDelay( true ); |
| |
| tcpAcceptor.bind( new InetSocketAddress( port ), protocolProvider.getHandler(), acceptorCfg ); |
| ldapStarted = true; |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Successful bind of an LDAP Service (" + port + ") is complete." ); |
| } |
| } |
| catch ( IOException e ) |
| { |
| String msg = "Failed to bind an LDAP service (" + port + ") to the service registry."; |
| LdapConfigurationException lce = new LdapConfigurationException( msg ); |
| lce.setRootCause( e ); |
| log.error( msg, e ); |
| throw lce; |
| } |
| } |
| |
| |
| private void startKerberos( ServerStartupConfiguration cfg, Hashtable env ) |
| { |
| if ( cfg.isEnableKerberos() ) |
| { |
| try |
| { |
| KdcConfiguration kdcConfiguration = new KdcConfiguration( env, LoadStrategy.PROPS ); |
| PrincipalStore kdcStore = new JndiPrincipalStoreImpl( kdcConfiguration, this ); |
| |
| DatagramAcceptorConfig udpConfig = new DatagramAcceptorConfig(); |
| udpConfig.setThreadModel( threadModel ); |
| |
| SocketAcceptorConfig tcpConfig = new SocketAcceptorConfig(); |
| tcpConfig.setDisconnectOnUnbind( false ); |
| tcpConfig.setReuseAddress( true ); |
| tcpConfig.setFilterChainBuilder( new DefaultIoFilterChainBuilder() ); |
| tcpConfig.setThreadModel( threadModel ); |
| |
| tcpKdcServer = new KerberosServer( kdcConfiguration, tcpAcceptor, tcpConfig, kdcStore ); |
| udpKdcServer = new KerberosServer( kdcConfiguration, udpAcceptor, udpConfig, kdcStore ); |
| } |
| catch ( Throwable t ) |
| { |
| log.error( "Failed to start the Kerberos service", t ); |
| } |
| } |
| } |
| |
| |
| private void startChangePassword( ServerStartupConfiguration cfg, Hashtable env ) |
| { |
| if ( cfg.isEnableChangePassword() ) |
| { |
| try |
| { |
| ChangePasswordConfiguration changePasswordConfiguration = new ChangePasswordConfiguration( env, |
| LoadStrategy.PROPS ); |
| PrincipalStore store = new JndiPrincipalStoreImpl( changePasswordConfiguration, this ); |
| |
| DatagramAcceptorConfig udpConfig = new DatagramAcceptorConfig(); |
| udpConfig.setThreadModel( threadModel ); |
| |
| SocketAcceptorConfig tcpConfig = new SocketAcceptorConfig(); |
| tcpConfig.setDisconnectOnUnbind( false ); |
| tcpConfig.setReuseAddress( true ); |
| tcpConfig.setFilterChainBuilder( new DefaultIoFilterChainBuilder() ); |
| tcpConfig.setThreadModel( threadModel ); |
| |
| tcpChangePasswordServer = new ChangePasswordServer( changePasswordConfiguration, tcpAcceptor, |
| tcpConfig, store ); |
| udpChangePasswordServer = new ChangePasswordServer( changePasswordConfiguration, udpAcceptor, |
| udpConfig, store ); |
| } |
| catch ( Throwable t ) |
| { |
| log.error( "Failed to start the Change Password service", t ); |
| } |
| } |
| } |
| |
| |
| private void startNTP( ServerStartupConfiguration cfg, Hashtable env ) |
| { |
| if ( cfg.isEnableNtp() ) |
| { |
| try |
| { |
| NtpConfiguration ntpConfig = new NtpConfiguration( env, LoadStrategy.PROPS ); |
| |
| DatagramAcceptorConfig udpConfig = new DatagramAcceptorConfig(); |
| udpConfig.setThreadModel( threadModel ); |
| |
| SocketAcceptorConfig tcpConfig = new SocketAcceptorConfig(); |
| tcpConfig.setDisconnectOnUnbind( false ); |
| tcpConfig.setReuseAddress( true ); |
| tcpConfig.setFilterChainBuilder( new DefaultIoFilterChainBuilder() ); |
| tcpConfig.setThreadModel( threadModel ); |
| |
| tcpNtpServer = new NtpServer( ntpConfig, tcpAcceptor, tcpConfig ); |
| udpNtpServer = new NtpServer( ntpConfig, udpAcceptor, udpConfig ); |
| } |
| catch ( Throwable t ) |
| { |
| log.error( "Failed to start the NTP service", t ); |
| } |
| } |
| } |
| |
| |
| private void stopLDAP0( int port ) |
| { |
| try |
| { |
| // we should unbind the service before we begin sending the notice |
| // of disconnect so new connections are not formed while we process |
| List writeFutures = new ArrayList(); |
| |
| // If the socket has already been unbound as with a successful |
| // GracefulShutdownRequest then this will complain that the service |
| // is not bound - this is ok because the GracefulShutdown has already |
| // sent notices to to the existing active sessions |
| List sessions = null; |
| |
| try |
| { |
| sessions = new ArrayList( tcpAcceptor.getManagedSessions( new InetSocketAddress( port ) ) ); |
| } |
| catch ( IllegalArgumentException e ) |
| { |
| log.warn( "Seems like the LDAP service (" + port + ") has already been unbound." ); |
| return; |
| } |
| |
| tcpAcceptor.unbind( new InetSocketAddress( port ) ); |
| |
| if ( log.isInfoEnabled() ) |
| { |
| log.info( "Unbind of an LDAP service (" + port + ") is complete." ); |
| log.info( "Sending notice of disconnect to existing clients sessions." ); |
| } |
| |
| // Send Notification of Disconnection messages to all connected clients. |
| if ( sessions != null ) |
| { |
| for ( Iterator i = sessions.iterator(); i.hasNext(); ) |
| { |
| IoSession session = ( IoSession ) i.next(); |
| writeFutures.add( session.write( NoticeOfDisconnect.UNAVAILABLE ) ); |
| } |
| } |
| |
| // And close the connections when the NoDs are sent. |
| Iterator sessionIt = sessions.iterator(); |
| |
| for ( Iterator i = writeFutures.iterator(); i.hasNext(); ) |
| { |
| WriteFuture future = ( WriteFuture ) i.next(); |
| future.join( 1000 ); |
| ( ( IoSession ) sessionIt.next() ).close(); |
| } |
| } |
| catch ( Exception e ) |
| { |
| log.warn( "Failed to sent NoD.", e ); |
| } |
| } |
| } |