001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009-2010 Sun Microsystems, Inc. 025 * Portions copyright 2012-2014 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.ldap; 029 030import static com.forgerock.opendj.util.StaticUtils.*; 031 032import java.io.Closeable; 033import java.io.IOException; 034import java.net.InetAddress; 035import java.net.InetSocketAddress; 036 037import org.forgerock.opendj.ldap.spi.LDAPListenerImpl; 038import org.forgerock.opendj.ldap.spi.TransportProvider; 039import org.forgerock.util.Reject; 040 041/** 042 * An LDAP server connection listener which waits for LDAP connection requests 043 * to come in over the network and binds them to a {@link ServerConnection} 044 * created using the provided {@link ServerConnectionFactory}. 045 * <p> 046 * When processing requests, {@code ServerConnection} implementations are passed 047 * an integer as the first parameter. This integer represents the 048 * {@code requestID} associated with the client request and corresponds to the 049 * {@code requestID} passed as a parameter to abandon and cancel extended 050 * requests. The request ID may also be useful for logging purposes. 051 * <p> 052 * An {@code LDAPListener} does not require {@code ServerConnection} 053 * implementations to return a result when processing requests. More 054 * specifically, an {@code LDAPListener} does not maintain any internal state 055 * information associated with each request which must be released. This is 056 * useful when implementing LDAP abandon operations which may prevent results 057 * being sent for abandoned operations. 058 * <p> 059 * The following code illustrates how to create a simple LDAP server: 060 * 061 * <pre> 062 * class MyClientConnection implements ServerConnection<Integer> { 063 * private final LDAPClientContext clientContext; 064 * 065 * private MyClientConnection(LDAPClientContext clientContext) { 066 * this.clientContext = clientContext; 067 * } 068 * 069 * public void add(Integer requestID, AddRequest request, ResultHandler<Result> handler, 070 * IntermediateResponseHandler intermediateResponseHandler) 071 * throws UnsupportedOperationException { 072 * // ... 073 * } 074 * 075 * // ... 076 * 077 * } 078 * 079 * class MyServer implements ServerConnectionFactory<LDAPClientContext, RequestContext> { 080 * public ServerConnection<RequestContext> accept(LDAPClientContext context) { 081 * System.out.println("Connection from: " + context.getPeerAddress()); 082 * return new MyClientConnection(context); 083 * } 084 * } 085 * 086 * public static void main(String[] args) throws Exception { 087 * LDAPListener listener = new LDAPListener(1389, new MyServer()); 088 * 089 * // ... 090 * 091 * listener.close(); 092 * } 093 * </pre> 094 */ 095public final class LDAPListener implements Closeable { 096 097 /** 098 * We implement the factory using the pimpl idiom in order have 099 * cleaner Javadoc which does not expose implementation methods. 100 */ 101 private final LDAPListenerImpl impl; 102 103 /** 104 * Transport provider that provides the implementation of this listener. 105 */ 106 private TransportProvider provider; 107 108 /** 109 * Creates a new LDAP listener implementation which will listen for LDAP 110 * client connections at the provided address. 111 * 112 * @param port 113 * The port to listen on. 114 * @param factory 115 * The server connection factory which will be used to create 116 * server connections. 117 * @throws IOException 118 * If an error occurred while trying to listen on the provided 119 * address. 120 * @throws NullPointerException 121 * If {code factory} was {@code null}. 122 */ 123 public LDAPListener(final int port, 124 final ServerConnectionFactory<LDAPClientContext, Integer> factory) throws IOException { 125 this(port, factory, new LDAPListenerOptions()); 126 } 127 128 /** 129 * Creates a new LDAP listener implementation which will listen for LDAP 130 * client connections at the provided address. 131 * 132 * @param port 133 * The port to listen on. 134 * @param factory 135 * The server connection factory which will be used to create 136 * server connections. 137 * @param options 138 * The LDAP listener options. 139 * @throws IOException 140 * If an error occurred while trying to listen on the provided 141 * address. 142 * @throws NullPointerException 143 * If {code factory} or {@code options} was {@code null}. 144 */ 145 public LDAPListener(final int port, 146 final ServerConnectionFactory<LDAPClientContext, Integer> factory, 147 final LDAPListenerOptions options) throws IOException { 148 Reject.ifNull(factory, options); 149 final InetSocketAddress address = new InetSocketAddress(port); 150 this.provider = getProvider(TransportProvider.class, options.getTransportProvider(), 151 options.getProviderClassLoader()); 152 this.impl = provider.getLDAPListener(address, factory, options); 153 } 154 155 /** 156 * Creates a new LDAP listener implementation which will listen for LDAP 157 * client connections at the provided address. 158 * 159 * @param address 160 * The address to listen on. 161 * @param factory 162 * The server connection factory which will be used to create 163 * server connections. 164 * @throws IOException 165 * If an error occurred while trying to listen on the provided 166 * address. 167 * @throws NullPointerException 168 * If {@code address} or {code factory} was {@code null}. 169 */ 170 public LDAPListener(final InetSocketAddress address, 171 final ServerConnectionFactory<LDAPClientContext, Integer> factory) throws IOException { 172 this(address, factory, new LDAPListenerOptions()); 173 } 174 175 /** 176 * Creates a new LDAP listener implementation which will listen for LDAP 177 * client connections at the provided address. 178 * 179 * @param address 180 * The address to listen on. 181 * @param factory 182 * The server connection factory which will be used to create 183 * server connections. 184 * @param options 185 * The LDAP listener options. 186 * @throws IOException 187 * If an error occurred while trying to listen on the provided 188 * address. 189 * @throws NullPointerException 190 * If {@code address}, {code factory}, or {@code options} was 191 * {@code null}. 192 */ 193 public LDAPListener(final InetSocketAddress address, 194 final ServerConnectionFactory<LDAPClientContext, Integer> factory, 195 final LDAPListenerOptions options) throws IOException { 196 Reject.ifNull(address, factory, options); 197 this.provider = getProvider(TransportProvider.class, options.getTransportProvider(), 198 options.getProviderClassLoader()); 199 this.impl = provider.getLDAPListener(address, factory, options); 200 } 201 202 /** 203 * Creates a new LDAP listener implementation which will listen for LDAP 204 * client connections at the provided address. 205 * 206 * @param host 207 * The address to listen on. 208 * @param port 209 * The port to listen on. 210 * @param factory 211 * The server connection factory which will be used to create 212 * server connections. 213 * @throws IOException 214 * If an error occurred while trying to listen on the provided 215 * address. 216 * @throws NullPointerException 217 * If {@code host} or {code factory} was {@code null}. 218 */ 219 public LDAPListener(final String host, final int port, 220 final ServerConnectionFactory<LDAPClientContext, Integer> factory) throws IOException { 221 this(host, port, factory, new LDAPListenerOptions()); 222 } 223 224 /** 225 * Creates a new LDAP listener implementation which will listen for LDAP 226 * client connections at the provided address. 227 * 228 * @param host 229 * The address to listen on. 230 * @param port 231 * The port to listen on. 232 * @param factory 233 * The server connection factory which will be used to create 234 * server connections. 235 * @param options 236 * The LDAP listener options. 237 * @throws IOException 238 * If an error occurred while trying to listen on the provided 239 * address. 240 * @throws NullPointerException 241 * If {@code host}, {code factory}, or {@code options} was 242 * {@code null}. 243 */ 244 public LDAPListener(final String host, final int port, 245 final ServerConnectionFactory<LDAPClientContext, Integer> factory, 246 final LDAPListenerOptions options) throws IOException { 247 Reject.ifNull(host, factory, options); 248 final InetSocketAddress address = new InetSocketAddress(host, port); 249 this.provider = getProvider(TransportProvider.class, options.getTransportProvider(), 250 options.getProviderClassLoader()); 251 this.impl = provider.getLDAPListener(address, factory, options); 252 } 253 254 /** 255 * Closes this LDAP connection listener. 256 */ 257 @Override 258 public void close() { 259 impl.close(); 260 } 261 262 /** 263 * Returns the {@code InetAddress} that this LDAP listener is listening on. 264 * 265 * @return The {@code InetAddress} that this LDAP listener is listening on. 266 */ 267 public InetAddress getAddress() { 268 return getSocketAddress().getAddress(); 269 } 270 271 /** 272 * Returns the host name that this LDAP listener is listening on. The 273 * returned host name is the same host name that was provided during 274 * construction and may be an IP address. More specifically, this method 275 * will not perform a reverse DNS lookup. 276 * 277 * @return The host name that this LDAP listener is listening on. 278 */ 279 public String getHostName() { 280 return Connections.getHostString(getSocketAddress()); 281 } 282 283 /** 284 * Returns the port that this LDAP listener is listening on. 285 * 286 * @return The port that this LDAP listener is listening on. 287 */ 288 public int getPort() { 289 return getSocketAddress().getPort(); 290 } 291 292 /** 293 * Returns the address that this LDAP listener is listening on. 294 * 295 * @return The address that this LDAP listener is listening on. 296 */ 297 public InetSocketAddress getSocketAddress() { 298 return impl.getSocketAddress(); 299 } 300 301 /** 302 * Returns the name of the transport provider, which provides the implementation 303 * of this factory. 304 * 305 * @return The name of actual transport provider. 306 */ 307 public String getProviderName() { 308 return provider.getName(); 309 } 310 311 @Override 312 public String toString() { 313 return impl.toString(); 314 } 315 316}