| | |
| | | ! (the "License"). You may not use this file except in compliance |
| | | ! with the License. |
| | | ! |
| | | ! You can obtain a copy of the license at |
| | | ! trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | ! You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | ! or http://forgerock.org/license/CDDLv1.0.html. |
| | | ! See the License for the specific language governing permissions |
| | | ! and limitations under the License. |
| | | ! |
| | | ! When distributing Covered Code, include this CDDL HEADER in each |
| | | ! file and include the License file at |
| | | ! trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | ! add the following below this CDDL HEADER, with the fields enclosed |
| | | ! by brackets "[]" replaced with your own identifying information: |
| | | ! file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | ! If applicable, add the following below this CDDL HEADER, with the |
| | | ! fields enclosed by brackets "[]" replaced with your own identifying |
| | | ! information: |
| | | ! Portions Copyright [yyyy] [name of copyright owner] |
| | | ! |
| | | ! CDDL HEADER END |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | */ |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldif.LDIFEntryWriter; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Demonstrates accessing server information about capabilities and schema. |
| | | */ |
| | | public final class GetInfo |
| | | { |
| | | // Connection information |
| | | private static String host; |
| | | private static int port; |
| | | // The kind of server information to request (all, controls, extops) |
| | | private static String infoType; |
| | | public final class GetInfo { |
| | | // Connection information |
| | | private static String host; |
| | | private static int port; |
| | | // The kind of server information to request (all, controls, extops) |
| | | private static String infoType; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Access the directory over LDAP to request information about capabilities |
| | | * and schema. |
| | | * |
| | | * @param args |
| | | * The command line arguments |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | parseArgs(args); |
| | | connect(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Authenticate over LDAP. |
| | | */ |
| | | private static void connect() |
| | | { |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | connection = factory.getConnection(); |
| | | connection.bind("", "".toCharArray()); // Anonymous bind |
| | | |
| | | final String attributeList; |
| | | if (infoType.toLowerCase().equals("controls")) |
| | | { |
| | | attributeList = "supportedControl"; |
| | | } |
| | | else if (infoType.toLowerCase().equals("extops")) |
| | | { |
| | | attributeList = "supportedExtension"; |
| | | } |
| | | else |
| | | { |
| | | attributeList = "+"; // All operational attributes |
| | | } |
| | | |
| | | final SearchResultEntry entry = connection.searchSingleEntry( |
| | | "", // DN is "" for root DSE. |
| | | SearchScope.BASE_OBJECT, // Read only the root DSE. |
| | | "objectclass=*", // Every object matches this filter. |
| | | attributeList); // Return these requested attributes. |
| | | |
| | | final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); |
| | | writer.writeComment("Root DSE for LDAP server at " + host + ":" + port); |
| | | if (entry != null) |
| | | { |
| | | writer.writeEntry(entry); |
| | | } |
| | | writer.flush(); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static void giveUp() |
| | | { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * |
| | | * @param args |
| | | * host port bind-dn bind-password info-type |
| | | */ |
| | | private static void parseArgs(final String[] args) |
| | | { |
| | | if (args.length != 3) |
| | | { |
| | | giveUp(); |
| | | /** |
| | | * Access the directory over LDAP to request information about capabilities |
| | | * and schema. |
| | | * |
| | | * @param args |
| | | * The command line arguments |
| | | */ |
| | | public static void main(final String[] args) { |
| | | parseArgs(args); |
| | | connect(); |
| | | } |
| | | |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | infoType = args[2]; // all, controls, or extops |
| | | if (!(infoType.toLowerCase().equals("all") |
| | | || infoType.toLowerCase().equals("controls") |
| | | || infoType.toLowerCase().equals("extops"))) |
| | | { |
| | | giveUp(); |
| | | /** |
| | | * Authenticate over LDAP. |
| | | */ |
| | | private static void connect() { |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | connection = factory.getConnection(); |
| | | connection.bind("", "".toCharArray()); // Anonymous bind |
| | | |
| | | final String attributeList; |
| | | if (infoType.toLowerCase().equals("controls")) { |
| | | attributeList = "supportedControl"; |
| | | } else if (infoType.toLowerCase().equals("extops")) { |
| | | attributeList = "supportedExtension"; |
| | | } else { |
| | | attributeList = "+"; // All operational attributes |
| | | } |
| | | |
| | | final SearchResultEntry entry = connection.searchSingleEntry("", // DN |
| | | // is |
| | | // "" |
| | | // for |
| | | // root |
| | | // DSE. |
| | | SearchScope.BASE_OBJECT, // Read only the root DSE. |
| | | "objectclass=*", // Every object matches this filter. |
| | | attributeList); // Return these requested attributes. |
| | | |
| | | final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); |
| | | writer.writeComment("Root DSE for LDAP server at " + host + ":" + port); |
| | | if (entry != null) { |
| | | writer.writeEntry(entry); |
| | | } |
| | | writer.flush(); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void giveUp() { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * |
| | | * @param args |
| | | * host port bind-dn bind-password info-type |
| | | */ |
| | | private static void parseArgs(final String[] args) { |
| | | if (args.length != 3) { |
| | | giveUp(); |
| | | } |
| | | |
| | | private static void printUsage() |
| | | { |
| | | System.err.println("Usage: host port info-type"); |
| | | System.err.println("\tAll arguments are required."); |
| | | System.err |
| | | .println("\tinfo-type to get can be either all, controls, or extops."); |
| | | } |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | infoType = args[2]; // all, controls, or extops |
| | | if (!(infoType.toLowerCase().equals("all") || infoType.toLowerCase().equals("controls") || infoType |
| | | .toLowerCase().equals("extops"))) { |
| | | giveUp(); |
| | | } |
| | | } |
| | | |
| | | private static void printUsage() { |
| | | System.err.println("Usage: host port info-type"); |
| | | System.err.println("\tAll arguments are required."); |
| | | System.err.println("\tinfo-type to get can be either all, controls, or extops."); |
| | | } |
| | | |
| | | |
| | | private GetInfo() |
| | | { |
| | | // Not used. |
| | | } |
| | | private GetInfo() { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.FileNotFoundException; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldif.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldif.ChangeRecord; |
| | | import org.forgerock.opendj.ldif.ConnectionChangeRecordWriter; |
| | | import org.forgerock.opendj.ldif.LDIFChangeRecordReader; |
| | | |
| | | /** |
| | | * An example client application which applies update operations to a Directory |
| | |
| | | * <host> <port> <username> <password> [<ldifFile>] |
| | | * </pre> |
| | | */ |
| | | public final class Modify |
| | | { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, LDIF |
| | | * file name containing the update operations (will use stdin if not |
| | | * provided). |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length < 4 || args.length > 5) |
| | | { |
| | | System.err |
| | | .println("Usage: host port username password [ldifFileName]"); |
| | | System.exit(1); |
| | | public final class Modify { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, |
| | | * LDIF file name containing the update operations (will use |
| | | * stdin if not provided). |
| | | */ |
| | | public static void main(final String[] args) { |
| | | if (args.length < 4 || args.length > 5) { |
| | | System.err.println("Usage: host port username password [ldifFileName]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | |
| | | // Create the LDIF reader which will either used the named file, if |
| | | // provided, or stdin. |
| | | InputStream ldif; |
| | | if (args.length > 4) { |
| | | try { |
| | | ldif = new FileInputStream(args[4]); |
| | | } catch (final FileNotFoundException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | } else { |
| | | ldif = System.in; |
| | | } |
| | | final LDIFChangeRecordReader reader = new LDIFChangeRecordReader(ldif); |
| | | |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Write the changes. |
| | | final ConnectionChangeRecordWriter writer = |
| | | new ConnectionChangeRecordWriter(connection); |
| | | while (reader.hasNext()) { |
| | | ChangeRecord changeRecord = reader.readChangeRecord(); |
| | | writer.writeChangeRecord(changeRecord); |
| | | System.err.println("Successfully modified entry " |
| | | + changeRecord.getName().toString()); |
| | | } |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | |
| | | try { |
| | | reader.close(); |
| | | } catch (final IOException ignored) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | |
| | | // Create the LDIF reader which will either used the named file, if |
| | | // provided, or stdin. |
| | | InputStream ldif; |
| | | if (args.length > 4) |
| | | { |
| | | try |
| | | { |
| | | ldif = new FileInputStream(args[4]); |
| | | } |
| | | catch (final FileNotFoundException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | private Modify() { |
| | | // Not used. |
| | | } |
| | | else |
| | | { |
| | | ldif = System.in; |
| | | } |
| | | final LDIFChangeRecordReader reader = new LDIFChangeRecordReader( |
| | | ldif); |
| | | |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory( |
| | | hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Write the changes. |
| | | final ConnectionChangeRecordWriter writer = |
| | | new ConnectionChangeRecordWriter(connection); |
| | | while (reader.hasNext()) |
| | | { |
| | | ChangeRecord changeRecord = reader.readChangeRecord(); |
| | | writer.writeChangeRecord(changeRecord); |
| | | System.err.println("Successfully modified entry " |
| | | + changeRecord.getName().toString()); |
| | | } |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | |
| | | try |
| | | { |
| | | reader.close(); |
| | | } |
| | | catch (final IOException ignored) |
| | | { |
| | | // Ignore. |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private Modify() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.controls.*; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ConnectionFactory; |
| | | import org.forgerock.opendj.ldap.Connections; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.LDAPClientContext; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.LDAPListener; |
| | | import org.forgerock.opendj.ldap.LDAPListenerOptions; |
| | | import org.forgerock.opendj.ldap.RequestContext; |
| | | import org.forgerock.opendj.ldap.RequestHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.RoundRobinLoadBalancingAlgorithm; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.ServerConnectionFactory; |
| | | import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.BindRequest; |
| | | import org.forgerock.opendj.ldap.requests.CancelExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.Request; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | |
| | | /** |
| | | * An LDAP load balancing proxy which forwards requests to one or more remote |
| | |
| | | * [<remoteAddress2> <remotePort2> ...] |
| | | * </pre> |
| | | */ |
| | | public final class Proxy |
| | | { |
| | | private static final class ProxyBackend implements |
| | | RequestHandler<RequestContext> |
| | | { |
| | | private final ConnectionFactory factory; |
| | | private final ConnectionFactory bindFactory; |
| | | public final class Proxy { |
| | | private static final class ProxyBackend implements RequestHandler<RequestContext> { |
| | | private final ConnectionFactory factory; |
| | | private final ConnectionFactory bindFactory; |
| | | |
| | | |
| | | |
| | | private ProxyBackend(final ConnectionFactory factory, |
| | | final ConnectionFactory bindFactory) |
| | | { |
| | | this.factory = factory; |
| | | this.bindFactory = bindFactory; |
| | | } |
| | | |
| | | |
| | | |
| | | private abstract class AbstractRequestCompletionHandler |
| | | <R extends Result, H extends ResultHandler<? super R>> |
| | | implements ResultHandler<R> |
| | | { |
| | | final H resultHandler; |
| | | final Connection connection; |
| | | |
| | | |
| | | |
| | | AbstractRequestCompletionHandler(final Connection connection, |
| | | final H resultHandler) |
| | | { |
| | | this.connection = connection; |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | connection.close(); |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleResult(final R result) |
| | | { |
| | | connection.close(); |
| | | resultHandler.handleResult(result); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private abstract class ConnectionCompletionHandler<R extends Result> |
| | | implements ResultHandler<Connection> |
| | | { |
| | | private final ResultHandler<? super R> resultHandler; |
| | | |
| | | |
| | | |
| | | ConnectionCompletionHandler(final ResultHandler<? super R> resultHandler) |
| | | { |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public abstract void handleResult(Connection connection); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final class RequestCompletionHandler<R extends Result> extends |
| | | AbstractRequestCompletionHandler<R, ResultHandler<? super R>> |
| | | { |
| | | RequestCompletionHandler(final Connection connection, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | super(connection, resultHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class SearchRequestCompletionHandler extends |
| | | AbstractRequestCompletionHandler<Result, SearchResultHandler> implements |
| | | SearchResultHandler |
| | | { |
| | | |
| | | SearchRequestCompletionHandler(final Connection connection, |
| | | final SearchResultHandler resultHandler) |
| | | { |
| | | super(connection, resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean handleEntry(final SearchResultEntry entry) |
| | | { |
| | | return resultHandler.handleEntry(entry); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean handleReference( |
| | | final SearchResultReference reference) |
| | | { |
| | | return resultHandler.handleReference(reference); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final RequestContext requestContext, |
| | | final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.addAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | private ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) { |
| | | this.factory = factory; |
| | | this.bindFactory = bindFactory; |
| | | } |
| | | |
| | | }; |
| | | private abstract class AbstractRequestCompletionHandler<R extends Result, H extends ResultHandler<? super R>> |
| | | implements ResultHandler<R> { |
| | | final H resultHandler; |
| | | final Connection connection; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) { |
| | | this.connection = connection; |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, |
| | | final int version, final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) |
| | | { |
| | | |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } |
| | | else |
| | | { |
| | | // Authenticate using a separate bind connection pool, because we |
| | | // don't want to change the state of the pooled connection. |
| | | final ConnectionCompletionHandler<BindResult> outerHandler = |
| | | new ConnectionCompletionHandler<BindResult>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final ResultHandler<BindResult> innerHandler = |
| | | new ResultHandler<BindResult>() |
| | | { |
| | | |
| | | @Override |
| | | public final void handleErrorResult( |
| | | final ErrorResultException error) |
| | | { |
| | | @Override |
| | | public final void handleErrorResult(final ErrorResultException error) { |
| | | connection.close(); |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleResult(final BindResult result) |
| | | { |
| | | @Override |
| | | public final void handleResult(final R result) { |
| | | connection.close(); |
| | | proxiedAuthControl = ProxiedAuthV2RequestControl |
| | | .newControl("dn:" + request.getName()); |
| | | resultHandler.handleResult(result); |
| | | } |
| | | }; |
| | | connection.bindAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | |
| | | proxiedAuthControl = null; |
| | | bindFactory.getConnectionAsync(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<CompareResult> outerHandler = |
| | | new ConnectionCompletionHandler<CompareResult>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<CompareResult> innerHandler = |
| | | new RequestCompletionHandler<CompareResult>(connection, |
| | | resultHandler); |
| | | connection.compareAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | private abstract class ConnectionCompletionHandler<R extends Result> implements |
| | | ResultHandler<Connection> { |
| | | private final ResultHandler<? super R> resultHandler; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | ConnectionCompletionHandler(final ResultHandler<? super R> resultHandler) { |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | @Override |
| | | public final void handleErrorResult(final ErrorResultException error) { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | @Override |
| | | public abstract void handleResult(Connection connection); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, |
| | | final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.deleteAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | if (request.getOID().equals(CancelExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Cancel extended request operation not supported")); |
| | | } |
| | | else if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "StartTLS extended request operation not supported")); |
| | | } |
| | | else |
| | | { |
| | | // Forward all other extended operations. |
| | | addProxiedAuthControl(request); |
| | | |
| | | final ConnectionCompletionHandler<R> outerHandler = |
| | | new ConnectionCompletionHandler<R>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<R> innerHandler = |
| | | new RequestCompletionHandler<R>(connection, resultHandler); |
| | | connection.extendedRequestAsync(request, |
| | | intermediateResponseHandler, innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, |
| | | final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | private final class RequestCompletionHandler<R extends Result> extends |
| | | AbstractRequestCompletionHandler<R, ResultHandler<? super R>> { |
| | | RequestCompletionHandler(final Connection connection, |
| | | final ResultHandler<? super R> resultHandler) { |
| | | super(connection, resultHandler); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | private final class SearchRequestCompletionHandler extends |
| | | AbstractRequestCompletionHandler<Result, SearchResultHandler> implements |
| | | SearchResultHandler { |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | SearchRequestCompletionHandler(final Connection connection, |
| | | final SearchResultHandler resultHandler) { |
| | | super(connection, resultHandler); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean handleEntry(final SearchResultEntry entry) { |
| | | return resultHandler.handleEntry(entry); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean handleReference(final SearchResultReference reference) { |
| | | return resultHandler.handleReference(reference); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyDNAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, |
| | | final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | final SearchRequestCompletionHandler innerHandler = |
| | | new SearchRequestCompletionHandler(connection, resultHandler); |
| | | connection.searchAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | public void handleAdd(final RequestContext requestContext, final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.addAsync(request, intermediateResponseHandler, innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | }; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, final int version, |
| | | final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) { |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } else { |
| | | // Authenticate using a separate bind connection pool, because |
| | | // we |
| | | // don't want to change the state of the pooled connection. |
| | | final ConnectionCompletionHandler<BindResult> outerHandler = |
| | | new ConnectionCompletionHandler<BindResult>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final ResultHandler<BindResult> innerHandler = |
| | | new ResultHandler<BindResult>() { |
| | | |
| | | @Override |
| | | public final void handleErrorResult( |
| | | final ErrorResultException error) { |
| | | connection.close(); |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | @Override |
| | | public final void handleResult(final BindResult result) { |
| | | connection.close(); |
| | | proxiedAuthControl = |
| | | ProxiedAuthV2RequestControl |
| | | .newControl("dn:" |
| | | + request.getName()); |
| | | resultHandler.handleResult(result); |
| | | } |
| | | }; |
| | | connection.bindAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | proxiedAuthControl = null; |
| | | bindFactory.getConnectionAsync(outerHandler); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<CompareResult> outerHandler = |
| | | new ConnectionCompletionHandler<CompareResult>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<CompareResult> innerHandler = |
| | | new RequestCompletionHandler<CompareResult>(connection, |
| | | resultHandler); |
| | | connection.compareAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.deleteAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) { |
| | | if (request.getOID().equals(CancelExtendedRequest.OID)) { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "Cancel extended request operation not supported")); |
| | | } else if (request.getOID().equals(StartTLSExtendedRequest.OID)) { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "StartTLS extended request operation not supported")); |
| | | } else { |
| | | // Forward all other extended operations. |
| | | addProxiedAuthControl(request); |
| | | |
| | | final ConnectionCompletionHandler<R> outerHandler = |
| | | new ConnectionCompletionHandler<R>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<R> innerHandler = |
| | | new RequestCompletionHandler<R>(connection, resultHandler); |
| | | connection.extendedRequestAsync(request, |
| | | intermediateResponseHandler, innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyDNAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) { |
| | | |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | final SearchRequestCompletionHandler innerHandler = |
| | | new SearchRequestCompletionHandler(connection, resultHandler); |
| | | connection.searchAsync(request, intermediateResponseHandler, |
| | | innerHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getConnectionAsync(outerHandler); |
| | | } |
| | | |
| | | private void addProxiedAuthControl(final Request request) { |
| | | final ProxiedAuthV2RequestControl control = proxiedAuthControl; |
| | | if (control != null) { |
| | | request.addControl(control); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: listen address, listen port, |
| | | * remote address1, remote port1, remote address2, remote port2, |
| | | * ... |
| | | */ |
| | | public static void main(final String[] args) { |
| | | if (args.length < 4 || args.length % 2 != 0) { |
| | | System.err.println("Usage: listenAddress listenPort " |
| | | + "remoteAddress1 remotePort1 remoteAddress2 remotePort2"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | |
| | | private void addProxiedAuthControl(final Request request) |
| | | { |
| | | final ProxiedAuthV2RequestControl control = proxiedAuthControl; |
| | | if (control != null) |
| | | { |
| | | request.addControl(control); |
| | | } |
| | | // Create load balancer. |
| | | final List<ConnectionFactory> factories = new LinkedList<ConnectionFactory>(); |
| | | final List<ConnectionFactory> bindFactories = new LinkedList<ConnectionFactory>(); |
| | | for (int i = 2; i < args.length; i += 2) { |
| | | final String remoteAddress = args[i]; |
| | | final int remotePort = Integer.parseInt(args[i + 1]); |
| | | |
| | | factories.add(Connections.newFixedConnectionPool(new LDAPConnectionFactory( |
| | | remoteAddress, remotePort), Integer.MAX_VALUE)); |
| | | bindFactories.add(Connections.newFixedConnectionPool(new LDAPConnectionFactory( |
| | | remoteAddress, remotePort), Integer.MAX_VALUE)); |
| | | } |
| | | final RoundRobinLoadBalancingAlgorithm algorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(factories); |
| | | final RoundRobinLoadBalancingAlgorithm bindAlgorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(bindFactories); |
| | | final ConnectionFactory factory = Connections.newLoadBalancer(algorithm); |
| | | final ConnectionFactory bindFactory = Connections.newLoadBalancer(bindAlgorithm); |
| | | |
| | | // Create a server connection adapter. |
| | | final ProxyBackend backend = new ProxyBackend(factory, bindFactory); |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = |
| | | Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try { |
| | | listener = new LDAPListener(localAddress, localPort, connectionHandler, options); |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } catch (final IOException e) { |
| | | System.out.println("Error listening on " + localAddress + ":" + localPort); |
| | | e.printStackTrace(); |
| | | } finally { |
| | | if (listener != null) { |
| | | listener.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: listen address, listen port, remote |
| | | * address1, remote port1, remote address2, remote port2, ... |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length < 4 || args.length % 2 != 0) |
| | | { |
| | | System.err.println("Usage: listenAddress listenPort " |
| | | + "remoteAddress1 remotePort1 remoteAddress2 remotePort2"); |
| | | System.exit(1); |
| | | private Proxy() { |
| | | // Not used. |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | |
| | | // Create load balancer. |
| | | final List<ConnectionFactory> factories = |
| | | new LinkedList<ConnectionFactory>(); |
| | | final List<ConnectionFactory> bindFactories = |
| | | new LinkedList<ConnectionFactory>(); |
| | | for (int i = 2; i < args.length; i += 2) |
| | | { |
| | | final String remoteAddress = args[i]; |
| | | final int remotePort = Integer.parseInt(args[i + 1]); |
| | | |
| | | factories.add(Connections.newFixedConnectionPool( |
| | | new LDAPConnectionFactory(remoteAddress, remotePort), |
| | | Integer.MAX_VALUE)); |
| | | bindFactories.add(Connections.newFixedConnectionPool( |
| | | new LDAPConnectionFactory(remoteAddress, remotePort), |
| | | Integer.MAX_VALUE)); |
| | | } |
| | | final RoundRobinLoadBalancingAlgorithm algorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(factories); |
| | | final RoundRobinLoadBalancingAlgorithm bindAlgorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(bindFactories); |
| | | final ConnectionFactory factory = Connections.newLoadBalancer(algorithm); |
| | | final ConnectionFactory bindFactory = Connections |
| | | .newLoadBalancer(bindAlgorithm); |
| | | |
| | | // Create a server connection adapter. |
| | | final ProxyBackend backend = new ProxyBackend(factory, bindFactory); |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler |
| | | = Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, connectionHandler, |
| | | options); |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.out |
| | | .println("Error listening on " + localAddress + ":" + localPort); |
| | | e.printStackTrace(); |
| | | } |
| | | finally |
| | | { |
| | | if (listener != null) |
| | | { |
| | | listener.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private Proxy() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.schema.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.DN; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.schema.AttributeType; |
| | | import org.forgerock.opendj.ldap.schema.MatchingRule; |
| | | import org.forgerock.opendj.ldap.schema.ObjectClass; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.schema.Syntax; |
| | | |
| | | /** |
| | | * An example client application which prints a summary of the schema on the |
| | |
| | | * <host> <port> <username> <password> |
| | | * </pre> |
| | | */ |
| | | public final class ReadSchema |
| | | { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password. |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length != 4) |
| | | { |
| | | System.err.println("Usage: host port username password"); |
| | | System.exit(1); |
| | | public final class ReadSchema { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password. |
| | | */ |
| | | public static void main(final String[] args) { |
| | | if (args.length != 4) { |
| | | System.err.println("Usage: host port username password"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Read the schema. |
| | | Schema schema = Schema.readSchemaForEntry(connection, DN.rootDN()); |
| | | |
| | | System.out.println("Attribute types"); |
| | | for (AttributeType at : schema.getAttributeTypes()) { |
| | | System.out.println(" " + at.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Object classes"); |
| | | for (ObjectClass oc : schema.getObjectClasses()) { |
| | | System.out.println(" " + oc.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Matching rules"); |
| | | for (MatchingRule mr : schema.getMatchingRules()) { |
| | | System.out.println(" " + mr.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Syntaxes"); |
| | | for (Syntax s : schema.getSyntaxes()) { |
| | | System.out.println(" " + s.getDescription()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | // Etc... |
| | | |
| | | System.out.println("WARNINGS"); |
| | | for (LocalizableMessage m : schema.getWarnings()) { |
| | | System.out.println(" " + m.toString()); |
| | | } |
| | | System.out.println(); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory( |
| | | hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Read the schema. |
| | | Schema schema = Schema.readSchemaForEntry(connection, DN.rootDN()); |
| | | |
| | | System.out.println("Attribute types"); |
| | | for (AttributeType at : schema.getAttributeTypes()) |
| | | { |
| | | System.out.println(" " + at.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Object classes"); |
| | | for (ObjectClass oc : schema.getObjectClasses()) |
| | | { |
| | | System.out.println(" " + oc.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Matching rules"); |
| | | for (MatchingRule mr : schema.getMatchingRules()) |
| | | { |
| | | System.out.println(" " + mr.getNameOrOID()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | System.out.println("Syntaxes"); |
| | | for (Syntax s : schema.getSyntaxes()) |
| | | { |
| | | System.out.println(" " + s.getDescription()); |
| | | } |
| | | System.out.println(); |
| | | |
| | | // Etc... |
| | | |
| | | System.out.println("WARNINGS"); |
| | | for (LocalizableMessage m : schema.getWarnings()) |
| | | { |
| | | System.out.println(" " + m.toString()); |
| | | } |
| | | System.out.println(); |
| | | private ReadSchema() { |
| | | // Not used. |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private ReadSchema() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | import org.forgerock.opendj.ldap.requests.PlainSASLBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An example client application which performs SASL PLAIN authentication to a |
| | | * directory server over LDAP with StartTLS. This example takes the following |
| | |
| | | * <li>authcid - Authentication identity</li> |
| | | * <li>passwd - Password of the user to authenticate</li> |
| | | * </ul> |
| | | * The host, port, authcid, and passwd are required. |
| | | * SASL PLAIN is described in <a href="http://www.ietf.org/rfc/rfc4616.txt">RFC |
| | | * 4616</a>. |
| | | * The host, port, authcid, and passwd are required. SASL PLAIN is described in |
| | | * <a href="http://www.ietf.org/rfc/rfc4616.txt">RFC 4616</a>. |
| | | * <p> |
| | | * The authzid and authcid are prefixed as described in <a |
| | | * href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513, section |
| | |
| | | * By default, OpenDJ is set up for SASL PLAIN to use the Exact Match Identity |
| | | * Mapper to find entries by searching uid values for the user ID. In other |
| | | * words, the following examples are equivalent. |
| | | * |
| | | * <pre> |
| | | * dn:uid=bjensen,ou=people,dc=example,dc=com |
| | | * u:bjensen |
| | | * </pre> |
| | | */ |
| | | public final class SASLAuth |
| | | { |
| | | /** |
| | | * Authenticate to the directory using SASL PLAIN. |
| | | * @param args The command line arguments |
| | | */ |
| | | public static void main(String[] args) |
| | | { |
| | | parseArgs(args); |
| | | Connection connection = null; |
| | | public final class SASLAuth { |
| | | /** |
| | | * Authenticate to the directory using SASL PLAIN. |
| | | * |
| | | * @param args |
| | | * The command line arguments |
| | | */ |
| | | public static void main(String[] args) { |
| | | parseArgs(args); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | final LDAPConnectionFactory factory = |
| | | new LDAPConnectionFactory(host, port, getTrustAllOptions()); |
| | | connection = factory.getConnection(); |
| | | PlainSASLBindRequest request = Requests.newPlainSASLBindRequest( |
| | | authcid, passwd.toCharArray()); |
| | | if (authzid != null) request.setAuthorizationID(authzid); |
| | | connection.bind(request); |
| | | System.out.println("Authenticated as " + authcid + "."); |
| | | try { |
| | | final LDAPConnectionFactory factory = |
| | | new LDAPConnectionFactory(host, port, getTrustAllOptions()); |
| | | connection = factory.getConnection(); |
| | | PlainSASLBindRequest request = |
| | | Requests.newPlainSASLBindRequest(authcid, passwd.toCharArray()); |
| | | if (authzid != null) { |
| | | request.setAuthorizationID(authzid); |
| | | } |
| | | connection.bind(request); |
| | | System.out.println("Authenticated as " + authcid + "."); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } catch (final GeneralSecurityException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | |
| | | /** |
| | | * For StartTLS the connection factory needs SSL context options. In the |
| | | * general case, a trust manager in the SSL context serves to check server |
| | | * certificates, and a key manager handles client keys when the server |
| | | * checks certificates from our client. |
| | | * |
| | | * OpenDJ directory server lets you install by default with a self-signed |
| | | * certificate that is not in the system trust store. To simplify this |
| | | * implementation trusts all server certificates. |
| | | */ |
| | | private static LDAPOptions getTrustAllOptions() throws GeneralSecurityException { |
| | | LDAPOptions lo = new LDAPOptions(); |
| | | SSLContext sslContext = |
| | | new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | lo.setSSLContext(sslContext); |
| | | lo.setUseStartTLS(true); |
| | | return lo; |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | |
| | | private static String host; |
| | | private static int port; |
| | | private static String authzid; |
| | | private static String authcid; |
| | | private static String passwd; |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * |
| | | * @param args |
| | | * host port [authzid] authcid passwd |
| | | */ |
| | | private static void parseArgs(String[] args) { |
| | | if (args.length < 4 || args.length > 5) { |
| | | giveUp(); |
| | | } |
| | | |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | |
| | | if (args.length == 5) { |
| | | authzid = args[2]; |
| | | authcid = args[3]; |
| | | passwd = args[4]; |
| | | } else { |
| | | authzid = null; |
| | | authcid = args[2]; |
| | | passwd = args[3]; |
| | | } |
| | | } |
| | | catch (final GeneralSecurityException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); |
| | | |
| | | private static void giveUp() { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | connection.close(); |
| | | |
| | | private static void printUsage() { |
| | | System.err.println("Usage: host port [authzid] authcid passwd"); |
| | | System.err.println("\tThe port must be able to handle LDAP with StartTLS."); |
| | | System.err.println("\tSee http://www.ietf.org/rfc/rfc4616.txt for more on SASL PLAIN."); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * For StartTLS the connection factory needs SSL context options. |
| | | * In the general case, a trust manager in the SSL context serves to check |
| | | * server certificates, and a key manager handles client keys when the server |
| | | * checks certificates from our client. |
| | | * |
| | | * OpenDJ directory server lets you install by default with a self-signed |
| | | * certificate that is not in the system trust store. To simplify this |
| | | * implementation trusts all server certificates. |
| | | */ |
| | | private static LDAPOptions getTrustAllOptions() |
| | | throws GeneralSecurityException |
| | | { |
| | | LDAPOptions lo = new LDAPOptions(); |
| | | SSLContext sslContext = new SSLContextBuilder() |
| | | .setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | lo.setSSLContext(sslContext); |
| | | lo.setUseStartTLS(true); |
| | | return lo; |
| | | } |
| | | |
| | | |
| | | |
| | | private static String host; |
| | | private static int port; |
| | | private static String authzid; |
| | | private static String authcid; |
| | | private static String passwd; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * @param args host port [authzid] authcid passwd |
| | | */ |
| | | private static void parseArgs(String[] args) |
| | | { |
| | | if (args.length < 4 || args.length > 5) giveUp(); |
| | | |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | |
| | | if (args.length == 5) |
| | | { |
| | | authzid = args[2]; |
| | | authcid = args[3]; |
| | | passwd = args[4]; |
| | | private SASLAuth() { |
| | | // Not used. |
| | | } |
| | | else |
| | | { |
| | | authzid = null; |
| | | authcid = args[2]; |
| | | passwd = args[3]; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static void giveUp() |
| | | { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | |
| | | |
| | | |
| | | private static void printUsage() |
| | | { |
| | | System.err.println( |
| | | "Usage: host port [authzid] authcid passwd"); |
| | | System.err.println( |
| | | "\tThe port must be able to handle LDAP with StartTLS."); |
| | | System.err.println( |
| | | "\tSee http://www.ietf.org/rfc/rfc4616.txt for more on SASL PLAIN."); |
| | | } |
| | | |
| | | |
| | | |
| | | private SASLAuth() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Arrays; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldif.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.ErrorResultIOException; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | import org.forgerock.opendj.ldif.ConnectionEntryReader; |
| | | import org.forgerock.opendj.ldif.LDIFEntryWriter; |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server. This example |
| | |
| | | * <baseDN> <scope> <filter> [<attibute> <attribute> ...] |
| | | * </pre> |
| | | */ |
| | | public final class Search |
| | | { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, base |
| | | * DN, scope, filter, and zero or more attributes to be retrieved. |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length < 7) |
| | | { |
| | | System.err |
| | | .println("Usage: host port username password baseDN scope " |
| | | + "filter [attribute ...]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | final String baseDN = args[4]; |
| | | final String scopeString = args[5]; |
| | | final String filter = args[6]; |
| | | String[] attributes; |
| | | if (args.length > 7) |
| | | { |
| | | attributes = Arrays.copyOfRange(args, 7, args.length); |
| | | } |
| | | else |
| | | { |
| | | attributes = new String[0]; |
| | | } |
| | | |
| | | SearchScope scope; |
| | | if (scopeString.equalsIgnoreCase("base")) |
| | | { |
| | | scope = SearchScope.BASE_OBJECT; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("one")) |
| | | { |
| | | scope = SearchScope.SINGLE_LEVEL; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("sub")) |
| | | { |
| | | scope = SearchScope.WHOLE_SUBTREE; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("subordinates")) |
| | | { |
| | | scope = SearchScope.SUBORDINATES; |
| | | } |
| | | else |
| | | { |
| | | System.err.println("Unknown scope: " + scopeString); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | // Create an LDIF writer which will write the search results to stdout. |
| | | final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); |
| | | |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory( |
| | | hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Read the entries and output them as LDIF. |
| | | final ConnectionEntryReader reader = connection.search(baseDN, |
| | | scope, filter, attributes); |
| | | while (reader.hasNext()) |
| | | { |
| | | if (!reader.isReference()) |
| | | { |
| | | final SearchResultEntry entry = reader.readEntry(); |
| | | writer.writeComment("Search result entry: " |
| | | + entry.getName().toString()); |
| | | writer.writeEntry(entry); |
| | | public final class Search { |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, |
| | | * base DN, scope, filter, and zero or more attributes to be |
| | | * retrieved. |
| | | */ |
| | | public static void main(final String[] args) { |
| | | if (args.length < 7) { |
| | | System.err.println("Usage: host port username password baseDN scope " |
| | | + "filter [attribute ...]"); |
| | | System.exit(1); |
| | | } |
| | | else |
| | | { |
| | | final SearchResultReference ref = reader.readReference(); |
| | | |
| | | // Got a continuation reference. |
| | | writer.writeComment("Search result reference: " |
| | | + ref.getURIs().toString()); |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | final String userName = args[2]; |
| | | final String password = args[3]; |
| | | final String baseDN = args[4]; |
| | | final String scopeString = args[5]; |
| | | final String filter = args[6]; |
| | | String[] attributes; |
| | | if (args.length > 7) { |
| | | attributes = Arrays.copyOfRange(args, 7, args.length); |
| | | } else { |
| | | attributes = new String[0]; |
| | | } |
| | | } |
| | | writer.flush(); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } |
| | | catch (final ErrorResultIOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System |
| | | .exit(e.getCause().getResult().getResultCode().intValue()); |
| | | return; |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | SearchScope scope; |
| | | if (scopeString.equalsIgnoreCase("base")) { |
| | | scope = SearchScope.BASE_OBJECT; |
| | | } else if (scopeString.equalsIgnoreCase("one")) { |
| | | scope = SearchScope.SINGLE_LEVEL; |
| | | } else if (scopeString.equalsIgnoreCase("sub")) { |
| | | scope = SearchScope.WHOLE_SUBTREE; |
| | | } else if (scopeString.equalsIgnoreCase("subordinates")) { |
| | | scope = SearchScope.SUBORDINATES; |
| | | } else { |
| | | System.err.println("Unknown scope: " + scopeString); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | // Create an LDIF writer which will write the search results to stdout. |
| | | final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); |
| | | |
| | | private Search() |
| | | { |
| | | // Not used. |
| | | } |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port); |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password.toCharArray()); |
| | | |
| | | // Read the entries and output them as LDIF. |
| | | final ConnectionEntryReader reader = |
| | | connection.search(baseDN, scope, filter, attributes); |
| | | while (reader.hasNext()) { |
| | | if (!reader.isReference()) { |
| | | final SearchResultEntry entry = reader.readEntry(); |
| | | writer.writeComment("Search result entry: " + entry.getName().toString()); |
| | | writer.writeEntry(entry); |
| | | } else { |
| | | final SearchResultReference ref = reader.readReference(); |
| | | |
| | | // Got a continuation reference. |
| | | writer.writeComment("Search result reference: " + ref.getURIs().toString()); |
| | | } |
| | | } |
| | | writer.flush(); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final ErrorResultIOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getCause().getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Search() { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.CountDownLatch; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldif.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.LDAPConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.requests.BindRequest; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | import org.forgerock.opendj.ldif.LDIFEntryWriter; |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server using the |
| | |
| | | * <baseDN> <scope> <filter> [<attibute> <attribute> ...] |
| | | * </pre> |
| | | */ |
| | | public final class SearchAsync |
| | | { |
| | | private static final class BindResultHandlerImpl implements |
| | | ResultHandler<BindResult> |
| | | { |
| | | public final class SearchAsync { |
| | | private static final class BindResultHandlerImpl implements ResultHandler<BindResult> { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final BindResult result) { |
| | | // Bind succeeded: initiate search. |
| | | final SearchRequest request = |
| | | Requests.newSearchRequest(baseDN, scope, filter, attributes); |
| | | connection.searchAsync(request, null, new SearchResultHandlerImpl()); |
| | | } |
| | | |
| | | } |
| | | |
| | | private static final class ConnectResultHandlerImpl implements ResultHandler<Connection> { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final Connection connection) { |
| | | // Connect succeeded: save connection and initiate bind. |
| | | SearchAsync.connection = connection; |
| | | |
| | | final BindRequest request = |
| | | Requests.newSimpleBindRequest(userName, password.toCharArray()); |
| | | connection.bindAsync(request, null, new BindResultHandlerImpl()); |
| | | } |
| | | |
| | | } |
| | | |
| | | private static final class SearchResultHandlerImpl implements SearchResultHandler { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public synchronized boolean handleEntry(final SearchResultEntry entry) { |
| | | try { |
| | | WRITER.writeComment("Search result entry: " + entry.getName().toString()); |
| | | WRITER.writeEntry(entry); |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public synchronized boolean handleReference(final SearchResultReference reference) { |
| | | try { |
| | | WRITER.writeComment("Search result reference: " + reference.getURIs().toString()); |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | resultCode = result.getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | } |
| | | |
| | | private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); |
| | | private static final LDIFEntryWriter WRITER = new LDIFEntryWriter(System.out); |
| | | private static String userName; |
| | | private static String password; |
| | | private static String baseDN; |
| | | private static SearchScope scope; |
| | | private static String filter; |
| | | private static String[] attributes; |
| | | private static Connection connection = null; |
| | | private static int resultCode = 0; |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, |
| | | * base DN, scope, filter, and zero or more attributes to be |
| | | * retrieved. |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | public static void main(final String[] args) { |
| | | if (args.length < 7) { |
| | | System.err.println("Usage: host port username password baseDN scope " |
| | | + "filter [attribute ...]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | userName = args[2]; |
| | | password = args[3]; |
| | | baseDN = args[4]; |
| | | final String scopeString = args[5]; |
| | | filter = args[6]; |
| | | if (args.length > 7) { |
| | | attributes = Arrays.copyOfRange(args, 7, args.length); |
| | | } else { |
| | | attributes = new String[0]; |
| | | } |
| | | |
| | | if (scopeString.equalsIgnoreCase("base")) { |
| | | scope = SearchScope.BASE_OBJECT; |
| | | } else if (scopeString.equalsIgnoreCase("one")) { |
| | | scope = SearchScope.SINGLE_LEVEL; |
| | | } else if (scopeString.equalsIgnoreCase("sub")) { |
| | | scope = SearchScope.WHOLE_SUBTREE; |
| | | } else if (scopeString.equalsIgnoreCase("subordinates")) { |
| | | scope = SearchScope.SUBORDINATES; |
| | | } else { |
| | | System.err.println("Unknown scope: " + scopeString); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | // Initiate the asynchronous connect, bind, and search. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port); |
| | | factory.getConnectionAsync(new ConnectResultHandlerImpl()); |
| | | |
| | | // Await completion. |
| | | try { |
| | | COMPLETION_LATCH.await(); |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | WRITER.flush(); |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | |
| | | System.exit(resultCode); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final BindResult result) |
| | | { |
| | | // Bind succeeded: initiate search. |
| | | final SearchRequest request = Requests.newSearchRequest(baseDN, |
| | | scope, filter, attributes); |
| | | connection.searchAsync(request, null, new SearchResultHandlerImpl()); |
| | | private SearchAsync() { |
| | | // Not used. |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private static final class ConnectResultHandlerImpl implements |
| | | ResultHandler<Connection> |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final Connection connection) |
| | | { |
| | | // Connect succeeded: save connection and initiate bind. |
| | | SearchAsync.connection = connection; |
| | | |
| | | final BindRequest request = Requests.newSimpleBindRequest( |
| | | userName, password.toCharArray()); |
| | | connection.bindAsync(request, null, new BindResultHandlerImpl()); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private static final class SearchResultHandlerImpl implements |
| | | SearchResultHandler |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public synchronized boolean handleEntry( |
| | | final SearchResultEntry entry) |
| | | { |
| | | try |
| | | { |
| | | WRITER.writeComment("Search result entry: " |
| | | + entry.getName().toString()); |
| | | WRITER.writeEntry(entry); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | System.err.println(error.getMessage()); |
| | | resultCode = error.getResult().getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public synchronized boolean handleReference( |
| | | final SearchResultReference reference) |
| | | { |
| | | try |
| | | { |
| | | WRITER.writeComment("Search result reference: " |
| | | + reference.getURIs().toString()); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | resultCode = result.getResultCode().intValue(); |
| | | COMPLETION_LATCH.countDown(); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch( |
| | | 1); |
| | | private static final LDIFEntryWriter WRITER = new LDIFEntryWriter( |
| | | System.out); |
| | | private static String userName; |
| | | private static String password; |
| | | private static String baseDN; |
| | | private static SearchScope scope; |
| | | private static String filter; |
| | | private static String[] attributes; |
| | | private static Connection connection = null; |
| | | private static int resultCode = 0; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: host, port, username, password, base |
| | | * DN, scope, filter, and zero or more attributes to be retrieved. |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length < 7) |
| | | { |
| | | System.err |
| | | .println("Usage: host port username password baseDN scope " |
| | | + "filter [attribute ...]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String hostName = args[0]; |
| | | final int port = Integer.parseInt(args[1]); |
| | | userName = args[2]; |
| | | password = args[3]; |
| | | baseDN = args[4]; |
| | | final String scopeString = args[5]; |
| | | filter = args[6]; |
| | | if (args.length > 7) |
| | | { |
| | | attributes = Arrays.copyOfRange(args, 7, args.length); |
| | | } |
| | | else |
| | | { |
| | | attributes = new String[0]; |
| | | } |
| | | |
| | | if (scopeString.equalsIgnoreCase("base")) |
| | | { |
| | | scope = SearchScope.BASE_OBJECT; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("one")) |
| | | { |
| | | scope = SearchScope.SINGLE_LEVEL; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("sub")) |
| | | { |
| | | scope = SearchScope.WHOLE_SUBTREE; |
| | | } |
| | | else if (scopeString.equalsIgnoreCase("subordinates")) |
| | | { |
| | | scope = SearchScope.SUBORDINATES; |
| | | } |
| | | else |
| | | { |
| | | System.err.println("Unknown scope: " + scopeString); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | // Initiate the asynchronous connect, bind, and search. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory( |
| | | hostName, port); |
| | | factory.getConnectionAsync(new ConnectResultHandlerImpl()); |
| | | |
| | | // Await completion. |
| | | try |
| | | { |
| | | COMPLETION_LATCH.await(); |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } |
| | | |
| | | try |
| | | { |
| | | WRITER.flush(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | |
| | | System.exit(resultCode); |
| | | } |
| | | |
| | | |
| | | |
| | | private SearchAsync() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | char[] password = c.readPassword("Password: "); |
| | | |
| | | // Search using mail address, and then bind with the DN and password. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, |
| | | port); |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); |
| | | Connection connection = null; |
| | | try { |
| | | connection = factory.getConnection(); |
| | | SearchResultEntry entry = connection.searchSingleEntry(baseDN, |
| | | SearchScope.WHOLE_SUBTREE, "(mail=" + mail + ")", "cn"); |
| | | SearchResultEntry entry = |
| | | connection.searchSingleEntry(baseDN, SearchScope.WHOLE_SUBTREE, "(mail=" + mail |
| | | + ")", "cn"); |
| | | DN bindDN = entry.getName(); |
| | | BindResult result = connection.bind(bindDN.toString(), password); |
| | | |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.FileInputStream; |
| | |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldif.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.CancelledResultException; |
| | | import org.forgerock.opendj.ldap.Connections; |
| | | import org.forgerock.opendj.ldap.DN; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.Filter; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.KeyManagers; |
| | | import org.forgerock.opendj.ldap.LDAPClientContext; |
| | | import org.forgerock.opendj.ldap.LDAPListener; |
| | | import org.forgerock.opendj.ldap.LDAPListenerOptions; |
| | | import org.forgerock.opendj.ldap.LinkedHashMapEntry; |
| | | import org.forgerock.opendj.ldap.Matcher; |
| | | import org.forgerock.opendj.ldap.Modification; |
| | | import org.forgerock.opendj.ldap.ModificationType; |
| | | import org.forgerock.opendj.ldap.RequestContext; |
| | | import org.forgerock.opendj.ldap.RequestHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.SSLContextBuilder; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.ServerConnection; |
| | | import org.forgerock.opendj.ldap.ServerConnectionFactory; |
| | | import org.forgerock.opendj.ldap.TrustManagers; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.BindRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldif.LDIFEntryReader; |
| | | |
| | | /** |
| | | * An LDAP directory server which exposes data contained in an LDIF file. This |
| | |
| | | * <listenAddress> <listenPort> [<ldifFile>] |
| | | * </pre> |
| | | */ |
| | | public final class Server |
| | | { |
| | | private static final class MemoryBackend implements |
| | | RequestHandler<RequestContext> |
| | | { |
| | | private final ConcurrentSkipListMap<DN, Entry> entries; |
| | | private final ReentrantReadWriteLock entryLock = new ReentrantReadWriteLock(); |
| | | public final class Server { |
| | | private static final class MemoryBackend implements RequestHandler<RequestContext> { |
| | | private final ConcurrentSkipListMap<DN, Entry> entries; |
| | | private final ReentrantReadWriteLock entryLock = new ReentrantReadWriteLock(); |
| | | |
| | | |
| | | |
| | | private MemoryBackend(final ConcurrentSkipListMap<DN, Entry> entries) |
| | | { |
| | | this.entries = entries; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final RequestContext requestContext, |
| | | final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | if (entries.containsKey(dn)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.ENTRY_ALREADY_EXISTS, "The entry " + dn.toString() |
| | | + " already exists")); |
| | | private MemoryBackend(final ConcurrentSkipListMap<DN, Entry> entries) { |
| | | this.entries = entries; |
| | | } |
| | | |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, |
| | | "The parent entry " + parent.toString() + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.put(dn, request); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final RequestContext requestContext, final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try { |
| | | DN dn = request.getName(); |
| | | if (entries.containsKey(dn)) { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.ENTRY_ALREADY_EXISTS, "The entry " + dn.toString() |
| | | + " already exists")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, |
| | | final int version, final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) |
| | | { |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } |
| | | else |
| | | { |
| | | // TODO: always succeed. |
| | | resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) |
| | | { |
| | | // TODO: |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, |
| | | final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | // TODO: check for children. |
| | | DN dn = request.getName(); |
| | | if (!entries.containsKey(dn)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.remove(dn); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "Extended request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, |
| | | final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | // TODO: controls. |
| | | // TODO: read lock is not really enough since concurrent updates may |
| | | // still occur to the same entry. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry entry = entries.get(dn); |
| | | if (entry == null) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | |
| | | Entry newEntry = new LinkedHashMapEntry(entry); |
| | | for (Modification mod : request.getModifications()) |
| | | { |
| | | ModificationType modType = mod.getModificationType(); |
| | | if (modType.equals(ModificationType.ADD)) |
| | | { |
| | | // TODO: Reject empty attribute and duplicate values. |
| | | newEntry.addAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.DELETE)) |
| | | { |
| | | // TODO: Reject missing values. |
| | | newEntry.removeAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.REPLACE)) |
| | | { |
| | | newEntry.replaceAttribute(mod.getAttribute()); |
| | | } |
| | | else |
| | | { |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Modify request contains an unsupported modification type")); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | entries.put(dn, newEntry); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "ModifyDN request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, |
| | | final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) |
| | | { |
| | | // TODO: controls, limits, etc. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry baseEntry = entries.get(dn); |
| | | if (baseEntry == null) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | return; |
| | | } |
| | | |
| | | SearchScope scope = request.getScope(); |
| | | Filter filter = request.getFilter(); |
| | | Matcher matcher = filter.matcher(); |
| | | |
| | | if (scope.equals(SearchScope.BASE_OBJECT)) |
| | | { |
| | | if (matcher.matches(baseEntry).toBoolean()) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.SINGLE_LEVEL)) |
| | | { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn, false); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isChildOf(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The parent entry " + parent.toString() |
| | | + " does not exist")); |
| | | } else { |
| | | entries.put(dn, request); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } finally { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | else if (!childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, final int version, |
| | | final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) { |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } else { |
| | | // TODO: always succeed. |
| | | resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.WHOLE_SUBTREE)) |
| | | { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) { |
| | | // TODO: |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try { |
| | | // TODO: check for children. |
| | | DN dn = request.getName(); |
| | | if (!entries.containsKey(dn)) { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } else { |
| | | entries.remove(dn); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } finally { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | else |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "Extended request operation not supported")); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | // TODO: controls. |
| | | // TODO: read lock is not really enough since concurrent updates may |
| | | // still occur to the same entry. |
| | | entryLock.readLock().lock(); |
| | | try { |
| | | DN dn = request.getName(); |
| | | Entry entry = entries.get(dn); |
| | | if (entry == null) { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | |
| | | Entry newEntry = new LinkedHashMapEntry(entry); |
| | | for (Modification mod : request.getModifications()) { |
| | | ModificationType modType = mod.getModificationType(); |
| | | if (modType.equals(ModificationType.ADD)) { |
| | | // TODO: Reject empty attribute and duplicate values. |
| | | newEntry.addAttribute(mod.getAttribute(), null); |
| | | } else if (modType.equals(ModificationType.DELETE)) { |
| | | // TODO: Reject missing values. |
| | | newEntry.removeAttribute(mod.getAttribute(), null); |
| | | } else if (modType.equals(ModificationType.REPLACE)) { |
| | | newEntry.replaceAttribute(mod.getAttribute()); |
| | | } else { |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "Modify request contains an unsupported modification type")); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | entries.put(dn, newEntry); |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } finally { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Search request contains an unsupported search scope")); |
| | | return; |
| | | } |
| | | |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | catch (CancelledResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean sendEntry(SearchRequest request, |
| | | SearchResultHandler resultHandler, Entry entry) |
| | | { |
| | | // TODO: check filter, strip attributes. |
| | | return resultHandler.handleEntry(Responses.newSearchResultEntry(entry)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: listen address, listen port, ldifFile |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length != 3 && args.length != 6) |
| | | { |
| | | System.err.println("Usage: listenAddress listenPort ldifFile " |
| | | + "[keyStoreFile keyStorePassword certNickname]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | final String ldifFileName = args[2]; |
| | | final String keyStoreFileName = (args.length == 6) ? args[3] : null; |
| | | final String keyStorePassword = (args.length == 6) ? args[4] : null; |
| | | final String certNickname = (args.length == 6) ? args[5] : null; |
| | | |
| | | // Create the memory backend. |
| | | final ConcurrentSkipListMap<DN, Entry> entries = |
| | | readEntriesFromLDIF(ldifFileName); |
| | | final MemoryBackend backend = new MemoryBackend(entries); |
| | | |
| | | // Create a server connection adapter. |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = |
| | | Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | |
| | | if (keyStoreFileName != null) |
| | | { |
| | | // Configure SSL/TLS and enable it when connections are accepted. |
| | | final SSLContext sslContext = new SSLContextBuilder() |
| | | .setKeyManager( |
| | | KeyManagers.useSingleCertificate(certNickname, KeyManagers |
| | | .useKeyStoreFile(keyStoreFileName, |
| | | keyStorePassword.toCharArray(), null))) |
| | | .setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | |
| | | ServerConnectionFactory<LDAPClientContext, Integer> sslWrapper = |
| | | new ServerConnectionFactory<LDAPClientContext, Integer>() |
| | | { |
| | | |
| | | public ServerConnection<Integer> handleAccept( |
| | | LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | clientContext.enableTLS(sslContext, null, null, false, false); |
| | | return connectionHandler.handleAccept(clientContext); |
| | | } |
| | | }; |
| | | |
| | | listener = new LDAPListener(localAddress, localPort, sslWrapper, |
| | | options); |
| | | } |
| | | else |
| | | { |
| | | // No SSL. |
| | | listener = new LDAPListener(localAddress, localPort, connectionHandler, |
| | | options); |
| | | } |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | System.out |
| | | .println("Error listening on " + localAddress + ":" + localPort); |
| | | e.printStackTrace(); |
| | | } |
| | | finally |
| | | { |
| | | if (listener != null) |
| | | { |
| | | listener.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Reads the entries from the named LDIF file. |
| | | * |
| | | * @param ldifFileName |
| | | * The name of the LDIF file. |
| | | * @return The entries. |
| | | */ |
| | | private static ConcurrentSkipListMap<DN, Entry> readEntriesFromLDIF( |
| | | final String ldifFileName) |
| | | { |
| | | final ConcurrentSkipListMap<DN, Entry> entries; |
| | | // Read the LDIF. |
| | | InputStream ldif; |
| | | try |
| | | { |
| | | ldif = new FileInputStream(ldifFileName); |
| | | } |
| | | catch (final FileNotFoundException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return null; // Satisfy compiler. |
| | | } |
| | | |
| | | entries = new ConcurrentSkipListMap<DN, Entry>(); |
| | | final LDIFEntryReader reader = new LDIFEntryReader(ldif); |
| | | try |
| | | { |
| | | while (reader.hasNext()) |
| | | { |
| | | Entry entry = reader.readEntry(); |
| | | entries.put(entry.getName(), entry); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return null; // Satisfy compiler. |
| | | } |
| | | finally |
| | | { |
| | | try |
| | | { |
| | | reader.close(); |
| | | } |
| | | catch (final IOException ignored) |
| | | { |
| | | // Ignore. |
| | | } |
| | | } |
| | | |
| | | // Quickly sanity check that every entry (except root entries) have a |
| | | // parent. |
| | | boolean isValid = true; |
| | | for (DN dn : entries.keySet()) |
| | | { |
| | | if (dn.size() > 1) |
| | | { |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) |
| | | { |
| | | System.err.println("The entry \"" + dn.toString() |
| | | + "\" does not have a parent"); |
| | | isValid = false; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "ModifyDN request operation not supported")); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) { |
| | | // TODO: controls, limits, etc. |
| | | entryLock.readLock().lock(); |
| | | try { |
| | | DN dn = request.getName(); |
| | | Entry baseEntry = entries.get(dn); |
| | | if (baseEntry == null) { |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | return; |
| | | } |
| | | |
| | | SearchScope scope = request.getScope(); |
| | | Filter filter = request.getFilter(); |
| | | Matcher matcher = filter.matcher(); |
| | | |
| | | if (scope.equals(SearchScope.BASE_OBJECT)) { |
| | | if (matcher.matches(baseEntry).toBoolean()) { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | } |
| | | } else if (scope.equals(SearchScope.SINGLE_LEVEL)) { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn, false); |
| | | for (Entry entry : subtree.values()) { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isChildOf(dn)) { |
| | | if (!matcher.matches(entry).toBoolean()) { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } else if (!childDN.isSubordinateOrEqualTo(dn)) { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } else if (scope.equals(SearchScope.WHOLE_SUBTREE)) { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn); |
| | | for (Entry entry : subtree.values()) { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isSubordinateOrEqualTo(dn)) { |
| | | if (!matcher.matches(entry).toBoolean()) { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } else { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } else { |
| | | resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "Search request contains an unsupported search scope")); |
| | | return; |
| | | } |
| | | |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } catch (CancelledResultException e) { |
| | | resultHandler.handleErrorResult(e); |
| | | } finally { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | private boolean sendEntry(SearchRequest request, SearchResultHandler resultHandler, |
| | | Entry entry) { |
| | | // TODO: check filter, strip attributes. |
| | | return resultHandler.handleEntry(Responses.newSearchResultEntry(entry)); |
| | | } |
| | | } |
| | | if (!isValid) |
| | | { |
| | | System.exit(1); |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: listen address, listen port, |
| | | * ldifFile |
| | | */ |
| | | public static void main(final String[] args) { |
| | | if (args.length != 3 && args.length != 6) { |
| | | System.err.println("Usage: listenAddress listenPort ldifFile " |
| | | + "[keyStoreFile keyStorePassword certNickname]"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | final String ldifFileName = args[2]; |
| | | final String keyStoreFileName = (args.length == 6) ? args[3] : null; |
| | | final String keyStorePassword = (args.length == 6) ? args[4] : null; |
| | | final String certNickname = (args.length == 6) ? args[5] : null; |
| | | |
| | | // Create the memory backend. |
| | | final ConcurrentSkipListMap<DN, Entry> entries = readEntriesFromLDIF(ldifFileName); |
| | | final MemoryBackend backend = new MemoryBackend(entries); |
| | | |
| | | // Create a server connection adapter. |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = |
| | | Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | LDAPListener listener = null; |
| | | try { |
| | | final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096); |
| | | |
| | | if (keyStoreFileName != null) { |
| | | // Configure SSL/TLS and enable it when connections are |
| | | // accepted. |
| | | final SSLContext sslContext = |
| | | new SSLContextBuilder().setKeyManager( |
| | | KeyManagers.useSingleCertificate(certNickname, KeyManagers |
| | | .useKeyStoreFile(keyStoreFileName, keyStorePassword |
| | | .toCharArray(), null))).setTrustManager( |
| | | TrustManagers.trustAll()).getSSLContext(); |
| | | |
| | | ServerConnectionFactory<LDAPClientContext, Integer> sslWrapper = |
| | | new ServerConnectionFactory<LDAPClientContext, Integer>() { |
| | | |
| | | public ServerConnection<Integer> handleAccept( |
| | | LDAPClientContext clientContext) throws ErrorResultException { |
| | | clientContext.enableTLS(sslContext, null, null, false, false); |
| | | return connectionHandler.handleAccept(clientContext); |
| | | } |
| | | }; |
| | | |
| | | listener = new LDAPListener(localAddress, localPort, sslWrapper, options); |
| | | } else { |
| | | // No SSL. |
| | | listener = new LDAPListener(localAddress, localPort, connectionHandler, options); |
| | | } |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } catch (final Exception e) { |
| | | System.out.println("Error listening on " + localAddress + ":" + localPort); |
| | | e.printStackTrace(); |
| | | } finally { |
| | | if (listener != null) { |
| | | listener.close(); |
| | | } |
| | | } |
| | | } |
| | | return entries; |
| | | } |
| | | |
| | | /** |
| | | * Reads the entries from the named LDIF file. |
| | | * |
| | | * @param ldifFileName |
| | | * The name of the LDIF file. |
| | | * @return The entries. |
| | | */ |
| | | private static ConcurrentSkipListMap<DN, Entry> readEntriesFromLDIF(final String ldifFileName) { |
| | | final ConcurrentSkipListMap<DN, Entry> entries; |
| | | // Read the LDIF. |
| | | InputStream ldif; |
| | | try { |
| | | ldif = new FileInputStream(ldifFileName); |
| | | } catch (final FileNotFoundException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return null; // Satisfy compiler. |
| | | } |
| | | |
| | | entries = new ConcurrentSkipListMap<DN, Entry>(); |
| | | final LDIFEntryReader reader = new LDIFEntryReader(ldif); |
| | | try { |
| | | while (reader.hasNext()) { |
| | | Entry entry = reader.readEntry(); |
| | | entries.put(entry.getName(), entry); |
| | | } |
| | | } catch (final IOException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return null; // Satisfy compiler. |
| | | } finally { |
| | | try { |
| | | reader.close(); |
| | | } catch (final IOException ignored) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | |
| | | private Server() |
| | | { |
| | | // Not used. |
| | | } |
| | | // Quickly sanity check that every entry (except root entries) have a |
| | | // parent. |
| | | boolean isValid = true; |
| | | for (DN dn : entries.keySet()) { |
| | | if (dn.size() > 1) { |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) { |
| | | System.err |
| | | .println("The entry \"" + dn.toString() + "\" does not have a parent"); |
| | | isValid = false; |
| | | } |
| | | } |
| | | } |
| | | if (!isValid) { |
| | | System.exit(1); |
| | | } |
| | | return entries; |
| | | } |
| | | |
| | | private Server() { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package org.forgerock.opendj.examples; |
| | | |
| | | |
| | | |
| | | import java.security.GeneralSecurityException; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | |
| | | import org.forgerock.opendj.ldap.SSLContextBuilder; |
| | | import org.forgerock.opendj.ldap.TrustManagers; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An example client application which performs simple authentication to a |
| | | * directory server. This example takes the following command line parameters: |
| | |
| | | * <li>use-starttls - (Optional) connect with StartTLS</li> |
| | | * <li>use-ssl - (Optional) connect over SSL</li> |
| | | * </ul> |
| | | * The host, port, bind-dn, and bind-password are required. The use-starttls |
| | | * and use-ssl parameters are optional and mutually exclusive. |
| | | * The host, port, bind-dn, and bind-password are required. The use-starttls and |
| | | * use-ssl parameters are optional and mutually exclusive. |
| | | */ |
| | | public final class SimpleAuth |
| | | { |
| | | public final class SimpleAuth { |
| | | |
| | | /** |
| | | * Authenticate to the directory either over LDAP, over LDAPS, or using |
| | | * StartTLS. |
| | | * |
| | | * @param args The command line arguments |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | parseArgs(args); |
| | | // Connect and bind to the server, then close the connection. |
| | | if (useStartTLS) connectStartTLS(); |
| | | else if (useSSL) connectSSL(); |
| | | else connect(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Authenticate over LDAP. |
| | | */ |
| | | private static void connect() |
| | | { |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory( |
| | | host, port); |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | connection = factory.getConnection(); |
| | | connection.bind(bindDN, bindPassword.toCharArray()); |
| | | System.out.println("Authenticated as " + bindDN + "."); |
| | | /** |
| | | * Authenticate to the directory either over LDAP, over LDAPS, or using |
| | | * StartTLS. |
| | | * |
| | | * @param args |
| | | * The command line arguments |
| | | */ |
| | | public static void main(final String[] args) { |
| | | parseArgs(args); |
| | | // Connect and bind to the server, then close the connection. |
| | | if (useStartTLS) { |
| | | connectStartTLS(); |
| | | } else if (useSSL) { |
| | | connectSSL(); |
| | | } else { |
| | | connect(); |
| | | } |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | |
| | | /** |
| | | * Authenticate over LDAP. |
| | | */ |
| | | private static void connect() { |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | connection = factory.getConnection(); |
| | | connection.bind(bindDN, bindPassword.toCharArray()); |
| | | System.out.println("Authenticated as " + bindDN + "."); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | |
| | | /** |
| | | * For StartTLS and SSL the connection factory needs SSL context options. In |
| | | * the general case, a trust manager in the SSL context serves to check |
| | | * server certificates, and a key manager handles client keys when the |
| | | * server checks certificates from our client. |
| | | * |
| | | * OpenDJ directory server lets you install by default with a self-signed |
| | | * certificate that is not in the system trust store. To simplify this |
| | | * implementation trusts all server certificates. |
| | | */ |
| | | private static LDAPOptions getTrustAllOptions() throws GeneralSecurityException { |
| | | LDAPOptions lo = new LDAPOptions(); |
| | | SSLContext sslContext = |
| | | new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | lo.setSSLContext(sslContext); |
| | | lo.setUseStartTLS(useStartTLS); |
| | | return lo; |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) connection.close(); |
| | | |
| | | /** |
| | | * Perform authentication over a secure connection, trusting all server |
| | | * certificates. |
| | | */ |
| | | private static void trustAllConnect() { |
| | | Connection connection = null; |
| | | |
| | | try { |
| | | final LDAPConnectionFactory factory = |
| | | new LDAPConnectionFactory(host, port, getTrustAllOptions()); |
| | | connection = factory.getConnection(); |
| | | connection.bind(bindDN, bindPassword.toCharArray()); |
| | | System.out.println("Authenticated as " + bindDN + "."); |
| | | } catch (final ErrorResultException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | } catch (final InterruptedException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | } catch (final GeneralSecurityException e) { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); |
| | | } finally { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * For StartTLS and SSL the connection factory needs SSL context options. |
| | | * In the general case, a trust manager in the SSL context serves to check |
| | | * server certificates, and a key manager handles client keys when the server |
| | | * checks certificates from our client. |
| | | * |
| | | * OpenDJ directory server lets you install by default with a self-signed |
| | | * certificate that is not in the system trust store. To simplify this |
| | | * implementation trusts all server certificates. |
| | | */ |
| | | private static LDAPOptions getTrustAllOptions() |
| | | throws GeneralSecurityException |
| | | { |
| | | LDAPOptions lo = new LDAPOptions(); |
| | | SSLContext sslContext = new SSLContextBuilder() |
| | | .setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | lo.setSSLContext(sslContext); |
| | | lo.setUseStartTLS(useStartTLS); |
| | | return lo; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Perform authentication over a secure connection, trusting all server |
| | | * certificates. |
| | | */ |
| | | private static void trustAllConnect() |
| | | { |
| | | Connection connection = null; |
| | | |
| | | try |
| | | { |
| | | final LDAPConnectionFactory factory = |
| | | new LDAPConnectionFactory(host, port, getTrustAllOptions()); |
| | | connection = factory.getConnection(); |
| | | connection.bind(bindDN, bindPassword.toCharArray()); |
| | | System.out.println("Authenticated as " + bindDN + "."); |
| | | /** |
| | | * Authenticate using StartTLS. |
| | | */ |
| | | private static void connectStartTLS() { |
| | | trustAllConnect(); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(e.getResult().getResultCode().intValue()); |
| | | return; |
| | | |
| | | /** |
| | | * Authenticate over LDAPS. |
| | | */ |
| | | private static void connectSSL() { |
| | | trustAllConnect(); |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); |
| | | return; |
| | | |
| | | private static String host; |
| | | private static int port; |
| | | private static String bindDN; |
| | | private static String bindPassword; |
| | | private static boolean useStartTLS = false; |
| | | private static boolean useSSL = false; |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * |
| | | * @param args |
| | | * host port bind-dn bind-password [ use-starttls | use-ssl ] |
| | | */ |
| | | private static void parseArgs(String[] args) { |
| | | if (args.length < 4 || args.length > 5) { |
| | | giveUp(); |
| | | } |
| | | |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | bindDN = args[2]; |
| | | bindPassword = args[3]; |
| | | |
| | | if (args.length == 5) { |
| | | if (args[4].toLowerCase().equals("use-starttls")) { |
| | | useStartTLS = true; |
| | | useSSL = false; |
| | | } else if (args[4].toLowerCase().equals("use-ssl")) { |
| | | useStartTLS = false; |
| | | useSSL = true; |
| | | } else { |
| | | giveUp(); |
| | | } |
| | | } |
| | | } |
| | | catch (final GeneralSecurityException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); |
| | | |
| | | private static void giveUp() { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | connection.close(); |
| | | |
| | | private static void printUsage() { |
| | | System.err.println("Usage: host port bind-dn bind-password [ use-starttls | use-ssl ]"); |
| | | System.err.println("\thost, port, bind-dn, and bind-password arguments are required."); |
| | | System.err.println("\tuse-starttls and use-ssl are optional and mutually exclusive."); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Authenticate using StartTLS. |
| | | */ |
| | | private static void connectStartTLS() |
| | | { |
| | | trustAllConnect(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Authenticate over LDAPS. |
| | | */ |
| | | private static void connectSSL() |
| | | { |
| | | trustAllConnect(); |
| | | } |
| | | |
| | | |
| | | |
| | | private static String host; |
| | | private static int port; |
| | | private static String bindDN; |
| | | private static String bindPassword; |
| | | private static boolean useStartTLS = false; |
| | | private static boolean useSSL = false; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Parse command line arguments. |
| | | * @param args host port bind-dn bind-password [ use-starttls | use-ssl ] |
| | | */ |
| | | private static void parseArgs(String[] args) |
| | | { |
| | | if (args.length < 4 || args.length > 5) giveUp(); |
| | | |
| | | host = args[0]; |
| | | port = Integer.parseInt(args[1]); |
| | | bindDN = args[2]; |
| | | bindPassword = args[3]; |
| | | |
| | | if (args.length == 5) |
| | | { |
| | | if (args[4].toLowerCase().equals("use-starttls")) |
| | | { |
| | | useStartTLS = true; |
| | | useSSL = false; |
| | | } |
| | | else if (args[4].toLowerCase().equals("use-ssl")) |
| | | { |
| | | useStartTLS = false; |
| | | useSSL = true; |
| | | } |
| | | else giveUp(); |
| | | private SimpleAuth() { |
| | | // Not used. |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static void giveUp() |
| | | { |
| | | printUsage(); |
| | | System.exit(1); |
| | | } |
| | | |
| | | |
| | | |
| | | private static void printUsage() |
| | | { |
| | | System.err.println( |
| | | "Usage: host port bind-dn bind-password [ use-starttls | use-ssl ]"); |
| | | System.err.println( |
| | | "\thost, port, bind-dn, and bind-password arguments are required."); |
| | | System.err.println( |
| | | "\tuse-starttls and use-ssl are optional and mutually exclusive."); |
| | | } |
| | | |
| | | |
| | | |
| | | private SimpleAuth() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | * OpenDJ LDAP SDK. |
| | | */ |
| | | package org.forgerock.opendj.examples; |
| | | |
| | |
| | | ! (the "License"). You may not use this file except in compliance |
| | | ! with the License. |
| | | ! |
| | | ! You can obtain a copy of the license at |
| | | ! trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | ! You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | ! or http://forgerock.org/license/CDDLv1.0.html. |
| | | ! See the License for the specific language governing permissions |
| | | ! and limitations under the License. |
| | | ! |
| | | ! When distributing Covered Code, include this CDDL HEADER in each |
| | | ! file and include the License file at |
| | | ! trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | ! add the following below this CDDL HEADER, with the fields enclosed |
| | | ! by brackets "[]" replaced with your own identifying information: |
| | | ! file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | ! If applicable, add the following below this CDDL HEADER, with the |
| | | ! fields enclosed by brackets "[]" replaced with your own identifying |
| | | ! information: |
| | | ! Portions Copyright [yyyy] [name of copyright owner] |
| | | ! |
| | | ! CDDL HEADER END |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.*; |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES; |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_TYPE; |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.*; |
| | | |
| | | import java.io.IOException; |
| | |
| | | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Grizzly ASN1 reader implementation. |
| | | */ |
| | | final class ASN1BufferReader extends AbstractASN1Reader implements ASN1Reader |
| | | { |
| | | private final class ChildSequenceLimiter implements SequenceLimiter |
| | | { |
| | | private SequenceLimiter parent; |
| | | final class ASN1BufferReader extends AbstractASN1Reader implements ASN1Reader { |
| | | private final class ChildSequenceLimiter implements SequenceLimiter { |
| | | private SequenceLimiter parent; |
| | | |
| | | private ChildSequenceLimiter child; |
| | | private ChildSequenceLimiter child; |
| | | |
| | | private int readLimit; |
| | | private int readLimit; |
| | | |
| | | private int bytesRead; |
| | | private int bytesRead; |
| | | |
| | | public void checkLimit(final int readSize) throws IOException { |
| | | if ((readLimit > 0) && (bytesRead + readSize > readLimit)) { |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | parent.checkLimit(readSize); |
| | | |
| | | public void checkLimit(final int readSize) throws IOException |
| | | { |
| | | if ((readLimit > 0) && (bytesRead + readSize > readLimit)) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | parent.checkLimit(readSize); |
| | | |
| | | bytesRead += readSize; |
| | | } |
| | | |
| | | |
| | | |
| | | public SequenceLimiter endSequence() throws IOException |
| | | { |
| | | parent.checkLimit(remaining()); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE) && remaining() > 0) |
| | | { |
| | | StaticUtils.DEBUG_LOG |
| | | .fine(String.format( |
| | | "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", |
| | | remaining())); |
| | | } |
| | | |
| | | for (int i = 0; i < remaining(); i++) |
| | | { |
| | | buffer.get(); |
| | | } |
| | | |
| | | return parent; |
| | | } |
| | | |
| | | |
| | | |
| | | public int remaining() |
| | | { |
| | | return readLimit - bytesRead; |
| | | } |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter startSequence(final int readLimit) |
| | | { |
| | | if (child == null) |
| | | { |
| | | child = new ChildSequenceLimiter(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | child.readLimit = readLimit; |
| | | child.bytesRead = 0; |
| | | |
| | | return child; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class RootSequenceLimiter implements SequenceLimiter |
| | | { |
| | | private ChildSequenceLimiter child; |
| | | |
| | | |
| | | |
| | | public void checkLimit(final int readSize) throws IOException |
| | | { |
| | | if (buffer.remaining() < readSize) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter endSequence() throws DecodeException |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED |
| | | .get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | } |
| | | |
| | | |
| | | |
| | | public int remaining() |
| | | { |
| | | return buffer.remaining(); |
| | | } |
| | | |
| | | |
| | | |
| | | public ChildSequenceLimiter startSequence(final int readLimit) |
| | | { |
| | | if (child == null) |
| | | { |
| | | child = new ChildSequenceLimiter(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | child.readLimit = readLimit; |
| | | child.bytesRead = 0; |
| | | |
| | | return child; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private interface SequenceLimiter |
| | | { |
| | | public void checkLimit(int readSize) throws IOException; |
| | | |
| | | |
| | | |
| | | public SequenceLimiter endSequence() throws IOException; |
| | | |
| | | |
| | | |
| | | public int remaining(); |
| | | |
| | | |
| | | |
| | | public SequenceLimiter startSequence(int readLimit); |
| | | } |
| | | |
| | | |
| | | |
| | | private static final int MAX_STRING_BUFFER_SIZE = 1024; |
| | | |
| | | private int state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | |
| | | private byte peekType = 0; |
| | | |
| | | private int peekLength = -1; |
| | | |
| | | private int lengthBytesNeeded = 0; |
| | | |
| | | private final int maxElementSize; |
| | | |
| | | private final CompositeBuffer buffer; |
| | | |
| | | private SequenceLimiter readLimiter; |
| | | |
| | | private final byte[] stringBuffer; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new ASN1 reader whose source is the provided input stream and |
| | | * having a user defined maximum BER element size. |
| | | * |
| | | * @param maxElementSize |
| | | * The maximum BER element size, or <code>0</code> to indicate that |
| | | * there is no limit. |
| | | * @param memoryManager |
| | | * The memory manager to use for buffering. |
| | | */ |
| | | ASN1BufferReader(final int maxElementSize, |
| | | final MemoryManager<?> memoryManager) |
| | | { |
| | | this.readLimiter = new RootSequenceLimiter(); |
| | | this.stringBuffer = new byte[MAX_STRING_BUFFER_SIZE]; |
| | | this.maxElementSize = maxElementSize; |
| | | this.buffer = BuffersBuffer.create(memoryManager); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Closes this ASN.1 reader and the underlying stream. |
| | | * |
| | | * @throws IOException |
| | | * if an I/O error occurs |
| | | */ |
| | | public void close() throws IOException |
| | | { |
| | | buffer.dispose(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Determines if a complete ASN.1 element is ready to be read from the stream |
| | | * reader. |
| | | * |
| | | * @return <code>true</code> if another complete element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean elementAvailable() throws IOException |
| | | { |
| | | return !((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE) |
| | | && !needFirstLengthByteState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES) |
| | | && !needAdditionalLengthBytesState(true)) |
| | | && peekLength <= readLimiter.remaining(); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Determines if the input stream contains at least one ASN.1 element to be |
| | | * read. |
| | | * |
| | | * @return <code>true</code> if another element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean hasNextElement() throws IOException |
| | | { |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(true); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int peekLength() throws IOException |
| | | { |
| | | peekType(); |
| | | |
| | | switch (state) |
| | | { |
| | | case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE: |
| | | needFirstLengthByteState(false); |
| | | break; |
| | | |
| | | case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES: |
| | | needAdditionalLengthBytesState(false); |
| | | } |
| | | |
| | | return peekLength; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public byte peekType() throws IOException |
| | | { |
| | | if (state == ELEMENT_READ_STATE_NEED_TYPE) |
| | | { |
| | | needTypeState(false); |
| | | } |
| | | |
| | | return peekType; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean readBoolean() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength != 1) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | final byte readByte = buffer.get(); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", peekType, |
| | | peekLength, String.valueOf(readByte != 0x00))); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return readByte != 0x00; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSequence() throws IOException |
| | | { |
| | | readLimiter = readLimiter.endSequence(); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE")); |
| | | } |
| | | |
| | | // Reset the state |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSet() throws IOException |
| | | { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | readEndSequence(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int readEnumerated() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if ((peekLength < 1) || (peekLength > 4)) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | // From an implementation point of view, an enumerated value is |
| | | // equivalent to an integer. |
| | | return (int) readInteger(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public long readInteger() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if ((peekLength < 1) || (peekLength > 8)) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | if (peekLength > 4) |
| | | { |
| | | long longValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) |
| | | { |
| | | longValue = 0xFFFFFFFFFFFFFFFFL; |
| | | bytesRead += readSize; |
| | | } |
| | | longValue = (longValue << 8) | (readByte & 0xFF); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return longValue; |
| | | } |
| | | else |
| | | { |
| | | int intValue = 0; |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) |
| | | { |
| | | intValue = 0xFFFFFFFF; |
| | | public SequenceLimiter endSequence() throws IOException { |
| | | parent.checkLimit(remaining()); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE) && remaining() > 0) { |
| | | StaticUtils.DEBUG_LOG.fine(String.format( |
| | | "Ignoring %d unused trailing bytes in ASN.1 SEQUENCE", remaining())); |
| | | } |
| | | |
| | | for (int i = 0; i < remaining(); i++) { |
| | | buffer.get(); |
| | | } |
| | | |
| | | return parent; |
| | | } |
| | | intValue = (intValue << 8) | (readByte & 0xFF); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", peekType, |
| | | peekLength, intValue)); |
| | | } |
| | | public int remaining() { |
| | | return readLimit - bytesRead; |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return intValue; |
| | | } |
| | | } |
| | | public ChildSequenceLimiter startSequence(final int readLimit) { |
| | | if (child == null) { |
| | | child = new ChildSequenceLimiter(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | child.readLimit = readLimit; |
| | | child.bytesRead = 0; |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readNull() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | // Make sure that the decoded length is exactly zero byte. |
| | | if (peekLength != 0) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH |
| | | .get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | return child; |
| | | } |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 NULL(type=0x%x, length=%d)", peekType, peekLength)); |
| | | private final class RootSequenceLimiter implements SequenceLimiter { |
| | | private ChildSequenceLimiter child; |
| | | |
| | | public void checkLimit(final int readSize) throws IOException { |
| | | if (buffer.remaining() < readSize) { |
| | | final LocalizableMessage message = ERR_ASN1_TRUNCATED_LENGTH_BYTE.get(); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | } |
| | | |
| | | public ChildSequenceLimiter endSequence() throws DecodeException { |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_READ_NOT_STARTED.get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | } |
| | | |
| | | public int remaining() { |
| | | return buffer.remaining(); |
| | | } |
| | | |
| | | public ChildSequenceLimiter startSequence(final int readLimit) { |
| | | if (child == null) { |
| | | child = new ChildSequenceLimiter(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | child.readLimit = readLimit; |
| | | child.bytesRead = 0; |
| | | |
| | | return child; |
| | | } |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | private interface SequenceLimiter { |
| | | public void checkLimit(int readSize) throws IOException; |
| | | |
| | | public SequenceLimiter endSequence() throws IOException; |
| | | |
| | | public int remaining(); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteString readOctetString() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength == 0) |
| | | { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ByteString.empty(); |
| | | public SequenceLimiter startSequence(int readLimit); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | // Copy the value and construct the element to return. |
| | | final byte[] value = new byte[peekLength]; |
| | | buffer.get(value); |
| | | private static final int MAX_STRING_BUFFER_SIZE = 1024; |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG |
| | | .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", |
| | | peekType, peekLength)); |
| | | private int state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | |
| | | private byte peekType = 0; |
| | | |
| | | private int peekLength = -1; |
| | | |
| | | private int lengthBytesNeeded = 0; |
| | | |
| | | private final int maxElementSize; |
| | | |
| | | private final CompositeBuffer buffer; |
| | | |
| | | private SequenceLimiter readLimiter; |
| | | |
| | | private final byte[] stringBuffer; |
| | | |
| | | /** |
| | | * Creates a new ASN1 reader whose source is the provided input stream and |
| | | * having a user defined maximum BER element size. |
| | | * |
| | | * @param maxElementSize |
| | | * The maximum BER element size, or <code>0</code> to indicate |
| | | * that there is no limit. |
| | | * @param memoryManager |
| | | * The memory manager to use for buffering. |
| | | */ |
| | | ASN1BufferReader(final int maxElementSize, final MemoryManager<?> memoryManager) { |
| | | this.readLimiter = new RootSequenceLimiter(); |
| | | this.stringBuffer = new byte[MAX_STRING_BUFFER_SIZE]; |
| | | this.maxElementSize = maxElementSize; |
| | | this.buffer = BuffersBuffer.create(memoryManager); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ByteString.wrap(value); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteStringBuilder readOctetString(final ByteStringBuilder builder) |
| | | throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength == 0) |
| | | { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return builder; |
| | | /** |
| | | * Closes this ASN.1 reader and the underlying stream. |
| | | * |
| | | * @throws IOException |
| | | * if an I/O error occurs |
| | | */ |
| | | public void close() throws IOException { |
| | | buffer.dispose(); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | // Copy the value and construct the element to return. |
| | | // TODO: Is there a more efficient way to do this? |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | builder.append(buffer.get()); |
| | | /** |
| | | * Determines if a complete ASN.1 element is ready to be read from the |
| | | * stream reader. |
| | | * |
| | | * @return <code>true</code> if another complete element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean elementAvailable() throws IOException { |
| | | return !((state == ELEMENT_READ_STATE_NEED_TYPE) && !needTypeState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE) |
| | | && !needFirstLengthByteState(true)) |
| | | && !((state == ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES) |
| | | && !needAdditionalLengthBytesState(true)) |
| | | && peekLength <= readLimiter.remaining(); |
| | | |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG |
| | | .finest(String.format("READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", |
| | | peekType, peekLength)); |
| | | /** |
| | | * Determines if the input stream contains at least one ASN.1 element to be |
| | | * read. |
| | | * |
| | | * @return <code>true</code> if another element is available or |
| | | * <code>false</code> otherwise. |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | public boolean hasNextElement() throws IOException { |
| | | return (state != ELEMENT_READ_STATE_NEED_TYPE) || needTypeState(true); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return builder; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int peekLength() throws IOException { |
| | | peekType(); |
| | | |
| | | switch (state) { |
| | | case ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE: |
| | | needFirstLengthByteState(false); |
| | | break; |
| | | |
| | | case ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES: |
| | | needAdditionalLengthBytesState(false); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String readOctetStringAsString() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength == 0) |
| | | { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ""; |
| | | return peekLength; |
| | | } |
| | | |
| | | byte[] readBuffer; |
| | | if (peekLength <= stringBuffer.length) |
| | | { |
| | | readBuffer = stringBuffer; |
| | | } |
| | | else |
| | | { |
| | | readBuffer = new byte[peekLength]; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public byte peekType() throws IOException { |
| | | if (state == ELEMENT_READ_STATE_NEED_TYPE) { |
| | | needTypeState(false); |
| | | } |
| | | |
| | | return peekType; |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | buffer.get(readBuffer, 0, peekLength); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean readBoolean() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | if (peekLength != 1) { |
| | | final LocalizableMessage message = ERR_ASN1_BOOLEAN_INVALID_LENGTH.get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | String str; |
| | | try |
| | | { |
| | | str = new String(readBuffer, 0, peekLength, "UTF-8"); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) |
| | | { |
| | | StaticUtils.DEBUG_LOG |
| | | .warning("Unable to decode ASN.1 OCTETSTRING bytes as UTF-8 string: " |
| | | + e.toString()); |
| | | } |
| | | readLimiter.checkLimit(peekLength); |
| | | final byte readByte = buffer.get(); |
| | | |
| | | str = new String(stringBuffer, 0, peekLength); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", peekType, peekLength, |
| | | String.valueOf(readByte != 0x00))); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return readByte != 0x00; |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", peekType, |
| | | peekLength, str)); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSequence() throws IOException { |
| | | readLimiter = readLimiter.endSequence(); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 END SEQUENCE")); |
| | | } |
| | | |
| | | // Reset the state |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readStartSequence() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | readLimiter = readLimiter.startSequence(peekLength); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType, |
| | | peekLength)); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readEndSet() throws IOException { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | readEndSequence(); |
| | | } |
| | | |
| | | // Reset the state |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int readEnumerated() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if ((peekLength < 1) || (peekLength > 4)) { |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readStartSet() throws IOException |
| | | { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | readStartSequence(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Reader skipElement() throws IOException |
| | | { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | for (int i = 0; i < peekLength; i++) |
| | | { |
| | | buffer.get(); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | void appendBytesRead(final Buffer buffer) |
| | | { |
| | | this.buffer.append(buffer); |
| | | } |
| | | |
| | | |
| | | |
| | | void disposeBytesRead() |
| | | { |
| | | this.buffer.shrink(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Internal helper method reading the additional ASN.1 length bytes and |
| | | * transition to the next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully read. |
| | | * @throws IOException |
| | | * If an error occurs while reading from the stream. |
| | | */ |
| | | private boolean needAdditionalLengthBytesState(final boolean ensureRead) |
| | | throws IOException |
| | | { |
| | | if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded)) |
| | | { |
| | | return false; |
| | | // From an implementation point of view, an enumerated value is |
| | | // equivalent to an integer. |
| | | return (int) readInteger(); |
| | | } |
| | | |
| | | byte readByte; |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) |
| | | { |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public long readInteger() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if ((peekLength < 1) || (peekLength > 8)) { |
| | | final LocalizableMessage message = ERR_ASN1_INTEGER_INVALID_LENGTH.get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | if (peekLength > 4) { |
| | | long longValue = 0; |
| | | for (int i = 0; i < peekLength; i++) { |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) { |
| | | longValue = 0xFFFFFFFFFFFFFFFFL; |
| | | } |
| | | longValue = (longValue << 8) | (readByte & 0xFF); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return longValue; |
| | | } else { |
| | | int intValue = 0; |
| | | for (int i = 0; i < peekLength; i++) { |
| | | final int readByte = buffer.get(); |
| | | if ((i == 0) && (((byte) readByte) < 0)) { |
| | | intValue = 0xFFFFFFFF; |
| | | } |
| | | intValue = (intValue << 8) | (readByte & 0xFF); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", peekType, peekLength, |
| | | intValue)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return intValue; |
| | | } |
| | | } |
| | | |
| | | // Make sure that the element is not larger than the maximum allowed |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) |
| | | { |
| | | final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | return true; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readNull() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | // Make sure that the decoded length is exactly zero byte. |
| | | if (peekLength != 0) { |
| | | final LocalizableMessage message = ERR_ASN1_NULL_INVALID_LENGTH.get(peekLength); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("READ ASN.1 NULL(type=0x%x, length=%d)", |
| | | peekType, peekLength)); |
| | | } |
| | | |
| | | /** |
| | | * Internal helper method reading the first length bytes and transition to the |
| | | * next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needFirstLengthByteState(final boolean ensureRead) |
| | | throws IOException |
| | | { |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) |
| | | { |
| | | return false; |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | byte readByte = buffer.get(); |
| | | peekLength = (readByte & 0x7F); |
| | | if (peekLength != readByte) |
| | | { |
| | | lengthBytesNeeded = peekLength; |
| | | if (lengthBytesNeeded > 4) |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES |
| | | .get(lengthBytesNeeded); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | peekLength = 0x00; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteString readOctetString() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded)) |
| | | { |
| | | state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES; |
| | | return false; |
| | | } |
| | | if (peekLength == 0) { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ByteString.empty(); |
| | | } |
| | | |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) |
| | | { |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | } |
| | | readLimiter.checkLimit(peekLength); |
| | | // Copy the value and construct the element to return. |
| | | final byte[] value = new byte[peekLength]; |
| | | buffer.get(value); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, peekLength)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ByteString.wrap(value); |
| | | } |
| | | |
| | | // Make sure that the element is not larger than the maximum allowed |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) |
| | | { |
| | | final LocalizableMessage m = ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | return true; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ByteStringBuilder readOctetString(final ByteStringBuilder builder) throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength == 0) { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return builder; |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | // Copy the value and construct the element to return. |
| | | // TODO: Is there a more efficient way to do this? |
| | | for (int i = 0; i < peekLength; i++) { |
| | | builder.append(buffer.get()); |
| | | } |
| | | |
| | | /** |
| | | * Internal helper method reading the ASN.1 type byte and transition to the |
| | | * next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the type byte was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needTypeState(final boolean ensureRead) throws IOException |
| | | { |
| | | // Read just the type. |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) |
| | | { |
| | | return false; |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d)", peekType, peekLength)); |
| | | } |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return builder; |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | peekType = buffer.get(); |
| | | state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | return true; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String readOctetStringAsString() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | if (peekLength == 0) { |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return ""; |
| | | } |
| | | |
| | | byte[] readBuffer; |
| | | if (peekLength <= stringBuffer.length) { |
| | | readBuffer = stringBuffer; |
| | | } else { |
| | | readBuffer = new byte[peekLength]; |
| | | } |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | buffer.get(readBuffer, 0, peekLength); |
| | | |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | |
| | | String str; |
| | | try { |
| | | str = new String(readBuffer, 0, peekLength, "UTF-8"); |
| | | } catch (final Exception e) { |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) { |
| | | StaticUtils.DEBUG_LOG |
| | | .warning("Unable to decode ASN.1 OCTETSTRING bytes as UTF-8 string: " |
| | | + e.toString()); |
| | | } |
| | | |
| | | str = new String(stringBuffer, 0, peekLength); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 OCTETSTRING(type=0x%x, length=%d, value=%s)", peekType, peekLength, |
| | | str)); |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readStartSequence() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | readLimiter = readLimiter.startSequence(peekLength); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "READ ASN.1 START SEQUENCE(type=0x%x, length=%d)", peekType, peekLength)); |
| | | } |
| | | |
| | | // Reset the state |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void readStartSet() throws IOException { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | readStartSequence(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Reader skipElement() throws IOException { |
| | | // Read the header if haven't done so already |
| | | peekLength(); |
| | | |
| | | readLimiter.checkLimit(peekLength); |
| | | for (int i = 0; i < peekLength; i++) { |
| | | buffer.get(); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_TYPE; |
| | | return this; |
| | | } |
| | | |
| | | void appendBytesRead(final Buffer buffer) { |
| | | this.buffer.append(buffer); |
| | | } |
| | | |
| | | void disposeBytesRead() { |
| | | this.buffer.shrink(); |
| | | } |
| | | |
| | | /** |
| | | * Internal helper method reading the additional ASN.1 length bytes and |
| | | * transition to the next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully read. |
| | | * @throws IOException |
| | | * If an error occurs while reading from the stream. |
| | | */ |
| | | private boolean needAdditionalLengthBytesState(final boolean ensureRead) throws IOException { |
| | | if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded)) { |
| | | return false; |
| | | } |
| | | |
| | | byte readByte; |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) { |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | } |
| | | |
| | | // Make sure that the element is not larger than the maximum allowed |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) { |
| | | final LocalizableMessage m = |
| | | ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Internal helper method reading the first length bytes and transition to |
| | | * the next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the length bytes was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needFirstLengthByteState(final boolean ensureRead) throws IOException { |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) { |
| | | return false; |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | byte readByte = buffer.get(); |
| | | peekLength = (readByte & 0x7F); |
| | | if (peekLength != readByte) { |
| | | lengthBytesNeeded = peekLength; |
| | | if (lengthBytesNeeded > 4) { |
| | | final LocalizableMessage message = |
| | | ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(lengthBytesNeeded); |
| | | throw DecodeException.fatalError(message); |
| | | } |
| | | peekLength = 0x00; |
| | | |
| | | if (ensureRead && (readLimiter.remaining() < lengthBytesNeeded)) { |
| | | state = ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES; |
| | | return false; |
| | | } |
| | | |
| | | readLimiter.checkLimit(lengthBytesNeeded); |
| | | while (lengthBytesNeeded > 0) { |
| | | readByte = buffer.get(); |
| | | peekLength = (peekLength << 8) | (readByte & 0xFF); |
| | | lengthBytesNeeded--; |
| | | } |
| | | } |
| | | |
| | | // Make sure that the element is not larger than the maximum allowed |
| | | // message size. |
| | | if ((maxElementSize > 0) && (peekLength > maxElementSize)) { |
| | | final LocalizableMessage m = |
| | | ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED |
| | | .get(peekLength, maxElementSize); |
| | | throw DecodeException.fatalError(m); |
| | | } |
| | | state = ELEMENT_READ_STATE_NEED_VALUE_BYTES; |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Internal helper method reading the ASN.1 type byte and transition to the |
| | | * next state if successful. |
| | | * |
| | | * @param ensureRead |
| | | * <code>true</code> to check for availability first. |
| | | * @return <code>true</code> if the type byte was successfully read |
| | | * @throws IOException |
| | | * If an error occurs while trying to decode an ASN1 element. |
| | | */ |
| | | private boolean needTypeState(final boolean ensureRead) throws IOException { |
| | | // Read just the type. |
| | | if (ensureRead && (readLimiter.remaining() <= 0)) { |
| | | return false; |
| | | } |
| | | |
| | | readLimiter.checkLimit(1); |
| | | peekType = buffer.get(); |
| | | state = ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE; |
| | | return true; |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | */ |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.asn1.ASN1Constants.BOOLEAN_VALUE_FALSE; |
| | | import static org.forgerock.opendj.asn1.ASN1Constants.BOOLEAN_VALUE_TRUE; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED; |
| | |
| | | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Grizzly ASN1 writer implementation. |
| | | */ |
| | | final class ASN1BufferWriter extends AbstractASN1Writer implements ASN1Writer, |
| | | Cacheable |
| | | { |
| | | private class ChildSequenceBuffer implements SequenceBuffer |
| | | { |
| | | private SequenceBuffer parent; |
| | | final class ASN1BufferWriter extends AbstractASN1Writer implements ASN1Writer, Cacheable { |
| | | private class ChildSequenceBuffer implements SequenceBuffer { |
| | | private SequenceBuffer parent; |
| | | |
| | | private ChildSequenceBuffer child; |
| | | private ChildSequenceBuffer child; |
| | | |
| | | private final ByteStringBuilder buffer = new ByteStringBuilder( |
| | | BUFFER_INIT_SIZE); |
| | | private final ByteStringBuilder buffer = new ByteStringBuilder(BUFFER_INIT_SIZE); |
| | | |
| | | public SequenceBuffer endSequence() throws IOException { |
| | | writeLength(parent, buffer.length()); |
| | | parent.writeByteArray(buffer.getBackingArray(), 0, buffer.length()); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("WRITE ASN.1 END SEQUENCE(length=%d)", |
| | | buffer.length())); |
| | | } |
| | | |
| | | public SequenceBuffer endSequence() throws IOException |
| | | { |
| | | writeLength(parent, buffer.length()); |
| | | parent.writeByteArray(buffer.getBackingArray(), 0, buffer.length()); |
| | | return parent; |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 END SEQUENCE(length=%d)", buffer.length())); |
| | | } |
| | | public SequenceBuffer startSequence(final byte type) throws IOException { |
| | | if (child == null) { |
| | | child = new ChildSequenceBuffer(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | return parent; |
| | | buffer.append(type); |
| | | child.buffer.clear(); |
| | | |
| | | return child; |
| | | } |
| | | |
| | | public void writeByte(final byte b) throws IOException { |
| | | buffer.append(b); |
| | | } |
| | | |
| | | public void writeByteArray(final byte[] bs, final int offset, final int length) |
| | | throws IOException { |
| | | buffer.append(bs, offset, length); |
| | | } |
| | | } |
| | | |
| | | private static final class RecyclableBuffer extends ByteBufferWrapper { |
| | | private volatile boolean usable = true; |
| | | |
| | | private RecyclableBuffer() { |
| | | visible = ByteBuffer.allocate(BUFFER_INIT_SIZE); |
| | | allowBufferDispose = true; |
| | | } |
| | | |
| | | public SequenceBuffer startSequence(final byte type) throws IOException |
| | | { |
| | | if (child == null) |
| | | { |
| | | child = new ChildSequenceBuffer(); |
| | | child.parent = this; |
| | | } |
| | | @Override |
| | | public void dispose() { |
| | | usable = true; |
| | | } |
| | | |
| | | buffer.append(type); |
| | | child.buffer.clear(); |
| | | |
| | | return child; |
| | | /** |
| | | * Ensures that the specified number of additional bytes will fit in the |
| | | * buffer and resizes it if necessary. |
| | | * |
| | | * @param size |
| | | * The number of additional bytes. |
| | | */ |
| | | public void ensureAdditionalCapacity(final int size) { |
| | | final int newCount = visible.position() + size; |
| | | if (newCount > visible.capacity()) { |
| | | final ByteBuffer newByteBuffer = |
| | | ByteBuffer.allocate(Math.max(visible.capacity() << 1, newCount)); |
| | | visible.flip(); |
| | | visible = newByteBuffer.put(visible); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private class RootSequenceBuffer implements SequenceBuffer { |
| | | private ChildSequenceBuffer child; |
| | | |
| | | public SequenceBuffer endSequence() throws IOException { |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED.get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | } |
| | | |
| | | public void writeByte(final byte b) throws IOException |
| | | { |
| | | buffer.append(b); |
| | | public SequenceBuffer startSequence(final byte type) throws IOException { |
| | | if (child == null) { |
| | | child = new ChildSequenceBuffer(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | outBuffer.ensureAdditionalCapacity(1); |
| | | outBuffer.put(type); |
| | | child.buffer.clear(); |
| | | |
| | | return child; |
| | | } |
| | | |
| | | public void writeByte(final byte b) throws IOException { |
| | | outBuffer.ensureAdditionalCapacity(1); |
| | | outBuffer.put(b); |
| | | } |
| | | |
| | | public void writeByteArray(final byte[] bs, final int offset, final int length) |
| | | throws IOException { |
| | | outBuffer.ensureAdditionalCapacity(length); |
| | | outBuffer.put(bs, offset, length); |
| | | } |
| | | } |
| | | |
| | | private interface SequenceBuffer { |
| | | public SequenceBuffer endSequence() throws IOException; |
| | | |
| | | public SequenceBuffer startSequence(byte type) throws IOException; |
| | | |
| | | public void writeByteArray(final byte[] bs, final int offset, |
| | | final int length) throws IOException |
| | | { |
| | | buffer.append(bs, offset, length); |
| | | } |
| | | } |
| | | public void writeByte(byte b) throws IOException; |
| | | |
| | | |
| | | |
| | | private static final class RecyclableBuffer extends ByteBufferWrapper |
| | | { |
| | | private volatile boolean usable = true; |
| | | |
| | | |
| | | |
| | | private RecyclableBuffer() |
| | | { |
| | | visible = ByteBuffer.allocate(BUFFER_INIT_SIZE); |
| | | allowBufferDispose = true; |
| | | public void writeByteArray(byte[] bs, int offset, int length) throws IOException; |
| | | } |
| | | |
| | | private static final int BUFFER_INIT_SIZE = 1024; |
| | | private final static ThreadCache.CachedTypeIndex<ASN1BufferWriter> WRITER_INDEX = ThreadCache |
| | | .obtainIndex(ASN1BufferWriter.class, 1); |
| | | |
| | | static ASN1BufferWriter getWriter() { |
| | | ASN1BufferWriter asn1Writer = ThreadCache.takeFromCache(WRITER_INDEX); |
| | | if (asn1Writer == null) { |
| | | asn1Writer = new ASN1BufferWriter(); |
| | | } |
| | | |
| | | @Override |
| | | public void dispose() |
| | | { |
| | | usable = true; |
| | | if (!asn1Writer.outBuffer.usable) { |
| | | // If the output buffer is unusable, create a new one. |
| | | asn1Writer.outBuffer = new RecyclableBuffer(); |
| | | } |
| | | asn1Writer.outBuffer.clear(); |
| | | return asn1Writer; |
| | | } |
| | | |
| | | private SequenceBuffer sequenceBuffer; |
| | | private RecyclableBuffer outBuffer; |
| | | |
| | | private final RootSequenceBuffer rootBuffer; |
| | | |
| | | /** |
| | | * Ensures that the specified number of additional bytes will fit in the |
| | | * buffer and resizes it if necessary. |
| | | * |
| | | * @param size |
| | | * The number of additional bytes. |
| | | * Creates a new ASN.1 writer that writes to a StreamWriter. |
| | | */ |
| | | public void ensureAdditionalCapacity(final int size) |
| | | { |
| | | final int newCount = visible.position() + size; |
| | | if (newCount > visible.capacity()) |
| | | { |
| | | final ByteBuffer newByteBuffer = ByteBuffer.allocate(Math.max(visible |
| | | .capacity() << 1, newCount)); |
| | | visible.flip(); |
| | | visible = newByteBuffer.put(visible); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private class RootSequenceBuffer implements SequenceBuffer |
| | | { |
| | | private ChildSequenceBuffer child; |
| | | |
| | | |
| | | |
| | | public SequenceBuffer endSequence() throws IOException |
| | | { |
| | | final LocalizableMessage message = ERR_ASN1_SEQUENCE_WRITE_NOT_STARTED |
| | | .get(); |
| | | throw new IllegalStateException(message.toString()); |
| | | private ASN1BufferWriter() { |
| | | this.sequenceBuffer = this.rootBuffer = new RootSequenceBuffer(); |
| | | this.outBuffer = new RecyclableBuffer(); |
| | | } |
| | | |
| | | |
| | | |
| | | public SequenceBuffer startSequence(final byte type) throws IOException |
| | | { |
| | | if (child == null) |
| | | { |
| | | child = new ChildSequenceBuffer(); |
| | | child.parent = this; |
| | | } |
| | | |
| | | outBuffer.ensureAdditionalCapacity(1); |
| | | outBuffer.put(type); |
| | | child.buffer.clear(); |
| | | |
| | | return child; |
| | | /** |
| | | * Closes this ASN.1 writer and the underlying outputstream. Any unfinished |
| | | * sequences will be ended. |
| | | * |
| | | * @throws IOException |
| | | * if an error occurs while closing the stream. |
| | | */ |
| | | public void close() throws IOException { |
| | | outBuffer = null; |
| | | } |
| | | |
| | | |
| | | |
| | | public void writeByte(final byte b) throws IOException |
| | | { |
| | | outBuffer.ensureAdditionalCapacity(1); |
| | | outBuffer.put(b); |
| | | /** |
| | | * Flushes the stream. |
| | | * |
| | | * @throws IOException |
| | | * If an I/O error occurs |
| | | */ |
| | | public void flush() throws IOException { |
| | | // Do nothing |
| | | } |
| | | |
| | | |
| | | |
| | | public void writeByteArray(final byte[] bs, final int offset, |
| | | final int length) throws IOException |
| | | { |
| | | outBuffer.ensureAdditionalCapacity(length); |
| | | outBuffer.put(bs, offset, length); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private interface SequenceBuffer |
| | | { |
| | | public SequenceBuffer endSequence() throws IOException; |
| | | |
| | | |
| | | |
| | | public SequenceBuffer startSequence(byte type) throws IOException; |
| | | |
| | | |
| | | |
| | | public void writeByte(byte b) throws IOException; |
| | | |
| | | |
| | | |
| | | public void writeByteArray(byte[] bs, int offset, int length) |
| | | throws IOException; |
| | | } |
| | | |
| | | |
| | | |
| | | private static final int BUFFER_INIT_SIZE = 1024; |
| | | private final static ThreadCache.CachedTypeIndex<ASN1BufferWriter> WRITER_INDEX = ThreadCache |
| | | .obtainIndex(ASN1BufferWriter.class, 1); |
| | | |
| | | |
| | | |
| | | static ASN1BufferWriter getWriter() |
| | | { |
| | | ASN1BufferWriter asn1Writer = ThreadCache.takeFromCache(WRITER_INDEX); |
| | | if (asn1Writer == null) |
| | | { |
| | | asn1Writer = new ASN1BufferWriter(); |
| | | public void recycle() { |
| | | sequenceBuffer = rootBuffer; |
| | | outBuffer.clear(); |
| | | ThreadCache.putToCache(WRITER_INDEX, this); |
| | | } |
| | | |
| | | if (!asn1Writer.outBuffer.usable) |
| | | { |
| | | // If the output buffer is unusable, create a new one. |
| | | asn1Writer.outBuffer = new RecyclableBuffer(); |
| | | } |
| | | asn1Writer.outBuffer.clear(); |
| | | return asn1Writer; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeBoolean(final byte type, final boolean booleanValue) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte(booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE); |
| | | |
| | | |
| | | |
| | | private SequenceBuffer sequenceBuffer; |
| | | private RecyclableBuffer outBuffer; |
| | | |
| | | private final RootSequenceBuffer rootBuffer; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new ASN.1 writer that writes to a StreamWriter. |
| | | */ |
| | | private ASN1BufferWriter() |
| | | { |
| | | this.sequenceBuffer = this.rootBuffer = new RootSequenceBuffer(); |
| | | this.outBuffer = new RecyclableBuffer(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Closes this ASN.1 writer and the underlying outputstream. Any unfinished |
| | | * sequences will be ended. |
| | | * |
| | | * @throws IOException |
| | | * if an error occurs while closing the stream. |
| | | */ |
| | | public void close() throws IOException |
| | | { |
| | | outBuffer = null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Flushes the stream. |
| | | * |
| | | * @throws IOException |
| | | * If an I/O error occurs |
| | | */ |
| | | public void flush() throws IOException |
| | | { |
| | | // Do nothing |
| | | } |
| | | |
| | | |
| | | |
| | | public void recycle() |
| | | { |
| | | sequenceBuffer = rootBuffer; |
| | | outBuffer.clear(); |
| | | ThreadCache.putToCache(WRITER_INDEX, this); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeBoolean(final byte type, final boolean booleanValue) |
| | | throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte(booleanValue ? BOOLEAN_VALUE_TRUE |
| | | : BOOLEAN_VALUE_FALSE); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", type, 1, |
| | | String.valueOf(booleanValue))); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEndSequence() throws IOException |
| | | { |
| | | sequenceBuffer = sequenceBuffer.endSequence(); |
| | | |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEndSet() throws IOException |
| | | { |
| | | return writeEndSequence(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEnumerated(final byte type, final int intValue) |
| | | throws IOException |
| | | { |
| | | return writeInteger(type, intValue); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeInteger(final byte type, final int intValue) |
| | | throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | if (((intValue < 0) && ((intValue & 0xFFFFFF80) == 0xFFFFFF80)) |
| | | || ((intValue & 0x0000007F) == intValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1, |
| | | intValue)); |
| | | } |
| | | } |
| | | else if (((intValue < 0) && ((intValue & 0xFFFF8000) == 0xFFFF8000)) |
| | | || ((intValue & 0x00007FFF) == intValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 2); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2, |
| | | intValue)); |
| | | } |
| | | } |
| | | else if (((intValue < 0) && ((intValue & 0xFF800000) == 0xFF800000)) |
| | | || ((intValue & 0x007FFFFF) == intValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 3); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3, |
| | | intValue)); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | writeLength(sequenceBuffer, 4); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4, |
| | | intValue)); |
| | | } |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeInteger(final byte type, final long longValue) |
| | | throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)) |
| | | || ((longValue & 0x000000000000007FL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L)) |
| | | || ((longValue & 0x0000000000007FFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 2); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L)) |
| | | || ((longValue & 0x00000000007FFFFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 3); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L)) |
| | | || ((longValue & 0x000000007FFFFFFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 4); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L)) |
| | | || ((longValue & 0x0000007FFFFFFFFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 5); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 5, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L)) |
| | | || ((longValue & 0x00007FFFFFFFFFFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 6); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 6, |
| | | longValue)); |
| | | } |
| | | } |
| | | else if (((longValue < 0) && ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L)) |
| | | || ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)) |
| | | { |
| | | writeLength(sequenceBuffer, 7); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 7, |
| | | longValue)); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | writeLength(sequenceBuffer, 8); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 56) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 8, |
| | | longValue)); |
| | | } |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeNull(final byte type) throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, 0); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 NULL(type=0x%x, length=%d)", type, 0)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final byte[] value, |
| | | final int offset, final int length) throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, length); |
| | | sequenceBuffer.writeByteArray(value, offset, length); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, length)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final ByteSequence value) |
| | | throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, value.length()); |
| | | // TODO: Is there a more efficient way to do this? |
| | | for (int i = 0; i < value.length(); i++) |
| | | { |
| | | sequenceBuffer.writeByte(value.byteAt(i)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 BOOLEAN(type=0x%x, length=%d, value=%s)", type, 1, String |
| | | .valueOf(booleanValue))); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String |
| | | .format("WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, value |
| | | .length())); |
| | | } |
| | | return this; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEndSequence() throws IOException { |
| | | sequenceBuffer = sequenceBuffer.endSequence(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final String value) |
| | | throws IOException |
| | | { |
| | | sequenceBuffer.writeByte(type); |
| | | |
| | | if (value == null) |
| | | { |
| | | writeLength(sequenceBuffer, 0); |
| | | return this; |
| | | return this; |
| | | } |
| | | |
| | | final byte[] bytes = StaticUtils.getBytes(value); |
| | | writeLength(sequenceBuffer, bytes.length); |
| | | sequenceBuffer.writeByteArray(bytes, 0, bytes.length); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, " + "value=%s)", type, |
| | | bytes.length, value)); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEndSet() throws IOException { |
| | | return writeEndSequence(); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeStartSequence(final byte type) throws IOException |
| | | { |
| | | // Get a child sequence buffer |
| | | sequenceBuffer = sequenceBuffer.startSequence(type); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 START SEQUENCE(type=0x%x)", type)); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeEnumerated(final byte type, final int intValue) throws IOException { |
| | | return writeInteger(type, intValue); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeStartSet(final byte type) throws IOException |
| | | { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | return writeStartSequence(type); |
| | | } |
| | | |
| | | |
| | | |
| | | Buffer getBuffer() |
| | | { |
| | | outBuffer.usable = false; |
| | | return outBuffer.flip(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Writes the provided value for use as the length of an ASN.1 element. |
| | | * |
| | | * @param buffer |
| | | * The sequence buffer to write to. |
| | | * @param length |
| | | * The length to encode for use in an ASN.1 element. |
| | | * @throws IOException |
| | | * if an error occurs while writing. |
| | | */ |
| | | private void writeLength(final SequenceBuffer buffer, final int length) |
| | | throws IOException |
| | | { |
| | | if (length < 128) |
| | | { |
| | | buffer.writeByte((byte) length); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeInteger(final byte type, final int intValue) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | if (((intValue < 0) && ((intValue & 0xFFFFFF80) == 0xFFFFFF80)) |
| | | || ((intValue & 0x0000007F) == intValue)) { |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1, intValue)); |
| | | } |
| | | } else if (((intValue < 0) && ((intValue & 0xFFFF8000) == 0xFFFF8000)) |
| | | || ((intValue & 0x00007FFF) == intValue)) { |
| | | writeLength(sequenceBuffer, 2); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2, intValue)); |
| | | } |
| | | } else if (((intValue < 0) && ((intValue & 0xFF800000) == 0xFF800000)) |
| | | || ((intValue & 0x007FFFFF) == intValue)) { |
| | | writeLength(sequenceBuffer, 3); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3, intValue)); |
| | | } |
| | | } else { |
| | | writeLength(sequenceBuffer, 4); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((intValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (intValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4, intValue)); |
| | | } |
| | | } |
| | | return this; |
| | | } |
| | | else if ((length & 0x000000FF) == length) |
| | | { |
| | | buffer.writeByte((byte) 0x81); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeInteger(final byte type, final long longValue) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)) |
| | | || ((longValue & 0x000000000000007FL) == longValue)) { |
| | | writeLength(sequenceBuffer, 1); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 1, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L)) |
| | | || ((longValue & 0x0000000000007FFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 2); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 2, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L)) |
| | | || ((longValue & 0x00000000007FFFFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 3); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 3, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L)) |
| | | || ((longValue & 0x000000007FFFFFFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 4); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 4, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L)) |
| | | || ((longValue & 0x0000007FFFFFFFFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 5); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 5, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L)) |
| | | || ((longValue & 0x00007FFFFFFFFFFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 6); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 6, longValue)); |
| | | } |
| | | } else if (((longValue < 0) && ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L)) |
| | | || ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)) { |
| | | writeLength(sequenceBuffer, 7); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 7, longValue)); |
| | | } |
| | | } else { |
| | | writeLength(sequenceBuffer, 8); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 56) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 48) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 40) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 32) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 24) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 16) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) ((longValue >> 8) & 0xFF)); |
| | | sequenceBuffer.writeByte((byte) (longValue & 0xFF)); |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 INTEGER(type=0x%x, length=%d, value=%d)", type, 8, longValue)); |
| | | } |
| | | } |
| | | return this; |
| | | } |
| | | else if ((length & 0x0000FFFF) == length) |
| | | { |
| | | buffer.writeByte((byte) 0x82); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeNull(final byte type) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, 0); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("WRITE ASN.1 NULL(type=0x%x, length=%d)", |
| | | type, 0)); |
| | | } |
| | | return this; |
| | | } |
| | | else if ((length & 0x00FFFFFF) == length) |
| | | { |
| | | buffer.writeByte((byte) 0x83); |
| | | buffer.writeByte((byte) ((length >> 16) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final byte[] value, final int offset, |
| | | final int length) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, length); |
| | | sequenceBuffer.writeByteArray(value, offset, length); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, length)); |
| | | } |
| | | return this; |
| | | } |
| | | else |
| | | { |
| | | buffer.writeByte((byte) 0x84); |
| | | buffer.writeByte((byte) ((length >> 24) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 16) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final ByteSequence value) |
| | | throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | writeLength(sequenceBuffer, value.length()); |
| | | // TODO: Is there a more efficient way to do this? |
| | | for (int i = 0; i < value.length(); i++) { |
| | | sequenceBuffer.writeByte(value.byteAt(i)); |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d)", type, value.length())); |
| | | } |
| | | return this; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeOctetString(final byte type, final String value) throws IOException { |
| | | sequenceBuffer.writeByte(type); |
| | | |
| | | if (value == null) { |
| | | writeLength(sequenceBuffer, 0); |
| | | return this; |
| | | } |
| | | |
| | | final byte[] bytes = StaticUtils.getBytes(value); |
| | | writeLength(sequenceBuffer, bytes.length); |
| | | sequenceBuffer.writeByteArray(bytes, 0, bytes.length); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format( |
| | | "WRITE ASN.1 OCTETSTRING(type=0x%x, length=%d, " + "value=%s)", type, |
| | | bytes.length, value)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeStartSequence(final byte type) throws IOException { |
| | | // Get a child sequence buffer |
| | | sequenceBuffer = sequenceBuffer.startSequence(type); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) { |
| | | StaticUtils.DEBUG_LOG.finest(String.format("WRITE ASN.1 START SEQUENCE(type=0x%x)", |
| | | type)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ASN1Writer writeStartSet(final byte type) throws IOException { |
| | | // From an implementation point of view, a set is equivalent to a |
| | | // sequence. |
| | | return writeStartSequence(type); |
| | | } |
| | | |
| | | Buffer getBuffer() { |
| | | outBuffer.usable = false; |
| | | return outBuffer.flip(); |
| | | } |
| | | |
| | | /** |
| | | * Writes the provided value for use as the length of an ASN.1 element. |
| | | * |
| | | * @param buffer |
| | | * The sequence buffer to write to. |
| | | * @param length |
| | | * The length to encode for use in an ASN.1 element. |
| | | * @throws IOException |
| | | * if an error occurs while writing. |
| | | */ |
| | | private void writeLength(final SequenceBuffer buffer, final int length) throws IOException { |
| | | if (length < 128) { |
| | | buffer.writeByte((byte) length); |
| | | } else if ((length & 0x000000FF) == length) { |
| | | buffer.writeByte((byte) 0x81); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | } else if ((length & 0x0000FFFF) == length) { |
| | | buffer.writeByte((byte) 0x82); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | } else if ((length & 0x00FFFFFF) == length) { |
| | | buffer.writeByte((byte) 0x83); |
| | | buffer.writeByte((byte) ((length >> 16) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | } else { |
| | | buffer.writeByte((byte) 0x84); |
| | | buffer.writeByte((byte) ((length >> 24) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 16) & 0xFF)); |
| | | buffer.writeByte((byte) ((length >> 8) & 0xFF)); |
| | | buffer.writeByte((byte) (length & 0xFF)); |
| | | } |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.responses.IntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | |
| | | import com.forgerock.opendj.util.AsynchronousFutureResult; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Abstract future result implementation. |
| | | * |
| | | * @param <S> |
| | | * The type of result returned by this future. |
| | | * The type of result returned by this future. |
| | | */ |
| | | abstract class AbstractLDAPFutureResultImpl<S extends Result> extends |
| | | AsynchronousFutureResult<S> implements IntermediateResponseHandler |
| | | { |
| | | private final Connection connection; |
| | | abstract class AbstractLDAPFutureResultImpl<S extends Result> extends AsynchronousFutureResult<S> |
| | | implements IntermediateResponseHandler { |
| | | private final Connection connection; |
| | | |
| | | private final int requestID; |
| | | private final int requestID; |
| | | |
| | | private IntermediateResponseHandler intermediateResponseHandler; |
| | | private IntermediateResponseHandler intermediateResponseHandler; |
| | | |
| | | private volatile long timestamp; |
| | | private volatile long timestamp; |
| | | |
| | | AbstractLDAPFutureResultImpl(final int requestID, final ResultHandler<? super S> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(resultHandler); |
| | | this.requestID = requestID; |
| | | this.connection = connection; |
| | | this.intermediateResponseHandler = intermediateResponseHandler; |
| | | this.timestamp = System.currentTimeMillis(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final int getRequestID() { |
| | | return requestID; |
| | | } |
| | | |
| | | AbstractLDAPFutureResultImpl(final int requestID, |
| | | final ResultHandler<? super S> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(resultHandler); |
| | | this.requestID = requestID; |
| | | this.connection = connection; |
| | | this.intermediateResponseHandler = intermediateResponseHandler; |
| | | this.timestamp = System.currentTimeMillis(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final int getRequestID() |
| | | { |
| | | return requestID; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final boolean handleIntermediateResponse( |
| | | final IntermediateResponse response) |
| | | { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) |
| | | { |
| | | updateTimestamp(); |
| | | if (intermediateResponseHandler != null) |
| | | { |
| | | if (!intermediateResponseHandler.handleIntermediateResponse(response)) |
| | | { |
| | | intermediateResponseHandler = null; |
| | | @Override |
| | | public final boolean handleIntermediateResponse(final IntermediateResponse response) { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) { |
| | | updateTimestamp(); |
| | | if (intermediateResponseHandler != null) { |
| | | if (!intermediateResponseHandler.handleIntermediateResponse(response)) { |
| | | intermediateResponseHandler = null; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected final ErrorResultException handleCancelRequest( |
| | | final boolean mayInterruptIfRunning) |
| | | { |
| | | connection.abandonAsync(Requests.newAbandonRequest(requestID)); |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | protected void toString(final StringBuilder sb) |
| | | { |
| | | sb.append(" requestID = "); |
| | | sb.append(requestID); |
| | | sb.append(" timestamp = "); |
| | | sb.append(timestamp); |
| | | super.toString(sb); |
| | | } |
| | | |
| | | |
| | | |
| | | final void adaptErrorResult(final Result result) |
| | | { |
| | | final S errorResult = newErrorResult(result.getResultCode(), |
| | | result.getDiagnosticMessage(), result.getCause()); |
| | | setResultOrError(errorResult); |
| | | } |
| | | |
| | | |
| | | |
| | | final long getTimestamp() |
| | | { |
| | | return timestamp; |
| | | } |
| | | |
| | | |
| | | |
| | | abstract S newErrorResult(ResultCode resultCode, String diagnosticMessage, |
| | | Throwable cause); |
| | | |
| | | |
| | | |
| | | final void setResultOrError(final S result) |
| | | { |
| | | if (result.getResultCode().isExceptional()) |
| | | { |
| | | handleErrorResult(ErrorResultException.newErrorResult(result)); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected final ErrorResultException handleCancelRequest(final boolean mayInterruptIfRunning) { |
| | | connection.abandonAsync(Requests.newAbandonRequest(requestID)); |
| | | return null; |
| | | } |
| | | else |
| | | { |
| | | handleResult(result); |
| | | |
| | | @Override |
| | | protected void toString(final StringBuilder sb) { |
| | | sb.append(" requestID = "); |
| | | sb.append(requestID); |
| | | sb.append(" timestamp = "); |
| | | sb.append(timestamp); |
| | | super.toString(sb); |
| | | } |
| | | } |
| | | |
| | | final void adaptErrorResult(final Result result) { |
| | | final S errorResult = |
| | | newErrorResult(result.getResultCode(), result.getDiagnosticMessage(), result |
| | | .getCause()); |
| | | setResultOrError(errorResult); |
| | | } |
| | | |
| | | final long getTimestamp() { |
| | | return timestamp; |
| | | } |
| | | |
| | | final void updateTimestamp() |
| | | { |
| | | timestamp = System.currentTimeMillis(); |
| | | } |
| | | abstract S newErrorResult(ResultCode resultCode, String diagnosticMessage, Throwable cause); |
| | | |
| | | final void setResultOrError(final S result) { |
| | | if (result.getResultCode().isExceptional()) { |
| | | handleErrorResult(ErrorResultException.newErrorResult(result)); |
| | | } else { |
| | | handleResult(result); |
| | | } |
| | | } |
| | | |
| | | final void updateTimestamp() { |
| | | timestamp = System.currentTimeMillis(); |
| | | } |
| | | |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.IntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | |
| | | /** |
| | | * Abstract LDAP message handler. |
| | | * |
| | | * @param <P> |
| | | * A user provided handler parameter. |
| | | * A user provided handler parameter. |
| | | */ |
| | | abstract class AbstractLDAPMessageHandler<P> implements LDAPMessageHandler<P> |
| | | { |
| | | public void abandonRequest(final P param, final int messageID, |
| | | final AbandonRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | abstract class AbstractLDAPMessageHandler<P> implements LDAPMessageHandler<P> { |
| | | public void abandonRequest(final P param, final int messageID, final AbandonRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void addRequest(final P param, final int messageID, final AddRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void addResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void addRequest(final P param, final int messageID, |
| | | final AddRequest request) throws UnexpectedRequestException, IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | public void bindRequest(final P param, final int messageID, final int version, |
| | | final GenericBindRequest request) throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void bindResult(final P param, final int messageID, final BindResult result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void compareRequest(final P param, final int messageID, final CompareRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void addResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | public void compareResult(final P param, final int messageID, final CompareResult result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void deleteRequest(final P param, final int messageID, final DeleteRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void deleteResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void bindRequest(final P param, final int messageID, |
| | | final int version, final GenericBindRequest request) |
| | | throws UnexpectedRequestException, IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | public <R extends ExtendedResult> void extendedRequest(final P param, final int messageID, |
| | | final ExtendedRequest<R> request) throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void extendedResult(final P param, final int messageID, final ExtendedResult result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void intermediateResponse(final P param, final int messageID, |
| | | final IntermediateResponse response) throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, response); |
| | | } |
| | | |
| | | public void bindResult(final P param, final int messageID, |
| | | final BindResult result) throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | public void modifyDNRequest(final P param, final int messageID, final ModifyDNRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void modifyDNResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void modifyRequest(final P param, final int messageID, final ModifyRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void compareRequest(final P param, final int messageID, |
| | | final CompareRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | public void modifyResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void searchRequest(final P param, final int messageID, final SearchRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void searchResult(final P param, final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | public void compareResult(final P param, final int messageID, |
| | | final CompareResult result) throws UnexpectedResponseException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | public void searchResultEntry(final P param, final int messageID, final SearchResultEntry entry) |
| | | throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, entry); |
| | | } |
| | | |
| | | public void searchResultReference(final P param, final int messageID, |
| | | final SearchResultReference reference) throws UnexpectedResponseException, IOException { |
| | | throw new UnexpectedResponseException(messageID, reference); |
| | | } |
| | | |
| | | public void unbindRequest(final P param, final int messageID, final UnbindRequest request) |
| | | throws UnexpectedRequestException, IOException { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | public void deleteRequest(final P param, final int messageID, |
| | | final DeleteRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void deleteResult(final P param, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | |
| | | |
| | | public <R extends ExtendedResult> void extendedRequest(final P param, |
| | | final int messageID, final ExtendedRequest<R> request) |
| | | throws UnexpectedRequestException, IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void extendedResult(final P param, final int messageID, |
| | | final ExtendedResult result) throws UnexpectedResponseException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | |
| | | |
| | | public void intermediateResponse(final P param, final int messageID, |
| | | final IntermediateResponse response) throws UnexpectedResponseException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, response); |
| | | } |
| | | |
| | | |
| | | |
| | | public void modifyDNRequest(final P param, final int messageID, |
| | | final ModifyDNRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void modifyDNResult(final P param, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | |
| | | |
| | | public void modifyRequest(final P param, final int messageID, |
| | | final ModifyRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void modifyResult(final P param, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | |
| | | |
| | | public void searchRequest(final P param, final int messageID, |
| | | final SearchRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void searchResult(final P param, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | |
| | | |
| | | |
| | | public void searchResultEntry(final P param, final int messageID, |
| | | final SearchResultEntry entry) throws UnexpectedResponseException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, entry); |
| | | } |
| | | |
| | | |
| | | |
| | | public void searchResultReference(final P param, final int messageID, |
| | | final SearchResultReference reference) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | throw new UnexpectedResponseException(messageID, reference); |
| | | } |
| | | |
| | | |
| | | |
| | | public void unbindRequest(final P param, final int messageID, |
| | | final UnbindRequest request) throws UnexpectedRequestException, |
| | | IOException |
| | | { |
| | | throw new UnexpectedRequestException(messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | public void unrecognizedMessage(final P param, final int messageID, |
| | | final byte messageTag, final ByteString messageBytes) |
| | | throws UnsupportedMessageException, IOException |
| | | { |
| | | throw new UnsupportedMessageException(messageID, messageTag, messageBytes); |
| | | } |
| | | public void unrecognizedMessage(final P param, final int messageID, final byte messageTag, |
| | | final ByteString messageBytes) throws UnsupportedMessageException, IOException { |
| | | throw new UnsupportedMessageException(messageID, messageTag, messageBytes); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.ConnectionSecurityLayer; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.glassfish.grizzly.AbstractTransformer; |
| | |
| | | import org.glassfish.grizzly.memory.Buffers; |
| | | import org.glassfish.grizzly.memory.MemoryManager; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Connection security layer filter adapter. |
| | | */ |
| | | final class ConnectionSecurityLayerFilter extends |
| | | AbstractCodecFilter<Buffer, Buffer> |
| | | { |
| | | /** |
| | | * <tt>Transformer</tt>, which decodes SASL encrypted data, contained in the |
| | | * input Buffer, to the output Buffer. |
| | | */ |
| | | private static final class Decoder extends |
| | | AbstractTransformer<Buffer, Buffer> |
| | | { |
| | | private static final int BUFFER_SIZE = 4096; |
| | | private final byte[] buffer = new byte[BUFFER_SIZE]; |
| | | private final ConnectionSecurityLayer layer; |
| | | private final MemoryManager<?> memoryManager; |
| | | final class ConnectionSecurityLayerFilter extends AbstractCodecFilter<Buffer, Buffer> { |
| | | /** |
| | | * <tt>Transformer</tt>, which decodes SASL encrypted data, contained in the |
| | | * input Buffer, to the output Buffer. |
| | | */ |
| | | private static final class Decoder extends AbstractTransformer<Buffer, Buffer> { |
| | | private static final int BUFFER_SIZE = 4096; |
| | | private final byte[] buffer = new byte[BUFFER_SIZE]; |
| | | private final ConnectionSecurityLayer layer; |
| | | private final MemoryManager<?> memoryManager; |
| | | |
| | | public Decoder(final ConnectionSecurityLayer layer, final MemoryManager<?> memoryManager) { |
| | | this.layer = layer; |
| | | this.memoryManager = memoryManager; |
| | | } |
| | | |
| | | public String getName() { |
| | | return this.getClass().getName(); |
| | | } |
| | | |
| | | public Decoder(final ConnectionSecurityLayer layer, |
| | | final MemoryManager<?> memoryManager) |
| | | { |
| | | this.layer = layer; |
| | | this.memoryManager = memoryManager; |
| | | public boolean hasInputRemaining(final AttributeStorage storage, final Buffer input) { |
| | | return input != null && input.hasRemaining(); |
| | | } |
| | | |
| | | @Override |
| | | public TransformationResult<Buffer, Buffer> transformImpl(final AttributeStorage storage, |
| | | final Buffer input) { |
| | | |
| | | final int len = Math.min(buffer.length, input.remaining()); |
| | | input.get(buffer, 0, len); |
| | | |
| | | try { |
| | | final Buffer output = Buffers.wrap(memoryManager, layer.unwrap(buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } catch (final ErrorResultException e) { |
| | | return TransformationResult.createErrorResult(e.getResult().getResultCode() |
| | | .intValue(), e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * <tt>Transformer</tt>, which encodes SASL encrypted data, contained in the |
| | | * input Buffer, to the output Buffer. |
| | | */ |
| | | private static final class Encoder extends AbstractTransformer<Buffer, Buffer> { |
| | | private static final int BUFFER_SIZE = 4096; |
| | | private final byte[] buffer = new byte[BUFFER_SIZE]; |
| | | private final ConnectionSecurityLayer layer; |
| | | private final MemoryManager<?> memoryManager; |
| | | |
| | | private Encoder(final ConnectionSecurityLayer layer, final MemoryManager<?> memoryManager) { |
| | | this.layer = layer; |
| | | this.memoryManager = memoryManager; |
| | | } |
| | | |
| | | public String getName() |
| | | { |
| | | return this.getClass().getName(); |
| | | public String getName() { |
| | | return this.getClass().getName(); |
| | | } |
| | | |
| | | public boolean hasInputRemaining(final AttributeStorage storage, final Buffer input) { |
| | | return input != null && input.hasRemaining(); |
| | | } |
| | | |
| | | @Override |
| | | public TransformationResult<Buffer, Buffer> transformImpl(final AttributeStorage storage, |
| | | final Buffer input) { |
| | | |
| | | final int len = Math.min(buffer.length, input.remaining()); |
| | | input.get(buffer, 0, len); |
| | | |
| | | try { |
| | | final Buffer output = Buffers.wrap(memoryManager, layer.wrap(buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } catch (final ErrorResultException e) { |
| | | return TransformationResult.createErrorResult(e.getResult().getResultCode() |
| | | .intValue(), e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public boolean hasInputRemaining(final AttributeStorage storage, |
| | | final Buffer input) |
| | | { |
| | | return input != null && input.hasRemaining(); |
| | | ConnectionSecurityLayerFilter(final ConnectionSecurityLayer layer, |
| | | final MemoryManager<?> memoryManager) { |
| | | super(new Decoder(layer, memoryManager), new Encoder(layer, memoryManager)); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public TransformationResult<Buffer, Buffer> transformImpl( |
| | | final AttributeStorage storage, final Buffer input) |
| | | { |
| | | |
| | | final int len = Math.min(buffer.length, input.remaining()); |
| | | input.get(buffer, 0, len); |
| | | |
| | | try |
| | | { |
| | | final Buffer output = Buffers.wrap(memoryManager, |
| | | layer.unwrap(buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | return TransformationResult.createErrorResult(e.getResult() |
| | | .getResultCode().intValue(), e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * <tt>Transformer</tt>, which encodes SASL encrypted data, contained in the |
| | | * input Buffer, to the output Buffer. |
| | | */ |
| | | private static final class Encoder extends |
| | | AbstractTransformer<Buffer, Buffer> |
| | | { |
| | | private static final int BUFFER_SIZE = 4096; |
| | | private final byte[] buffer = new byte[BUFFER_SIZE]; |
| | | private final ConnectionSecurityLayer layer; |
| | | private final MemoryManager<?> memoryManager; |
| | | |
| | | |
| | | |
| | | private Encoder(final ConnectionSecurityLayer layer, |
| | | final MemoryManager<?> memoryManager) |
| | | { |
| | | this.layer = layer; |
| | | this.memoryManager = memoryManager; |
| | | } |
| | | |
| | | |
| | | |
| | | public String getName() |
| | | { |
| | | return this.getClass().getName(); |
| | | } |
| | | |
| | | |
| | | |
| | | public boolean hasInputRemaining(final AttributeStorage storage, |
| | | final Buffer input) |
| | | { |
| | | return input != null && input.hasRemaining(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public TransformationResult<Buffer, Buffer> transformImpl( |
| | | final AttributeStorage storage, final Buffer input) |
| | | { |
| | | |
| | | final int len = Math.min(buffer.length, input.remaining()); |
| | | input.get(buffer, 0, len); |
| | | |
| | | try |
| | | { |
| | | final Buffer output = Buffers.wrap(memoryManager, |
| | | layer.wrap(buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | return TransformationResult.createErrorResult(e.getResult() |
| | | .getResultCode().intValue(), e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | ConnectionSecurityLayerFilter(final ConnectionSecurityLayer layer, |
| | | final MemoryManager<?> memoryManager) |
| | | { |
| | | super(new Decoder(layer, memoryManager), new Encoder(layer, memoryManager)); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | |
| | | import org.glassfish.grizzly.strategies.SameThreadIOStrategy; |
| | | import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The default {@link TCPNIOTransport} which all {@code LDAPConnectionFactory}s |
| | | * and {@code LDAPListener}s will use unless otherwise specified in their |
| | | * options. |
| | | */ |
| | | final class DefaultTCPNIOTransport |
| | | { |
| | | private static TCPNIOTransport defaultTransport = null; |
| | | final class DefaultTCPNIOTransport { |
| | | private static TCPNIOTransport defaultTransport = null; |
| | | |
| | | /** |
| | | * Returns the default {@link TCPNIOTransport} which all |
| | | * {@code LDAPConnectionFactory}s and {@code LDAPListener}s will use unless |
| | | * otherwise specified in their options. |
| | | * |
| | | * @return The default {@link TCPNIOTransport}. |
| | | */ |
| | | static synchronized TCPNIOTransport getInstance() { |
| | | if (defaultTransport == null) { |
| | | final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance(); |
| | | |
| | | // Determine which threading strategy to use, and total number of |
| | | // threads. |
| | | final String useWorkerThreadsStr = |
| | | System.getProperty("org.forgerock.opendj.transport.useWorkerThreads"); |
| | | final boolean useWorkerThreadStrategy; |
| | | if (useWorkerThreadsStr != null) { |
| | | useWorkerThreadStrategy = Boolean.parseBoolean(useWorkerThreadsStr); |
| | | } else { |
| | | // The most best performing strategy to use is the |
| | | // SameThreadIOStrategy, |
| | | // however it can only be used in cases where result listeners |
| | | // will not |
| | | // block. |
| | | useWorkerThreadStrategy = true; |
| | | } |
| | | |
| | | /** |
| | | * Returns the default {@link TCPNIOTransport} which all |
| | | * {@code LDAPConnectionFactory}s and {@code LDAPListener}s will use unless |
| | | * otherwise specified in their options. |
| | | * |
| | | * @return The default {@link TCPNIOTransport}. |
| | | */ |
| | | static synchronized TCPNIOTransport getInstance() |
| | | { |
| | | if (defaultTransport == null) |
| | | { |
| | | final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder |
| | | .newInstance(); |
| | | if (useWorkerThreadStrategy) { |
| | | builder.setIOStrategy(WorkerThreadIOStrategy.getInstance()); |
| | | } else { |
| | | builder.setIOStrategy(SameThreadIOStrategy.getInstance()); |
| | | } |
| | | |
| | | // Determine which threading strategy to use, and total number of threads. |
| | | final String useWorkerThreadsStr = System |
| | | .getProperty("org.forgerock.opendj.transport.useWorkerThreads"); |
| | | final boolean useWorkerThreadStrategy; |
| | | if (useWorkerThreadsStr != null) |
| | | { |
| | | useWorkerThreadStrategy = Boolean |
| | | .parseBoolean(useWorkerThreadsStr); |
| | | } |
| | | else |
| | | { |
| | | // The most best performing strategy to use is the SameThreadIOStrategy, |
| | | // however it can only be used in cases where result listeners will not |
| | | // block. |
| | | useWorkerThreadStrategy = true; |
| | | } |
| | | // Calculate thread counts. |
| | | final int cpus = Runtime.getRuntime().availableProcessors(); |
| | | |
| | | if (useWorkerThreadStrategy) |
| | | { |
| | | builder.setIOStrategy(WorkerThreadIOStrategy.getInstance()); |
| | | } |
| | | else |
| | | { |
| | | builder.setIOStrategy(SameThreadIOStrategy.getInstance()); |
| | | } |
| | | // Calculate the number of selector threads. |
| | | final String selectorsStr = |
| | | System.getProperty("org.forgerock.opendj.transport.selectors"); |
| | | final int selectorThreadCount; |
| | | |
| | | // Calculate thread counts. |
| | | final int cpus = Runtime.getRuntime().availableProcessors(); |
| | | if (selectorsStr != null) { |
| | | selectorThreadCount = Integer.parseInt(selectorsStr); |
| | | } else { |
| | | selectorThreadCount = |
| | | useWorkerThreadStrategy ? Math.max(2, cpus / 4) : Math.max(5, |
| | | (cpus / 2) - 1); |
| | | } |
| | | |
| | | // Calculate the number of selector threads. |
| | | final String selectorsStr = System |
| | | .getProperty("org.forgerock.opendj.transport.selectors"); |
| | | final int selectorThreadCount; |
| | | builder.getSelectorThreadPoolConfig().setCorePoolSize(selectorThreadCount) |
| | | .setMaxPoolSize(selectorThreadCount).setPoolName( |
| | | "OpenDJ LDAP SDK Grizzly selector thread"); |
| | | |
| | | if (selectorsStr != null) |
| | | { |
| | | selectorThreadCount = Integer.parseInt(selectorsStr); |
| | | } |
| | | else |
| | | { |
| | | selectorThreadCount = useWorkerThreadStrategy ? Math.max(2, |
| | | cpus / 4) : Math.max(5, (cpus / 2) - 1); |
| | | } |
| | | // Calculate the number of worker threads. |
| | | if (builder.getWorkerThreadPoolConfig() != null) { |
| | | final String workersStr = |
| | | System.getProperty("org.forgerock.opendj.transport.workers"); |
| | | final int workerThreadCount; |
| | | |
| | | builder.getSelectorThreadPoolConfig() |
| | | .setCorePoolSize(selectorThreadCount) |
| | | .setMaxPoolSize(selectorThreadCount) |
| | | .setPoolName("OpenDJ LDAP SDK Grizzly selector thread"); |
| | | if (workersStr != null) { |
| | | workerThreadCount = Integer.parseInt(workersStr); |
| | | } else { |
| | | workerThreadCount = useWorkerThreadStrategy ? Math.max(5, (cpus * 2)) : 0; |
| | | } |
| | | |
| | | // Calculate the number of worker threads. |
| | | if (builder.getWorkerThreadPoolConfig() != null) |
| | | { |
| | | final String workersStr = System |
| | | .getProperty("org.forgerock.opendj.transport.workers"); |
| | | final int workerThreadCount; |
| | | builder.getWorkerThreadPoolConfig().setCorePoolSize(workerThreadCount) |
| | | .setMaxPoolSize(workerThreadCount).setPoolName( |
| | | "OpenDJ LDAP SDK Grizzly worker thread"); |
| | | } |
| | | |
| | | if (workersStr != null) |
| | | { |
| | | workerThreadCount = Integer.parseInt(workersStr); |
| | | } |
| | | else |
| | | { |
| | | workerThreadCount = useWorkerThreadStrategy ? Math.max(5, |
| | | (cpus * 2)) : 0; |
| | | // Parse IO related options. |
| | | final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger"); |
| | | if (lingerStr != null) { |
| | | // Disabled by default. |
| | | builder.setLinger(Integer.parseInt(lingerStr)); |
| | | } |
| | | |
| | | final String tcpNoDelayStr = |
| | | System.getProperty("org.forgerock.opendj.transport.tcpNoDelay"); |
| | | if (tcpNoDelayStr != null) { |
| | | // Enabled by default. |
| | | builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr)); |
| | | } |
| | | |
| | | final String reuseAddressStr = |
| | | System.getProperty("org.forgerock.opendj.transport.reuseAddress"); |
| | | if (reuseAddressStr != null) { |
| | | // Enabled by default. |
| | | builder.setReuseAddress(Boolean.parseBoolean(reuseAddressStr)); |
| | | } |
| | | |
| | | defaultTransport = builder.build(); |
| | | |
| | | // FIXME: raise bug in Grizzly. We should not need to do this, but |
| | | // failure |
| | | // to do so causes many deadlocks. |
| | | defaultTransport.setSelectorRunnersCount(selectorThreadCount); |
| | | |
| | | try { |
| | | defaultTransport.start(); |
| | | } catch (final IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | builder.getWorkerThreadPoolConfig() |
| | | .setCorePoolSize(workerThreadCount) |
| | | .setMaxPoolSize(workerThreadCount) |
| | | .setPoolName("OpenDJ LDAP SDK Grizzly worker thread"); |
| | | } |
| | | |
| | | // Parse IO related options. |
| | | final String lingerStr = System |
| | | .getProperty("org.forgerock.opendj.transport.linger"); |
| | | if (lingerStr != null) |
| | | { |
| | | // Disabled by default. |
| | | builder.setLinger(Integer.parseInt(lingerStr)); |
| | | } |
| | | |
| | | final String tcpNoDelayStr = System |
| | | .getProperty("org.forgerock.opendj.transport.tcpNoDelay"); |
| | | if (tcpNoDelayStr != null) |
| | | { |
| | | // Enabled by default. |
| | | builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr)); |
| | | } |
| | | |
| | | final String reuseAddressStr = System |
| | | .getProperty("org.forgerock.opendj.transport.reuseAddress"); |
| | | if (reuseAddressStr != null) |
| | | { |
| | | // Enabled by default. |
| | | builder |
| | | .setReuseAddress(Boolean.parseBoolean(reuseAddressStr)); |
| | | } |
| | | |
| | | defaultTransport = builder.build(); |
| | | |
| | | // FIXME: raise bug in Grizzly. We should not need to do this, but failure |
| | | // to do so causes many deadlocks. |
| | | defaultTransport.setSelectorRunnersCount(selectorThreadCount); |
| | | |
| | | try |
| | | { |
| | | defaultTransport.start(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | throw new RuntimeException(e); |
| | | } |
| | | return defaultTransport; |
| | | } |
| | | |
| | | return defaultTransport; |
| | | } |
| | | |
| | | |
| | | |
| | | private DefaultTCPNIOTransport() |
| | | { |
| | | // Prevent instantiation. |
| | | } |
| | | private DefaultTCPNIOTransport() { |
| | | // Prevent instantiation. |
| | | } |
| | | |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.util.List; |
| | | import java.util.concurrent.CopyOnWriteArrayList; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldap.AbstractAsynchronousConnection; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ConnectionEventListener; |
| | | import org.forgerock.opendj.ldap.FutureResult; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.ServerConnection; |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.BindRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | |
| | | import com.forgerock.opendj.util.CompletedFutureResult; |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class defines a pseudo-connection object that can be used for performing |
| | | * internal operations directly against a {@code ServerConnection} |
| | | * implementation. |
| | | */ |
| | | public final class InternalConnection extends AbstractAsynchronousConnection |
| | | { |
| | | private static final class InternalBindFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<BindResult> |
| | | { |
| | | private final BindRequest bindRequest; |
| | | public final class InternalConnection extends AbstractAsynchronousConnection { |
| | | private static final class InternalBindFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<BindResult> { |
| | | private final BindRequest bindRequest; |
| | | |
| | | InternalBindFutureResultImpl(final int messageID, final BindRequest bindRequest, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | this.bindRequest = bindRequest; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("InternalBindFutureResultImpl("); |
| | | sb.append("bindRequest = "); |
| | | sb.append(bindRequest); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | InternalBindFutureResultImpl(final int messageID, |
| | | final BindRequest bindRequest, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | this.bindRequest = bindRequest; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return Responses.newBindResult(resultCode).setDiagnosticMessage(diagnosticMessage) |
| | | .setCause(cause); |
| | | } |
| | | } |
| | | |
| | | private final ServerConnection<Integer> serverConnection; |
| | | private final List<ConnectionEventListener> listeners = |
| | | new CopyOnWriteArrayList<ConnectionEventListener>(); |
| | | private final AtomicInteger messageID = new AtomicInteger(); |
| | | |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("InternalBindFutureResultImpl("); |
| | | sb.append("bindRequest = "); |
| | | sb.append(bindRequest); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | /** |
| | | * Sets the server connection associated with this internal connection. |
| | | * |
| | | * @param serverConnection |
| | | * The server connection. |
| | | */ |
| | | public InternalConnection(final ServerConnection<Integer> serverConnection) { |
| | | this.serverConnection = serverConnection; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindResult newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newBindResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | public FutureResult<Void> abandonAsync(final AbandonRequest request) { |
| | | final int i = messageID.getAndIncrement(); |
| | | serverConnection.handleAbandon(i, request); |
| | | return new CompletedFutureResult<Void>((Void) null, i); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> addAsync(final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler, |
| | | this); |
| | | serverConnection.handleAdd(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.add(listener); |
| | | } |
| | | |
| | | private final ServerConnection<Integer> serverConnection; |
| | | private final List<ConnectionEventListener> listeners = |
| | | new CopyOnWriteArrayList<ConnectionEventListener>(); |
| | | private final AtomicInteger messageID = new AtomicInteger(); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<BindResult> bindAsync(final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final InternalBindFutureResultImpl future = |
| | | new InternalBindFutureResultImpl(i, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | serverConnection.handleBind(i, 3, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close(final UnbindRequest request, final String reason) { |
| | | final int i = messageID.getAndIncrement(); |
| | | serverConnection.handleConnectionClosed(i, request); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<CompareResult> compareAsync(final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPCompareFutureResultImpl future = |
| | | new LDAPCompareFutureResultImpl(i, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | serverConnection.handleCompare(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * Sets the server connection associated with this internal connection. |
| | | * |
| | | * @param serverConnection |
| | | * The server connection. |
| | | */ |
| | | public InternalConnection(final ServerConnection<Integer> serverConnection) |
| | | { |
| | | this.serverConnection = serverConnection; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> deleteAsync(final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler, |
| | | this); |
| | | serverConnection.handleDelete(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync( |
| | | final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPExtendedFutureResultImpl<R> future = |
| | | new LDAPExtendedFutureResultImpl<R>(i, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | serverConnection.handleExtendedRequest(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() { |
| | | // FIXME: this should be true after close has been called. |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Void> abandonAsync(final AbandonRequest request) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | serverConnection.handleAbandon(i, request); |
| | | return new CompletedFutureResult<Void>((Void) null, i); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isValid() { |
| | | // FIXME: this should be false if this connection is disconnected. |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyAsync(final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler, |
| | | this); |
| | | serverConnection.handleModify(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler, |
| | | this); |
| | | serverConnection.handleModifyDN(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> addAsync(final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, |
| | | resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleAdd(i, request, future, future); |
| | | return future; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.remove(listener); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> searchAsync(final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPSearchFutureResultImpl future = |
| | | new LDAPSearchFutureResultImpl(i, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | serverConnection.handleSearch(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.add(listener); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<BindResult> bindAsync(final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final InternalBindFutureResultImpl future = new InternalBindFutureResultImpl( |
| | | i, request, resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleBind(i, 3, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close(final UnbindRequest request, final String reason) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | serverConnection.handleConnectionClosed(i, request); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<CompareResult> compareAsync(final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl( |
| | | i, request, resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleCompare(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> deleteAsync(final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, |
| | | resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleDelete(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync( |
| | | final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>( |
| | | i, request, resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleExtendedRequest(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() |
| | | { |
| | | // FIXME: this should be true after close has been called. |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isValid() |
| | | { |
| | | // FIXME: this should be false if this connection is disconnected. |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyAsync(final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, |
| | | resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleModify(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, |
| | | resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleModifyDN(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeConnectionEventListener( |
| | | final ConnectionEventListener listener) |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.remove(listener); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> searchAsync(final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(i, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleSearch(i, request, future, future); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("InternalConnection("); |
| | | builder.append(String.valueOf(serverConnection)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("InternalConnection("); |
| | | builder.append(String.valueOf(serverConnection)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Bind result future implementation. |
| | | */ |
| | | final class LDAPBindFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<BindResult> |
| | | { |
| | | private final BindClient bindClient; |
| | | final class LDAPBindFutureResultImpl extends AbstractLDAPFutureResultImpl<BindResult> { |
| | | private final BindClient bindClient; |
| | | |
| | | LDAPBindFutureResultImpl(final int requestID, final BindClient bindClient, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.bindClient = bindClient; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected boolean isCancelable() { |
| | | return false; |
| | | } |
| | | |
| | | LDAPBindFutureResultImpl(final int requestID, final BindClient bindClient, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.bindClient = bindClient; |
| | | } |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPBindFutureResultImpl("); |
| | | sb.append("bindClient = "); |
| | | sb.append(bindClient); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | BindClient getBindClient() { |
| | | return bindClient; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected boolean isCancelable() { |
| | | return false; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPBindFutureResultImpl("); |
| | | sb.append("bindClient = "); |
| | | sb.append(bindClient); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | BindClient getBindClient() |
| | | { |
| | | return bindClient; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindResult newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newBindResult(resultCode).setDiagnosticMessage( |
| | | diagnosticMessage).setCause(cause); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return Responses.newBindResult(resultCode).setDiagnosticMessage(diagnosticMessage) |
| | | .setCause(cause); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.OID_NOTICE_OF_DISCONNECTION; |
| | | |
| | | import java.io.EOFException; |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.BindClient; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.IntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.Connection; |
| | | import org.glassfish.grizzly.EmptyCompletionHandler; |
| | |
| | | import org.glassfish.grizzly.filterchain.FilterChainContext; |
| | | import org.glassfish.grizzly.filterchain.NextAction; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Grizzly filter implementation for decoding LDAP responses and handling client |
| | | * side logic for SSL and SASL operations over LDAP. |
| | | */ |
| | | final class LDAPClientFilter extends BaseFilter |
| | | { |
| | | private static final Attribute<LDAPConnection> LDAP_CONNECTION_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPClientConnection"); |
| | | private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader"); |
| | | final class LDAPClientFilter extends BaseFilter { |
| | | private static final Attribute<LDAPConnection> LDAP_CONNECTION_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPClientConnection"); |
| | | private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader"); |
| | | |
| | | private final int maxASN1ElementSize; |
| | | private final LDAPReader ldapReader; |
| | | private final int maxASN1ElementSize; |
| | | private final LDAPReader ldapReader; |
| | | |
| | | private static final AbstractLDAPMessageHandler<FilterChainContext> |
| | | CLIENT_RESPONSE_HANDLER = new AbstractLDAPMessageHandler<FilterChainContext>() |
| | | { |
| | | @Override |
| | | public void addResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | private static final AbstractLDAPMessageHandler<FilterChainContext> CLIENT_RESPONSE_HANDLER = |
| | | new AbstractLDAPMessageHandler<FilterChainContext>() { |
| | | @Override |
| | | public void addResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) |
| | | { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof AddRequest) |
| | | { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void bindResult(final FilterChainContext ctx, final int messageID, |
| | | final BindResult result) throws UnexpectedResponseException, |
| | | IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPBindFutureResultImpl) |
| | | { |
| | | final LDAPBindFutureResultImpl future = |
| | | ((LDAPBindFutureResultImpl) pendingRequest); |
| | | final BindClient bindClient = future.getBindClient(); |
| | | |
| | | try |
| | | { |
| | | if (!bindClient.evaluateResult(result)) |
| | | { |
| | | // The server is expecting a multi stage bind response. |
| | | final int msgID = |
| | | ldapConnection.continuePendingBindRequest(future); |
| | | |
| | | final ASN1BufferWriter asn1Writer = |
| | | ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | final GenericBindRequest nextRequest = bindClient |
| | | .nextBindRequest(); |
| | | new LDAPWriter().bindRequest(asn1Writer, msgID, 3, |
| | | nextRequest); |
| | | ctx.write(asn1Writer.getBuffer(), null); |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof AddRequest) { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | |
| | | @Override |
| | | public void bindResult(final FilterChainContext ctx, final int messageID, |
| | | final BindResult result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPBindFutureResultImpl) { |
| | | final LDAPBindFutureResultImpl future = |
| | | ((LDAPBindFutureResultImpl) pendingRequest); |
| | | final BindClient bindClient = future.getBindClient(); |
| | | |
| | | try { |
| | | if (!bindClient.evaluateResult(result)) { |
| | | // The server is expecting a multi stage |
| | | // bind response. |
| | | final int msgID = |
| | | ldapConnection.continuePendingBindRequest(future); |
| | | |
| | | final ASN1BufferWriter asn1Writer = |
| | | ASN1BufferWriter.getWriter(); |
| | | try { |
| | | final GenericBindRequest nextRequest = |
| | | bindClient.nextBindRequest(); |
| | | new LDAPWriter().bindRequest(asn1Writer, msgID, 3, |
| | | nextRequest); |
| | | ctx.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return; |
| | | } |
| | | } catch (final ErrorResultException e) { |
| | | future.adaptErrorResult(e.getResult()); |
| | | return; |
| | | } catch (final IOException e) { |
| | | // FIXME: I18N need to have a better error |
| | | // message. |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e); |
| | | future.adaptErrorResult(errorResult); |
| | | return; |
| | | } |
| | | |
| | | if (result.getResultCode() == ResultCode.SUCCESS) { |
| | | final ConnectionSecurityLayer l = |
| | | bindClient.getConnectionSecurityLayer(); |
| | | if (l != null) { |
| | | // The connection needs to be secured by |
| | | // the SASL |
| | | // mechanism. |
| | | ldapConnection |
| | | .installFilter(new ConnectionSecurityLayerFilter(l, |
| | | ctx.getConnection().getTransport() |
| | | .getMemoryManager())); |
| | | } |
| | | } |
| | | |
| | | ldapConnection.setBindOrStartTLSInProgress(false); |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | return; |
| | | } |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | future.adaptErrorResult(e.getResult()); |
| | | return; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e); |
| | | future.adaptErrorResult(errorResult); |
| | | return; |
| | | } |
| | | |
| | | if (result.getResultCode() == ResultCode.SUCCESS) |
| | | { |
| | | final ConnectionSecurityLayer l = bindClient |
| | | .getConnectionSecurityLayer(); |
| | | if (l != null) |
| | | { |
| | | // The connection needs to be secured by the SASL |
| | | // mechanism. |
| | | ldapConnection.installFilter(new ConnectionSecurityLayerFilter(l, ctx |
| | | .getConnection().getTransport().getMemoryManager())); |
| | | } |
| | | } |
| | | @Override |
| | | public void compareResult(final FilterChainContext ctx, final int messageID, |
| | | final CompareResult result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | ldapConnection.setBindOrStartTLSInProgress(false); |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPCompareFutureResultImpl) { |
| | | final LDAPCompareFutureResultImpl future = |
| | | (LDAPCompareFutureResultImpl) pendingRequest; |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void deleteResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof DeleteRequest) { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void compareResult(final FilterChainContext ctx, |
| | | final int messageID, final CompareResult result) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | @Override |
| | | public void extendedResult(final FilterChainContext ctx, final int messageID, |
| | | final ExtendedResult result) throws UnexpectedResponseException, |
| | | IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | if (messageID == 0) { |
| | | if ((result.getOID() != null) |
| | | && result.getOID().equals(OID_NOTICE_OF_DISCONNECTION)) { |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPCompareFutureResultImpl) |
| | | { |
| | | final LDAPCompareFutureResultImpl future = |
| | | (LDAPCompareFutureResultImpl) pendingRequest; |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | final Result errorResult = |
| | | Responses |
| | | .newResult(result.getResultCode()) |
| | | .setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | ldapConnection.close(null, true, errorResult); |
| | | return; |
| | | } else { |
| | | // Unsolicited notification received. |
| | | ldapConnection.handleUnsolicitedNotification(result); |
| | | } |
| | | } |
| | | |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPExtendedFutureResultImpl<?>) { |
| | | final LDAPExtendedFutureResultImpl<?> extendedFuture = |
| | | ((LDAPExtendedFutureResultImpl<?>) pendingRequest); |
| | | try { |
| | | handleExtendedResult0(ldapConnection, extendedFuture, result); |
| | | } catch (final DecodeException de) { |
| | | // FIXME: should the connection be closed as |
| | | // well? |
| | | final Result errorResult = |
| | | Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setDiagnosticMessage(de.getLocalizedMessage()) |
| | | .setCause(de); |
| | | extendedFuture.adaptErrorResult(errorResult); |
| | | } |
| | | } else { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void deleteResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | @Override |
| | | public void intermediateResponse(final FilterChainContext ctx, final int messageID, |
| | | final IntermediateResponse response) throws UnexpectedResponseException, |
| | | IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.getPendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) |
| | | { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof DeleteRequest) |
| | | { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | if (pendingRequest != null) { |
| | | pendingRequest.handleIntermediateResponse(response); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void modifyDNResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof ModifyDNRequest) { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void extendedResult(final FilterChainContext ctx, |
| | | final int messageID, final ExtendedResult result) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | if (messageID == 0) |
| | | { |
| | | if ((result.getOID() != null) |
| | | && result.getOID().equals(OID_NOTICE_OF_DISCONNECTION)) |
| | | { |
| | | @Override |
| | | public void modifyResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | final Result errorResult = Responses |
| | | .newResult(result.getResultCode()).setDiagnosticMessage( |
| | | result.getDiagnosticMessage()); |
| | | ldapConnection.close(null, true, errorResult); |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | // Unsolicited notification received. |
| | | ldapConnection.handleUnsolicitedNotification(result); |
| | | } |
| | | } |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof ModifyRequest) { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | @Override |
| | | public void searchResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.removePendingRequest(messageID); |
| | | |
| | | if(pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPExtendedFutureResultImpl<?>) |
| | | { |
| | | final LDAPExtendedFutureResultImpl<?> extendedFuture = |
| | | ((LDAPExtendedFutureResultImpl<?>) pendingRequest); |
| | | try |
| | | { |
| | | handleExtendedResult0(ldapConnection, extendedFuture, result); |
| | | } |
| | | catch (final DecodeException de) |
| | | { |
| | | // FIXME: should the connection be closed as well? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage( |
| | | de.getLocalizedMessage()).setCause(de); |
| | | extendedFuture.adaptErrorResult(errorResult); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest) |
| | | .setResultOrError(result); |
| | | } else { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void searchResultEntry(final FilterChainContext ctx, final int messageID, |
| | | final SearchResultEntry entry) throws UnexpectedResponseException, |
| | | IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.getPendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest).handleEntry(entry); |
| | | } else { |
| | | throw new UnexpectedResponseException(messageID, entry); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void intermediateResponse(final FilterChainContext ctx, |
| | | final int messageID, final IntermediateResponse response) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .getPendingRequest(messageID); |
| | | @Override |
| | | public void searchResultReference(final FilterChainContext ctx, |
| | | final int messageID, final SearchResultReference reference) |
| | | throws UnexpectedResponseException, IOException { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (ldapConnection != null) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = |
| | | ldapConnection.getPendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | pendingRequest.handleIntermediateResponse(response); |
| | | } |
| | | } |
| | | } |
| | | if (pendingRequest != null) { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest) |
| | | .handleReference(reference); |
| | | } else { |
| | | throw new UnexpectedResponseException(messageID, reference); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Needed in order to expose type information. |
| | | private <R extends ExtendedResult> void handleExtendedResult0( |
| | | final LDAPConnection conn, final LDAPExtendedFutureResultImpl<R> future, |
| | | final ExtendedResult result) throws DecodeException { |
| | | final R decodedResponse = |
| | | future.decodeResult(result, conn.getLDAPOptions().getDecodeOptions()); |
| | | |
| | | if (future.getRequest() instanceof StartTLSExtendedRequest) { |
| | | if (result.getResultCode() == ResultCode.SUCCESS) { |
| | | try { |
| | | final StartTLSExtendedRequest request = |
| | | (StartTLSExtendedRequest) future.getRequest(); |
| | | conn.startTLS(request.getSSLContext(), request |
| | | .getEnabledProtocols(), request.getEnabledCipherSuites(), |
| | | new EmptyCompletionHandler<SSLEngine>() { |
| | | @Override |
| | | public void completed(final SSLEngine result) { |
| | | conn.setBindOrStartTLSInProgress(false); |
| | | future.setResultOrError(decodedResponse); |
| | | } |
| | | |
| | | @Override |
| | | public void modifyDNResult(final FilterChainContext ctx, |
| | | final int messageID, final Result result) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | @Override |
| | | public void failed(final Throwable throwable) { |
| | | final Result errorResult = |
| | | Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setCause(throwable) |
| | | .setDiagnosticMessage( |
| | | "SSL handshake failed"); |
| | | conn.setBindOrStartTLSInProgress(false); |
| | | conn.close(null, false, errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | }); |
| | | return; |
| | | } catch (final IOException e) { |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setCause(e).setDiagnosticMessage(e.getMessage()); |
| | | future.adaptErrorResult(errorResult); |
| | | conn.close(null, false, errorResult); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) |
| | | { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof ModifyDNRequest) |
| | | { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void modifyResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPFutureResultImpl) |
| | | { |
| | | final LDAPFutureResultImpl future = |
| | | (LDAPFutureResultImpl) pendingRequest; |
| | | if (future.getRequest() instanceof ModifyRequest) |
| | | { |
| | | future.setResultOrError(result); |
| | | return; |
| | | } |
| | | } |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void searchResult(final FilterChainContext ctx, final int messageID, |
| | | final Result result) throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .removePendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) |
| | | { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest) |
| | | .setResultOrError(result); |
| | | } |
| | | else |
| | | { |
| | | throw new UnexpectedResponseException(messageID, result); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void searchResultEntry(final FilterChainContext ctx, |
| | | final int messageID, final SearchResultEntry entry) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .getPendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) |
| | | { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest).handleEntry(entry); |
| | | } |
| | | else |
| | | { |
| | | throw new UnexpectedResponseException(messageID, entry); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void searchResultReference(final FilterChainContext ctx, |
| | | final int messageID, final SearchResultReference reference) |
| | | throws UnexpectedResponseException, IOException |
| | | { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if(ldapConnection != null) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest = ldapConnection |
| | | .getPendingRequest(messageID); |
| | | |
| | | if (pendingRequest != null) |
| | | { |
| | | if (pendingRequest instanceof LDAPSearchFutureResultImpl) |
| | | { |
| | | ((LDAPSearchFutureResultImpl) pendingRequest) |
| | | .handleReference(reference); |
| | | } |
| | | else |
| | | { |
| | | throw new UnexpectedResponseException(messageID, reference); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | // Needed in order to expose type information. |
| | | private <R extends ExtendedResult> void handleExtendedResult0( |
| | | final LDAPConnection conn, |
| | | final LDAPExtendedFutureResultImpl<R> future, |
| | | final ExtendedResult result) throws DecodeException |
| | | { |
| | | final R decodedResponse = future.decodeResult(result, conn |
| | | .getLDAPOptions().getDecodeOptions()); |
| | | |
| | | if (future.getRequest() instanceof StartTLSExtendedRequest) |
| | | { |
| | | if (result.getResultCode() == ResultCode.SUCCESS) |
| | | { |
| | | try |
| | | { |
| | | final StartTLSExtendedRequest request = (StartTLSExtendedRequest) future |
| | | .getRequest(); |
| | | conn.startTLS(request.getSSLContext(), |
| | | request.getEnabledProtocols(), request.getEnabledCipherSuites(), |
| | | new EmptyCompletionHandler<SSLEngine>() |
| | | { |
| | | @Override |
| | | public void completed(final SSLEngine result) |
| | | { |
| | | conn.setBindOrStartTLSInProgress(false); |
| | | future.setResultOrError(decodedResponse); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | LDAPClientFilter(final LDAPReader ldapReader, final int maxASN1ElementSize) { |
| | | this.ldapReader = ldapReader; |
| | | this.maxASN1ElementSize = maxASN1ElementSize; |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void failed(final Throwable throwable) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(throwable) |
| | | .setDiagnosticMessage("SSL handshake failed"); |
| | | conn.setBindOrStartTLSInProgress(false); |
| | | conn.close(null, false, errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | }); |
| | | @Override |
| | | public void exceptionOccurred(final FilterChainContext ctx, final Throwable error) { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | if (!connection.isOpen()) { |
| | | // Grizzly doens't not deregister the read interest from the |
| | | // selector so closing the connection results in an |
| | | // EOFException. |
| | | // Just ignore errors on closed connections. |
| | | return; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e) |
| | | .setDiagnosticMessage(e.getMessage()); |
| | | future.adaptErrorResult(errorResult); |
| | | conn.close(null, false, errorResult); |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(connection); |
| | | |
| | | future.setResultOrError(decodedResponse); |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | LDAPClientFilter(final LDAPReader ldapReader, final int maxASN1ElementSize) |
| | | { |
| | | this.ldapReader = ldapReader; |
| | | this.maxASN1ElementSize = maxASN1ElementSize; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void exceptionOccurred(final FilterChainContext ctx, |
| | | final Throwable error) |
| | | { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | if (!connection.isOpen()) |
| | | { |
| | | // Grizzly doens't not deregister the read interest from the |
| | | // selector so closing the connection results in an |
| | | // EOFException. |
| | | // Just ignore errors on closed connections. |
| | | return; |
| | | } |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(connection); |
| | | |
| | | Result errorResult; |
| | | if (error instanceof EOFException) |
| | | { |
| | | // FIXME: Is this the best result code? |
| | | errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN) |
| | | .setCause(error); |
| | | } |
| | | else |
| | | { |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setCause(error); |
| | | } |
| | | ldapConnection.close(null, false, errorResult); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public NextAction handleClose(final FilterChainContext ctx) |
| | | throws IOException |
| | | { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR |
| | | .remove(connection); |
| | | if (ldapConnection != null) |
| | | { |
| | | TimeoutChecker.INSTANCE.removeConnection(ldapConnection); |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN); |
| | | ldapConnection.close(null, false, errorResult); |
| | | } |
| | | return ctx.getInvokeAction(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public NextAction handleRead(final FilterChainContext ctx) throws IOException |
| | | { |
| | | final Buffer buffer = (Buffer) ctx.getMessage(); |
| | | ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR |
| | | .get(ctx.getConnection()); |
| | | if (asn1Reader == null) |
| | | { |
| | | asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection() |
| | | .getTransport().getMemoryManager()); |
| | | LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader); |
| | | } |
| | | asn1Reader.appendBytesRead(buffer); |
| | | |
| | | try |
| | | { |
| | | while (asn1Reader.elementAvailable()) |
| | | { |
| | | ldapReader.decode(asn1Reader, CLIENT_RESPONSE_HANDLER, ctx); |
| | | } |
| | | } |
| | | catch(IOException ioe) |
| | | { |
| | | final LDAPConnection ldapConnection = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setCause(ioe).setDiagnosticMessage(ioe.getMessage()); |
| | | ldapConnection.close(null, false, errorResult); |
| | | throw ioe; |
| | | } |
| | | finally |
| | | { |
| | | asn1Reader.disposeBytesRead(); |
| | | Result errorResult; |
| | | if (error instanceof EOFException) { |
| | | // FIXME: Is this the best result code? |
| | | errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN).setCause(error); |
| | | } else { |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(error); |
| | | } |
| | | ldapConnection.close(null, false, errorResult); |
| | | } |
| | | |
| | | return ctx.getStopAction(); |
| | | } |
| | | @Override |
| | | public NextAction handleClose(final FilterChainContext ctx) throws IOException { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.remove(connection); |
| | | if (ldapConnection != null) { |
| | | TimeoutChecker.INSTANCE.removeConnection(ldapConnection); |
| | | final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN); |
| | | ldapConnection.close(null, false, errorResult); |
| | | } |
| | | return ctx.getInvokeAction(); |
| | | } |
| | | |
| | | @Override |
| | | public NextAction handleRead(final FilterChainContext ctx) throws IOException { |
| | | final Buffer buffer = (Buffer) ctx.getMessage(); |
| | | ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR.get(ctx.getConnection()); |
| | | if (asn1Reader == null) { |
| | | asn1Reader = |
| | | new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection().getTransport() |
| | | .getMemoryManager()); |
| | | LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader); |
| | | } |
| | | asn1Reader.appendBytesRead(buffer); |
| | | |
| | | try { |
| | | while (asn1Reader.elementAvailable()) { |
| | | ldapReader.decode(asn1Reader, CLIENT_RESPONSE_HANDLER, ctx); |
| | | } |
| | | } catch (IOException ioe) { |
| | | final LDAPConnection ldapConnection = LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR).setCause(ioe) |
| | | .setDiagnosticMessage(ioe.getMessage()); |
| | | ldapConnection.close(null, false, errorResult); |
| | | throw ioe; |
| | | } finally { |
| | | asn1Reader.disposeBytesRead(); |
| | | } |
| | | |
| | | void registerConnection(final Connection<?> connection, |
| | | final LDAPConnection ldapConnection) |
| | | { |
| | | TimeoutChecker.INSTANCE.addConnection(ldapConnection); |
| | | LDAP_CONNECTION_ATTR.set(connection, ldapConnection); |
| | | } |
| | | return ctx.getStopAction(); |
| | | } |
| | | |
| | | void registerConnection(final Connection<?> connection, final LDAPConnection ldapConnection) { |
| | | TimeoutChecker.INSTANCE.addConnection(ldapConnection); |
| | | LDAP_CONNECTION_ATTR.set(connection, ldapConnection); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Compare result future implementation. |
| | | */ |
| | | final class LDAPCompareFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<CompareResult> |
| | | { |
| | | private final CompareRequest request; |
| | | final class LDAPCompareFutureResultImpl extends AbstractLDAPFutureResultImpl<CompareResult> { |
| | | private final CompareRequest request; |
| | | |
| | | LDAPCompareFutureResultImpl(final int requestID, final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPCompareFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | LDAPCompareFutureResultImpl(final int requestID, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | CompareRequest getRequest() { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPCompareFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | CompareRequest getRequest() |
| | | { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | CompareResult newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newCompareResult(resultCode).setDiagnosticMessage( |
| | | diagnosticMessage).setCause(cause); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | CompareResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return Responses.newCompareResult(resultCode).setDiagnosticMessage(diagnosticMessage) |
| | | .setCause(cause); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldap.AbstractAsynchronousConnection; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ConnectionEventListener; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.FutureResult; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.LDAPOptions; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.BindClient; |
| | | import org.forgerock.opendj.ldap.requests.BindRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.glassfish.grizzly.CompletionHandler; |
| | | import org.glassfish.grizzly.filterchain.Filter; |
| | | import org.glassfish.grizzly.filterchain.FilterChain; |
| | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * LDAP connection implementation. |
| | | * <p> |
| | | * TODO: handle illegal state exceptions. |
| | | */ |
| | | final class LDAPConnection extends AbstractAsynchronousConnection implements |
| | | Connection |
| | | { |
| | | private final org.glassfish.grizzly.Connection<?> connection; |
| | | private Result connectionInvalidReason; |
| | | private boolean isClosed = false; |
| | | private final List<ConnectionEventListener> listeners = |
| | | new CopyOnWriteArrayList<ConnectionEventListener>(); |
| | | private final AtomicInteger nextMsgID = new AtomicInteger(1); |
| | | private final AtomicBoolean bindOrStartTLSInProgress = new AtomicBoolean( |
| | | false); |
| | | private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests = |
| | | new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>(); |
| | | private final Object stateLock = new Object(); |
| | | private final LDAPWriter ldapWriter = new LDAPWriter(); |
| | | private final LDAPOptions options; |
| | | final class LDAPConnection extends AbstractAsynchronousConnection implements Connection { |
| | | private final org.glassfish.grizzly.Connection<?> connection; |
| | | private Result connectionInvalidReason; |
| | | private boolean isClosed = false; |
| | | private final List<ConnectionEventListener> listeners = |
| | | new CopyOnWriteArrayList<ConnectionEventListener>(); |
| | | private final AtomicInteger nextMsgID = new AtomicInteger(1); |
| | | private final AtomicBoolean bindOrStartTLSInProgress = new AtomicBoolean(false); |
| | | private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests = |
| | | new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>(); |
| | | private final Object stateLock = new Object(); |
| | | private final LDAPWriter ldapWriter = new LDAPWriter(); |
| | | private final LDAPOptions options; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDAP connection. |
| | | * |
| | | * @param connection |
| | | * The Grizzly connection. |
| | | * @param options |
| | | * The LDAP client options. |
| | | */ |
| | | LDAPConnection(final org.glassfish.grizzly.Connection<?> connection, |
| | | final LDAPOptions options) |
| | | { |
| | | this.connection = connection; |
| | | this.options = options; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Void> abandonAsync(final AbandonRequest request) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest; |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | return new CompletedFutureResult<Void>( |
| | | newErrorResult(connectionInvalidReason), messageID); |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress"); |
| | | return new CompletedFutureResult<Void>(newErrorResult(errorResult), |
| | | messageID); |
| | | } |
| | | |
| | | // First remove the future associated with the request to be abandoned. |
| | | pendingRequest = pendingRequests.remove(request.getRequestID()); |
| | | /** |
| | | * Creates a new LDAP connection. |
| | | * |
| | | * @param connection |
| | | * The Grizzly connection. |
| | | * @param options |
| | | * The LDAP client options. |
| | | */ |
| | | LDAPConnection(final org.glassfish.grizzly.Connection<?> connection, final LDAPOptions options) { |
| | | this.connection = connection; |
| | | this.options = options; |
| | | } |
| | | |
| | | if (pendingRequest == null) |
| | | { |
| | | // There has never been a request with the specified message ID or the |
| | | // response has already been received and handled. We can ignore this |
| | | // abandon request. |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Void> abandonAsync(final AbandonRequest request) { |
| | | final AbstractLDAPFutureResultImpl<?> pendingRequest; |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | |
| | | // Message ID will be -1 since no request was sent. |
| | | return new CompletedFutureResult<Void>((Void) null); |
| | | } |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | return new CompletedFutureResult<Void>(newErrorResult(connectionInvalidReason), |
| | | messageID); |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress"); |
| | | return new CompletedFutureResult<Void>(newErrorResult(errorResult), messageID); |
| | | } |
| | | |
| | | pendingRequest.cancel(false); |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.abandonRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | return new CompletedFutureResult<Void>((Void) null, messageID); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | return new CompletedFutureResult<Void>(newErrorResult(errorResult), |
| | | messageID); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> addAsync(final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses |
| | | .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.addRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.add(listener); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<BindResult> bindAsync(final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | |
| | | BindClient context; |
| | | try |
| | | { |
| | | context = request |
| | | .createBindClient(connection.getPeerAddress() instanceof InetSocketAddress ? |
| | | ((InetSocketAddress) connection.getPeerAddress()).getHostName() |
| | | : connection.getPeerAddress().toString()); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred while creating a bind context").setCause(e); |
| | | final ErrorResultException error = ErrorResultException |
| | | .newErrorResult(errorResult); |
| | | if (resultHandler != null) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | return new CompletedFutureResult<BindResult>(error, messageID); |
| | | } |
| | | |
| | | final LDAPBindFutureResultImpl future = new LDAPBindFutureResultImpl( |
| | | messageID, context, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (!pendingRequests.isEmpty()) |
| | | { |
| | | future.setResultOrError(Responses.newBindResult( |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "There are other operations pending on this connection")); |
| | | return future; |
| | | } |
| | | |
| | | if (!bindOrStartTLSInProgress.compareAndSet(false, true)) |
| | | { |
| | | future.setResultOrError(Responses.newBindResult( |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | // Use the bind client to get the initial request instead of using the |
| | | // bind request passed to this method. |
| | | final GenericBindRequest initialRequest = context.nextBindRequest(); |
| | | ldapWriter.bindRequest(asn1Writer, messageID, 3, initialRequest); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | bindOrStartTLSInProgress.set(false); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void close(final UnbindRequest request, final String reason) |
| | | { |
| | | // FIXME: I18N need to internationalize this message. |
| | | Validator.ensureNotNull(request); |
| | | |
| | | close( |
| | | request, |
| | | false, |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setDiagnosticMessage( |
| | | "Connection closed by client" |
| | | + (reason != null ? ": " + reason : ""))); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<CompareResult> compareAsync(final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl( |
| | | messageID, request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses.newCompareResult( |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.compareRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> deleteAsync(final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses |
| | | .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.deleteRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync( |
| | | final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>( |
| | | messageID, request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | if (!pendingRequests.isEmpty()) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "There are pending operations on this connection")); |
| | | return future; |
| | | // First remove the future associated with the request to be |
| | | // abandoned. |
| | | pendingRequest = pendingRequests.remove(request.getRequestID()); |
| | | } |
| | | if (isTLSEnabled()) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "This connection is already TLS enabled")); |
| | | return future; |
| | | |
| | | if (pendingRequest == null) { |
| | | // There has never been a request with the specified message ID or |
| | | // the |
| | | // response has already been received and handled. We can ignore |
| | | // this |
| | | // abandon request. |
| | | |
| | | // Message ID will be -1 since no request was sent. |
| | | return new CompletedFutureResult<Void>((Void) null); |
| | | } |
| | | if (!bindOrStartTLSInProgress.compareAndSet(false, true)) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | |
| | | pendingRequest.cancel(false); |
| | | |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.abandonRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | return new CompletedFutureResult<Void>((Void) null, messageID); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | return new CompletedFutureResult<Void>(newErrorResult(errorResult), messageID); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> addAsync(final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.extendedRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | bindOrStartTLSInProgress.set(false); |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.addRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isClosed() |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | return isClosed; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isValid() |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | return connectionInvalidReason == null && !isClosed; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> modifyAsync(final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses |
| | | .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.modifyRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.add(listener); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<BindResult> bindAsync(final BindRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super BindResult> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = new LDAPFutureResultImpl(messageID, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses |
| | | .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.modifyDNRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void removeConnectionEventListener( |
| | | final ConnectionEventListener listener) |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.remove(listener); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> searchAsync(final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) |
| | | { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl( |
| | | messageID, request, resultHandler, intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | | future.setResultOrError(Responses |
| | | .newResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.searchRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnection("); |
| | | builder.append(connection.getLocalAddress()); |
| | | builder.append(','); |
| | | builder.append(connection.getPeerAddress()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | int continuePendingBindRequest(final LDAPBindFutureResultImpl future) |
| | | throws ErrorResultException |
| | | { |
| | | final int newMsgID = nextMsgID.getAndIncrement(); |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | throw newErrorResult(connectionInvalidReason); |
| | | } |
| | | pendingRequests.put(newMsgID, future); |
| | | } |
| | | return newMsgID; |
| | | } |
| | | |
| | | |
| | | |
| | | long cancelExpiredRequests(final long currentTime) |
| | | { |
| | | final long timeout = options.getTimeout(TimeUnit.MILLISECONDS); |
| | | long delay = timeout; |
| | | if (timeout > 0) |
| | | { |
| | | for (int requestID : pendingRequests.keySet()) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests |
| | | .get(requestID); |
| | | if (future != null) |
| | | { |
| | | final long diff = (future.getTimestamp() + timeout) - currentTime; |
| | | if (diff <= 0 && pendingRequests.remove(requestID) != null) |
| | | { |
| | | StaticUtils.DEBUG_LOG.fine("Cancelling expired future result: " |
| | | + future); |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_TIMEOUT); |
| | | future.adaptErrorResult(result); |
| | | |
| | | abandonAsync(Requests.newAbandonRequest(future.getRequestID())); |
| | | } |
| | | else |
| | | { |
| | | delay = Math.min(delay, diff); |
| | | } |
| | | BindClient context; |
| | | try { |
| | | context = |
| | | request.createBindClient( |
| | | connection.getPeerAddress() instanceof InetSocketAddress |
| | | ? ((InetSocketAddress) connection.getPeerAddress()).getHostName() |
| | | : connection.getPeerAddress().toString()); |
| | | } catch (final Exception e) { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred while creating a bind context").setCause(e); |
| | | final ErrorResultException error = ErrorResultException.newErrorResult(errorResult); |
| | | if (resultHandler != null) { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | return new CompletedFutureResult<BindResult>(error, messageID); |
| | | } |
| | | } |
| | | } |
| | | return delay; |
| | | } |
| | | |
| | | final LDAPBindFutureResultImpl future = |
| | | new LDAPBindFutureResultImpl(messageID, context, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (!pendingRequests.isEmpty()) { |
| | | future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage( |
| | | "There are other operations pending on this connection")); |
| | | return future; |
| | | } |
| | | |
| | | void close(final UnbindRequest unbindRequest, |
| | | final boolean isDisconnectNotification, final Result reason) |
| | | { |
| | | boolean notifyClose = false; |
| | | boolean notifyErrorOccurred = false; |
| | | if (!bindOrStartTLSInProgress.compareAndSet(false, true)) { |
| | | future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (isClosed) |
| | | { |
| | | // Already closed. |
| | | return; |
| | | } |
| | | |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | // Already closed. |
| | | isClosed = true; |
| | | return; |
| | | } |
| | | |
| | | if (unbindRequest != null) |
| | | { |
| | | // User closed. |
| | | isClosed = true; |
| | | notifyClose = true; |
| | | } |
| | | else |
| | | { |
| | | notifyErrorOccurred = true; |
| | | } |
| | | |
| | | // Mark the connection as invalid. |
| | | if (!isDisconnectNotification) |
| | | { |
| | | // Connection termination was detected locally, so use the provided |
| | | // reason for all subsequent requests. |
| | | connectionInvalidReason = reason; |
| | | } |
| | | else |
| | | { |
| | | // Connection termination was triggered remotely. We don't want to |
| | | // blindly pass on the result code to requests since it could be |
| | | // confused for a genuine response. For example, if the disconnect |
| | | // contained the invalidCredentials result code then this could be |
| | | // misinterpreted as a genuine authentication failure for subsequent |
| | | // bind requests. |
| | | connectionInvalidReason = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_SERVER_DOWN).setDiagnosticMessage( |
| | | "Connection closed by server"); |
| | | } |
| | | } |
| | | |
| | | // First abort all outstanding requests. |
| | | for (int requestID : pendingRequests.keySet()) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests |
| | | .remove(requestID); |
| | | if (future != null) |
| | | { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | } |
| | | } |
| | | |
| | | // Now try cleanly closing the connection if possible. |
| | | // Only send unbind if specified. |
| | | if (unbindRequest != null && !isDisconnectNotification) |
| | | { |
| | | try |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | ldapWriter.unbindRequest(asn1Writer, nextMsgID.getAndIncrement(), |
| | | unbindRequest); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | // Use the bind client to get the initial request instead of |
| | | // using the |
| | | // bind request passed to this method. |
| | | final GenericBindRequest initialRequest = context.nextBindRequest(); |
| | | ldapWriter.bindRequest(asn1Writer, messageID, 3, initialRequest); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | bindOrStartTLSInProgress.set(false); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | // Underlying channel prob blown up. Just ignore. |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | try |
| | | { |
| | | connection.close(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | // Ignore. |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void close(final UnbindRequest request, final String reason) { |
| | | // FIXME: I18N need to internationalize this message. |
| | | Validator.ensureNotNull(request); |
| | | |
| | | close(request, false, Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setDiagnosticMessage( |
| | | "Connection closed by client" + (reason != null ? ": " + reason : ""))); |
| | | } |
| | | |
| | | // Notify listeners. |
| | | if (notifyClose) |
| | | { |
| | | for (final ConnectionEventListener listener : listeners) |
| | | { |
| | | listener.handleConnectionClosed(); |
| | | } |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<CompareResult> compareAsync(final CompareRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super CompareResult> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPCompareFutureResultImpl future = |
| | | new LDAPCompareFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | if (notifyErrorOccurred) |
| | | { |
| | | for (final ConnectionEventListener listener : listeners) |
| | | { |
| | | // Use the reason provided in the disconnect notification. |
| | | listener.handleConnectionError(isDisconnectNotification, |
| | | newErrorResult(reason)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | LDAPOptions getLDAPOptions() |
| | | { |
| | | return options; |
| | | } |
| | | |
| | | |
| | | |
| | | AbstractLDAPFutureResultImpl<?> getPendingRequest(final Integer messageID) |
| | | { |
| | | return pendingRequests.get(messageID); |
| | | } |
| | | |
| | | |
| | | |
| | | void handleUnsolicitedNotification(final ExtendedResult result) |
| | | { |
| | | if (isClosed()) |
| | | { |
| | | // Don't notify after connection is closed. |
| | | return; |
| | | } |
| | | |
| | | for (final ConnectionEventListener listener : listeners) |
| | | { |
| | | listener.handleUnsolicitedNotification(result); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Installs a new Grizzly filter (e.g. SSL/SASL) beneath the top-level LDAP |
| | | * filter. |
| | | * |
| | | * @param filter |
| | | * The filter to be installed. |
| | | */ |
| | | void installFilter(final Filter filter) |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | // Determine the index where the filter should be added. |
| | | FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); |
| | | int filterIndex = oldFilterChain.size() - 1; |
| | | if (filter instanceof SSLFilter) |
| | | { |
| | | // Beneath any ConnectionSecurityLayerFilters if present, otherwise |
| | | // beneath the LDAP filter. |
| | | for (int i = oldFilterChain.size() - 2; i >= 0; i--) |
| | | { |
| | | if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) |
| | | { |
| | | filterIndex = i + 1; |
| | | break; |
| | | } |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newCompareResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | } |
| | | |
| | | // Create the new filter chain. |
| | | FilterChain newFilterChain = FilterChainBuilder.stateless() |
| | | .addAll(oldFilterChain) |
| | | .add(filterIndex, filter) |
| | | .build(); |
| | | connection.setProcessor(newFilterChain); |
| | | } |
| | | } |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.compareRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether or not TLS is enabled on this connection. |
| | | * |
| | | * @return {@code true} if TLS is enabled on this connection, otherwise |
| | | * {@code false}. |
| | | */ |
| | | boolean isTLSEnabled() |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | final FilterChain currentFilterChain = (FilterChain) connection |
| | | .getProcessor(); |
| | | for (Filter filter : currentFilterChain) |
| | | { |
| | | if (filter instanceof SSLFilter) |
| | | { |
| | | return true; |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | } |
| | | return false; |
| | | |
| | | return future; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> deleteAsync(final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | AbstractLDAPFutureResultImpl<?> removePendingRequest(final Integer messageID) |
| | | { |
| | | return pendingRequests.remove(messageID); |
| | | } |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.deleteRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | |
| | | void setBindOrStartTLSInProgress(final boolean state) |
| | | { |
| | | bindOrStartTLSInProgress.set(state); |
| | | } |
| | | |
| | | |
| | | |
| | | void startTLS(final SSLContext sslContext, |
| | | final List<String> protocols, final List<String> cipherSuites, |
| | | final CompletionHandler<SSLEngine> completionHandler) throws IOException |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | if (isTLSEnabled()) |
| | | { |
| | | throw new IllegalStateException("TLS already enabled"); |
| | | } |
| | | |
| | | SSLEngineConfigurator sslEngineConfigurator = new SSLEngineConfigurator( |
| | | sslContext, true, false, false); |
| | | sslEngineConfigurator.setEnabledProtocols(protocols.isEmpty() ? null |
| | | : protocols.toArray(new String[protocols.size()])); |
| | | sslEngineConfigurator |
| | | .setEnabledCipherSuites(cipherSuites.isEmpty() ? null : cipherSuites |
| | | .toArray(new String[cipherSuites.size()])); |
| | | SSLFilter sslFilter = new SSLFilter(null, sslEngineConfigurator); |
| | | installFilter(sslFilter); |
| | | sslFilter.handshake(connection, completionHandler); |
| | | return future; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync( |
| | | final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super R> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPExtendedFutureResultImpl<R> future = |
| | | new LDAPExtendedFutureResultImpl<R>(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (request.getOID().equals(StartTLSExtendedRequest.OID)) { |
| | | if (!pendingRequests.isEmpty()) { |
| | | future.setResultOrError(request.getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.OPERATIONS_ERROR, "", |
| | | "There are pending operations on this connection")); |
| | | return future; |
| | | } |
| | | if (isTLSEnabled()) { |
| | | future.setResultOrError(request.getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.OPERATIONS_ERROR, "", |
| | | "This connection is already TLS enabled")); |
| | | return future; |
| | | } |
| | | if (!bindOrStartTLSInProgress.compareAndSet(false, true)) { |
| | | future.setResultOrError(request.getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.OPERATIONS_ERROR, "", |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | } else { |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(request.getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.OPERATIONS_ERROR, "", |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | private void connectionErrorOccurred(final Result reason) |
| | | { |
| | | close(null, false, reason); |
| | | } |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.extendedRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | bindOrStartTLSInProgress.set(false); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isClosed() { |
| | | synchronized (stateLock) { |
| | | return isClosed; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isValid() { |
| | | synchronized (stateLock) { |
| | | return connectionInvalidReason == null && !isClosed; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> modifyAsync(final ModifyRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.modifyRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<? super Result> resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPFutureResultImpl future = |
| | | new LDAPFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.modifyDNRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void removeConnectionEventListener(final ConnectionEventListener listener) { |
| | | Validator.ensureNotNull(listener); |
| | | listeners.remove(listener); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> searchAsync(final SearchRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final SearchResultHandler resultHandler) { |
| | | final int messageID = nextMsgID.getAndIncrement(); |
| | | final LDAPSearchFutureResultImpl future = |
| | | new LDAPSearchFutureResultImpl(messageID, request, resultHandler, |
| | | intermediateResponseHandler, this); |
| | | |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | return future; |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) { |
| | | future.setResultOrError(Responses.newResult(ResultCode.OPERATIONS_ERROR) |
| | | .setDiagnosticMessage("Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | | pendingRequests.put(messageID, future); |
| | | } |
| | | |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter.searchRequest(asn1Writer, messageID, request); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | pendingRequests.remove(messageID); |
| | | |
| | | // FIXME: what other sort of IOExceptions can be thrown? |
| | | // FIXME: Is this the best result code? |
| | | final Result errorResult = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | future.adaptErrorResult(errorResult); |
| | | } |
| | | |
| | | return future; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnection("); |
| | | builder.append(connection.getLocalAddress()); |
| | | builder.append(','); |
| | | builder.append(connection.getPeerAddress()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | int continuePendingBindRequest(final LDAPBindFutureResultImpl future) |
| | | throws ErrorResultException { |
| | | final int newMsgID = nextMsgID.getAndIncrement(); |
| | | synchronized (stateLock) { |
| | | if (connectionInvalidReason != null) { |
| | | throw newErrorResult(connectionInvalidReason); |
| | | } |
| | | pendingRequests.put(newMsgID, future); |
| | | } |
| | | return newMsgID; |
| | | } |
| | | |
| | | long cancelExpiredRequests(final long currentTime) { |
| | | final long timeout = options.getTimeout(TimeUnit.MILLISECONDS); |
| | | long delay = timeout; |
| | | if (timeout > 0) { |
| | | for (int requestID : pendingRequests.keySet()) { |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests.get(requestID); |
| | | if (future != null) { |
| | | final long diff = (future.getTimestamp() + timeout) - currentTime; |
| | | if (diff <= 0 && pendingRequests.remove(requestID) != null) { |
| | | StaticUtils.DEBUG_LOG.fine("Cancelling expired future result: " + future); |
| | | final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT); |
| | | future.adaptErrorResult(result); |
| | | |
| | | abandonAsync(Requests.newAbandonRequest(future.getRequestID())); |
| | | } else { |
| | | delay = Math.min(delay, diff); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return delay; |
| | | } |
| | | |
| | | void close(final UnbindRequest unbindRequest, final boolean isDisconnectNotification, |
| | | final Result reason) { |
| | | boolean notifyClose = false; |
| | | boolean notifyErrorOccurred = false; |
| | | |
| | | synchronized (stateLock) { |
| | | if (isClosed) { |
| | | // Already closed. |
| | | return; |
| | | } |
| | | |
| | | if (connectionInvalidReason != null) { |
| | | // Already closed. |
| | | isClosed = true; |
| | | return; |
| | | } |
| | | |
| | | if (unbindRequest != null) { |
| | | // User closed. |
| | | isClosed = true; |
| | | notifyClose = true; |
| | | } else { |
| | | notifyErrorOccurred = true; |
| | | } |
| | | |
| | | // Mark the connection as invalid. |
| | | if (!isDisconnectNotification) { |
| | | // Connection termination was detected locally, so use the |
| | | // provided |
| | | // reason for all subsequent requests. |
| | | connectionInvalidReason = reason; |
| | | } else { |
| | | // Connection termination was triggered remotely. We don't want |
| | | // to |
| | | // blindly pass on the result code to requests since it could be |
| | | // confused for a genuine response. For example, if the |
| | | // disconnect |
| | | // contained the invalidCredentials result code then this could |
| | | // be |
| | | // misinterpreted as a genuine authentication failure for |
| | | // subsequent |
| | | // bind requests. |
| | | connectionInvalidReason = |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_SERVER_DOWN) |
| | | .setDiagnosticMessage("Connection closed by server"); |
| | | } |
| | | } |
| | | |
| | | // First abort all outstanding requests. |
| | | for (int requestID : pendingRequests.keySet()) { |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests.remove(requestID); |
| | | if (future != null) { |
| | | future.adaptErrorResult(connectionInvalidReason); |
| | | } |
| | | } |
| | | |
| | | // Now try cleanly closing the connection if possible. |
| | | // Only send unbind if specified. |
| | | if (unbindRequest != null && !isDisconnectNotification) { |
| | | try { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | ldapWriter |
| | | .unbindRequest(asn1Writer, nextMsgID.getAndIncrement(), unbindRequest); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } catch (final IOException e) { |
| | | // Underlying channel prob blown up. Just ignore. |
| | | } |
| | | } |
| | | |
| | | try { |
| | | connection.close(); |
| | | } catch (final IOException e) { |
| | | // Ignore. |
| | | } |
| | | |
| | | // Notify listeners. |
| | | if (notifyClose) { |
| | | for (final ConnectionEventListener listener : listeners) { |
| | | listener.handleConnectionClosed(); |
| | | } |
| | | } |
| | | |
| | | if (notifyErrorOccurred) { |
| | | for (final ConnectionEventListener listener : listeners) { |
| | | // Use the reason provided in the disconnect notification. |
| | | listener.handleConnectionError(isDisconnectNotification, newErrorResult(reason)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | LDAPOptions getLDAPOptions() { |
| | | return options; |
| | | } |
| | | |
| | | AbstractLDAPFutureResultImpl<?> getPendingRequest(final Integer messageID) { |
| | | return pendingRequests.get(messageID); |
| | | } |
| | | |
| | | void handleUnsolicitedNotification(final ExtendedResult result) { |
| | | if (isClosed()) { |
| | | // Don't notify after connection is closed. |
| | | return; |
| | | } |
| | | |
| | | for (final ConnectionEventListener listener : listeners) { |
| | | listener.handleUnsolicitedNotification(result); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Installs a new Grizzly filter (e.g. SSL/SASL) beneath the top-level LDAP |
| | | * filter. |
| | | * |
| | | * @param filter |
| | | * The filter to be installed. |
| | | */ |
| | | void installFilter(final Filter filter) { |
| | | synchronized (stateLock) { |
| | | // Determine the index where the filter should be added. |
| | | FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); |
| | | int filterIndex = oldFilterChain.size() - 1; |
| | | if (filter instanceof SSLFilter) { |
| | | // Beneath any ConnectionSecurityLayerFilters if present, |
| | | // otherwise |
| | | // beneath the LDAP filter. |
| | | for (int i = oldFilterChain.size() - 2; i >= 0; i--) { |
| | | if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) { |
| | | filterIndex = i + 1; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Create the new filter chain. |
| | | FilterChain newFilterChain = |
| | | FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter) |
| | | .build(); |
| | | connection.setProcessor(newFilterChain); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether or not TLS is enabled on this connection. |
| | | * |
| | | * @return {@code true} if TLS is enabled on this connection, otherwise |
| | | * {@code false}. |
| | | */ |
| | | boolean isTLSEnabled() { |
| | | synchronized (stateLock) { |
| | | final FilterChain currentFilterChain = (FilterChain) connection.getProcessor(); |
| | | for (Filter filter : currentFilterChain) { |
| | | if (filter instanceof SSLFilter) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | AbstractLDAPFutureResultImpl<?> removePendingRequest(final Integer messageID) { |
| | | return pendingRequests.remove(messageID); |
| | | } |
| | | |
| | | void setBindOrStartTLSInProgress(final boolean state) { |
| | | bindOrStartTLSInProgress.set(state); |
| | | } |
| | | |
| | | void startTLS(final SSLContext sslContext, final List<String> protocols, |
| | | final List<String> cipherSuites, final CompletionHandler<SSLEngine> completionHandler) |
| | | throws IOException { |
| | | synchronized (stateLock) { |
| | | if (isTLSEnabled()) { |
| | | throw new IllegalStateException("TLS already enabled"); |
| | | } |
| | | |
| | | SSLEngineConfigurator sslEngineConfigurator = |
| | | new SSLEngineConfigurator(sslContext, true, false, false); |
| | | sslEngineConfigurator.setEnabledProtocols(protocols.isEmpty() ? null : protocols |
| | | .toArray(new String[protocols.size()])); |
| | | sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ? null |
| | | : cipherSuites.toArray(new String[cipherSuites.size()])); |
| | | SSLFilter sslFilter = new SSLFilter(null, sslEngineConfigurator); |
| | | installFilter(sslFilter); |
| | | sslFilter.handshake(connection, completionHandler); |
| | | } |
| | | } |
| | | |
| | | private void connectionErrorOccurred(final Result reason) { |
| | | close(null, false, reason); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | |
| | | |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.ConnectionFactory; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.FutureResult; |
| | | import org.forgerock.opendj.ldap.LDAPOptions; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | |
| | | import com.forgerock.opendj.util.FutureResultTransformer; |
| | | import com.forgerock.opendj.util.RecursiveFutureResult; |
| | | |
| | | |
| | | |
| | | /** |
| | | * LDAP connection factory implementation. |
| | | */ |
| | | public final class LDAPConnectionFactoryImpl implements ConnectionFactory |
| | | { |
| | | public final class LDAPConnectionFactoryImpl implements ConnectionFactory { |
| | | |
| | | @SuppressWarnings("rawtypes") |
| | | private final class ConnectionCompletionHandler implements |
| | | CompletionHandler<org.glassfish.grizzly.Connection> |
| | | { |
| | | private final FutureResultTransformer<Result, Connection> startTLSFutureResult; |
| | | private final RecursiveFutureResult<LDAPConnection, ExtendedResult> connectionFutureResult; |
| | | private LDAPConnection connection; |
| | | @SuppressWarnings("rawtypes") |
| | | private final class ConnectionCompletionHandler implements |
| | | CompletionHandler<org.glassfish.grizzly.Connection> { |
| | | private final FutureResultTransformer<Result, Connection> startTLSFutureResult; |
| | | private final RecursiveFutureResult<LDAPConnection, ExtendedResult> connectionFutureResult; |
| | | private LDAPConnection connection; |
| | | |
| | | private ConnectionCompletionHandler(final ResultHandler<? super Connection> handler) { |
| | | this.startTLSFutureResult = new FutureResultTransformer<Result, Connection>(handler) { |
| | | |
| | | |
| | | private ConnectionCompletionHandler(final ResultHandler<? super Connection> handler) |
| | | { |
| | | this.startTLSFutureResult = new FutureResultTransformer<Result, Connection>( |
| | | handler) |
| | | { |
| | | |
| | | @Override |
| | | protected ErrorResultException transformErrorResult( |
| | | final ErrorResultException errorResult) |
| | | { |
| | | // Ensure that the connection is closed. |
| | | try |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Ignore. |
| | | } |
| | | return errorResult; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | protected LDAPConnection transformResult(final Result result) |
| | | throws ErrorResultException |
| | | { |
| | | return connection; |
| | | } |
| | | |
| | | }; |
| | | |
| | | this.connectionFutureResult = new RecursiveFutureResult<LDAPConnection, ExtendedResult>( |
| | | startTLSFutureResult) |
| | | { |
| | | |
| | | @Override |
| | | protected FutureResult<? extends ExtendedResult> chainResult( |
| | | final LDAPConnection innerResult, |
| | | final ResultHandler<? super ExtendedResult> handler) |
| | | throws ErrorResultException |
| | | { |
| | | connection = innerResult; |
| | | |
| | | if (options.getSSLContext() != null && options.useStartTLS()) |
| | | { |
| | | // Chain StartTLS extended request. |
| | | final StartTLSExtendedRequest startTLS = Requests |
| | | .newStartTLSExtendedRequest(options.getSSLContext()); |
| | | startTLS.addEnabledCipherSuite(options.getEnabledCipherSuites() |
| | | .toArray(new String[options.getEnabledCipherSuites().size()])); |
| | | startTLS.addEnabledProtocol(options.getEnabledProtocols().toArray( |
| | | new String[options.getEnabledProtocols().size()])); |
| | | return connection.extendedRequestAsync(startTLS, null, handler); |
| | | } |
| | | else if (options.getSSLContext() != null) |
| | | { |
| | | // Install SSL/TLS layer. |
| | | try |
| | | { |
| | | connection.startTLS(options.getSSLContext(), |
| | | options.getEnabledProtocols(), |
| | | options.getEnabledCipherSuites(), |
| | | new EmptyCompletionHandler<SSLEngine>() |
| | | { |
| | | @Override |
| | | public void completed(final SSLEngine result) |
| | | { |
| | | handler.handleResult(null); |
| | | @Override |
| | | protected ErrorResultException transformErrorResult( |
| | | final ErrorResultException errorResult) { |
| | | // Ensure that the connection is closed. |
| | | try { |
| | | if (connection != null) { |
| | | connection.close(); |
| | | } |
| | | } catch (final Exception e) { |
| | | // Ignore. |
| | | } |
| | | return errorResult; |
| | | } |
| | | |
| | | @Override |
| | | protected LDAPConnection transformResult(final Result result) |
| | | throws ErrorResultException { |
| | | return connection; |
| | | } |
| | | |
| | | }; |
| | | |
| | | @Override |
| | | public void failed(final Throwable throwable) |
| | | { |
| | | handler.handleErrorResult(newErrorResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | throwable.getMessage(), throwable)); |
| | | } |
| | | }); |
| | | return null; |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | ioe.getMessage(), ioe); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // Plain connection. |
| | | handler.handleResult(null); |
| | | return new CompletedFutureResult<ExtendedResult>( |
| | | (ExtendedResult) null); |
| | | } |
| | | this.connectionFutureResult = |
| | | new RecursiveFutureResult<LDAPConnection, ExtendedResult>(startTLSFutureResult) { |
| | | |
| | | @Override |
| | | protected FutureResult<? extends ExtendedResult> chainResult( |
| | | final LDAPConnection innerResult, |
| | | final ResultHandler<? super ExtendedResult> handler) |
| | | throws ErrorResultException { |
| | | connection = innerResult; |
| | | |
| | | if (options.getSSLContext() != null && options.useStartTLS()) { |
| | | // Chain StartTLS extended request. |
| | | final StartTLSExtendedRequest startTLS = |
| | | Requests.newStartTLSExtendedRequest(options.getSSLContext()); |
| | | startTLS.addEnabledCipherSuite(options |
| | | .getEnabledCipherSuites() |
| | | .toArray( |
| | | new String[options.getEnabledCipherSuites().size()])); |
| | | startTLS.addEnabledProtocol(options.getEnabledProtocols().toArray( |
| | | new String[options.getEnabledProtocols().size()])); |
| | | return connection.extendedRequestAsync(startTLS, null, handler); |
| | | } else if (options.getSSLContext() != null) { |
| | | // Install SSL/TLS layer. |
| | | try { |
| | | connection.startTLS(options.getSSLContext(), options |
| | | .getEnabledProtocols(), options |
| | | .getEnabledCipherSuites(), |
| | | new EmptyCompletionHandler<SSLEngine>() { |
| | | @Override |
| | | public void completed(final SSLEngine result) { |
| | | handler.handleResult(null); |
| | | } |
| | | |
| | | @Override |
| | | public void failed(final Throwable throwable) { |
| | | handler.handleErrorResult(newErrorResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | throwable.getMessage(), throwable)); |
| | | } |
| | | }); |
| | | return null; |
| | | } catch (final IOException ioe) { |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, ioe |
| | | .getMessage(), ioe); |
| | | } |
| | | } else { |
| | | // Plain connection. |
| | | handler.handleResult(null); |
| | | return new CompletedFutureResult<ExtendedResult>( |
| | | (ExtendedResult) null); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | |
| | | startTLSFutureResult.setFutureResult(connectionFutureResult); |
| | | } |
| | | |
| | | }; |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void cancelled() { |
| | | // Ignore this. |
| | | } |
| | | |
| | | startTLSFutureResult.setFutureResult(connectionFutureResult); |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void completed(final org.glassfish.grizzly.Connection connection) { |
| | | connectionFutureResult.handleResult(adaptConnection(connection)); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void failed(final Throwable throwable) { |
| | | connectionFutureResult.handleErrorResult(adaptConnectionException(throwable)); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void updated(final org.glassfish.grizzly.Connection connection) { |
| | | // Ignore this. |
| | | } |
| | | |
| | | } |
| | | |
| | | private final SocketAddress socketAddress; |
| | | private final TCPNIOTransport transport; |
| | | private final FilterChain defaultFilterChain; |
| | | private final LDAPClientFilter clientFilter; |
| | | private final LDAPOptions options; |
| | | |
| | | /** |
| | | * Creates a new LDAP connection factory implementation which can be used to |
| | | * create connections to the Directory Server at the provided host and port |
| | | * address using provided connection options. |
| | | * |
| | | * @param address |
| | | * The address of the Directory Server to connect to. |
| | | * @param options |
| | | * The LDAP connection options to use when creating connections. |
| | | */ |
| | | public LDAPConnectionFactoryImpl(final SocketAddress address, final LDAPOptions options) { |
| | | if (options.getTCPNIOTransport() == null) { |
| | | this.transport = DefaultTCPNIOTransport.getInstance(); |
| | | } else { |
| | | this.transport = options.getTCPNIOTransport(); |
| | | } |
| | | this.socketAddress = address; |
| | | this.options = new LDAPOptions(options); |
| | | this.clientFilter = |
| | | new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0); |
| | | this.defaultFilterChain = |
| | | FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void cancelled() |
| | | { |
| | | // Ignore this. |
| | | public Connection getConnection() throws ErrorResultException, InterruptedException { |
| | | return getConnectionAsync(null).get(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void completed(final org.glassfish.grizzly.Connection connection) |
| | | { |
| | | connectionFutureResult.handleResult(adaptConnection(connection)); |
| | | public FutureResult<Connection> getConnectionAsync( |
| | | final ResultHandler<? super Connection> handler) { |
| | | final ConnectionCompletionHandler ch = new ConnectionCompletionHandler(handler); |
| | | try { |
| | | ch.connectionFutureResult.setFutureResult(transport.connect(socketAddress, ch)); |
| | | return ch.startTLSFutureResult; |
| | | } catch (final IOException e) { |
| | | final ErrorResultException result = adaptConnectionException(e); |
| | | return new CompletedFutureResult<Connection>(result); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the address of the Directory Server. |
| | | * |
| | | * @return The address of the Directory Server. |
| | | */ |
| | | public SocketAddress getSocketAddress() { |
| | | return socketAddress; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void failed(final Throwable throwable) |
| | | { |
| | | connectionFutureResult |
| | | .handleErrorResult(adaptConnectionException(throwable)); |
| | | public String toString() { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnectionFactory("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | private LDAPConnection adaptConnection(final org.glassfish.grizzly.Connection<?> connection) { |
| | | // Test shows that its much faster with non block writes but risk |
| | | // running out of memory if the server is slow. |
| | | connection.configureBlocking(true); |
| | | connection.setProcessor(defaultFilterChain); |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void updated(final org.glassfish.grizzly.Connection connection) |
| | | { |
| | | // Ignore this. |
| | | final LDAPConnection ldapConnection = new LDAPConnection(connection, options); |
| | | clientFilter.registerConnection(connection, ldapConnection); |
| | | return ldapConnection; |
| | | } |
| | | |
| | | } |
| | | private ErrorResultException adaptConnectionException(Throwable t) { |
| | | if (t instanceof ExecutionException) { |
| | | t = t.getCause(); |
| | | } |
| | | |
| | | |
| | | |
| | | private final SocketAddress socketAddress; |
| | | private final TCPNIOTransport transport; |
| | | private final FilterChain defaultFilterChain; |
| | | private final LDAPClientFilter clientFilter; |
| | | private final LDAPOptions options; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDAP connection factory implementation which can be used to |
| | | * create connections to the Directory Server at the provided host and port |
| | | * address using provided connection options. |
| | | * |
| | | * @param address |
| | | * The address of the Directory Server to connect to. |
| | | * @param options |
| | | * The LDAP connection options to use when creating connections. |
| | | */ |
| | | public LDAPConnectionFactoryImpl(final SocketAddress address, |
| | | final LDAPOptions options) |
| | | { |
| | | if (options.getTCPNIOTransport() == null) |
| | | { |
| | | this.transport = DefaultTCPNIOTransport.getInstance(); |
| | | return newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, t.getMessage(), t); |
| | | } |
| | | else |
| | | { |
| | | this.transport = options.getTCPNIOTransport(); |
| | | } |
| | | this.socketAddress = address; |
| | | this.options = new LDAPOptions(options); |
| | | this.clientFilter = new LDAPClientFilter(new LDAPReader( |
| | | this.options.getDecodeOptions()), 0); |
| | | this.defaultFilterChain = FilterChainBuilder.stateless() |
| | | .add(new TransportFilter()) |
| | | .add(clientFilter) |
| | | .build(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Connection getConnection() throws ErrorResultException, |
| | | InterruptedException |
| | | { |
| | | return getConnectionAsync(null).get(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Connection> getConnectionAsync( |
| | | final ResultHandler<? super Connection> handler) |
| | | { |
| | | final ConnectionCompletionHandler ch = new ConnectionCompletionHandler(handler); |
| | | try |
| | | { |
| | | ch.connectionFutureResult.setFutureResult(transport.connect(socketAddress, ch)); |
| | | return ch.startTLSFutureResult; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | final ErrorResultException result = adaptConnectionException(e); |
| | | return new CompletedFutureResult<Connection>(result); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the address of the Directory Server. |
| | | * |
| | | * @return The address of the Directory Server. |
| | | */ |
| | | public SocketAddress getSocketAddress() |
| | | { |
| | | return socketAddress; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnectionFactory("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | private LDAPConnection adaptConnection( |
| | | final org.glassfish.grizzly.Connection<?> connection) |
| | | { |
| | | // Test shows that its much faster with non block writes but risk |
| | | // running out of memory if the server is slow. |
| | | connection.configureBlocking(true); |
| | | connection.setProcessor(defaultFilterChain); |
| | | |
| | | final LDAPConnection ldapConnection = new LDAPConnection(connection, |
| | | options); |
| | | clientFilter.registerConnection(connection, ldapConnection); |
| | | return ldapConnection; |
| | | } |
| | | |
| | | |
| | | |
| | | private ErrorResultException adaptConnectionException(Throwable t) |
| | | { |
| | | if (t instanceof ExecutionException) |
| | | { |
| | | t = t.getCause(); |
| | | } |
| | | |
| | | return newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, t.getMessage(), |
| | | t); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | */ |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class defines a number of constants used in the LDAP protocol. |
| | | */ |
| | | public final class LDAPConstants |
| | | { |
| | | public final class LDAPConstants { |
| | | |
| | | /** |
| | | * The protocol op type for bind requests. |
| | | */ |
| | | public static final byte OP_TYPE_BIND_REQUEST = 0x60; |
| | | /** |
| | | * The protocol op type for bind requests. |
| | | */ |
| | | public static final byte OP_TYPE_BIND_REQUEST = 0x60; |
| | | |
| | | /** |
| | | * The protocol op type for bind responses. |
| | | */ |
| | | public static final byte OP_TYPE_BIND_RESPONSE = 0x61; |
| | | /** |
| | | * The protocol op type for bind responses. |
| | | */ |
| | | public static final byte OP_TYPE_BIND_RESPONSE = 0x61; |
| | | |
| | | /** |
| | | * The protocol op type for unbind requests. |
| | | */ |
| | | public static final byte OP_TYPE_UNBIND_REQUEST = 0x42; |
| | | /** |
| | | * The protocol op type for unbind requests. |
| | | */ |
| | | public static final byte OP_TYPE_UNBIND_REQUEST = 0x42; |
| | | |
| | | /** |
| | | * The protocol op type for search requests. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_REQUEST = 0x63; |
| | | /** |
| | | * The protocol op type for search requests. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_REQUEST = 0x63; |
| | | |
| | | /** |
| | | * The protocol op type for search result entries. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_ENTRY = 0x64; |
| | | /** |
| | | * The protocol op type for search result entries. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_ENTRY = 0x64; |
| | | |
| | | /** |
| | | * The protocol op type for search result references. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_REFERENCE = 0x73; |
| | | /** |
| | | * The protocol op type for search result references. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_REFERENCE = 0x73; |
| | | |
| | | /** |
| | | * The protocol op type for search result done elements. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_DONE = 0x65; |
| | | /** |
| | | * The protocol op type for search result done elements. |
| | | */ |
| | | public static final byte OP_TYPE_SEARCH_RESULT_DONE = 0x65; |
| | | |
| | | /** |
| | | * The protocol op type for modify requests. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_REQUEST = 0x66; |
| | | /** |
| | | * The protocol op type for modify requests. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_REQUEST = 0x66; |
| | | |
| | | /** |
| | | * The protocol op type for modify responses. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_RESPONSE = 0x67; |
| | | /** |
| | | * The protocol op type for modify responses. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_RESPONSE = 0x67; |
| | | |
| | | /** |
| | | * The protocol op type for add requests. |
| | | */ |
| | | public static final byte OP_TYPE_ADD_REQUEST = 0x68; |
| | | /** |
| | | * The protocol op type for add requests. |
| | | */ |
| | | public static final byte OP_TYPE_ADD_REQUEST = 0x68; |
| | | |
| | | /** |
| | | * The protocol op type for add responses. |
| | | */ |
| | | public static final byte OP_TYPE_ADD_RESPONSE = 0x69; |
| | | /** |
| | | * The protocol op type for add responses. |
| | | */ |
| | | public static final byte OP_TYPE_ADD_RESPONSE = 0x69; |
| | | |
| | | /** |
| | | * The protocol op type for delete requests. |
| | | */ |
| | | public static final byte OP_TYPE_DELETE_REQUEST = 0x4A; |
| | | /** |
| | | * The protocol op type for delete requests. |
| | | */ |
| | | public static final byte OP_TYPE_DELETE_REQUEST = 0x4A; |
| | | |
| | | /** |
| | | * The protocol op type for delete responses. |
| | | */ |
| | | public static final byte OP_TYPE_DELETE_RESPONSE = 0x6B; |
| | | /** |
| | | * The protocol op type for delete responses. |
| | | */ |
| | | public static final byte OP_TYPE_DELETE_RESPONSE = 0x6B; |
| | | |
| | | /** |
| | | * The protocol op type for modify DN requests. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_DN_REQUEST = 0x6C; |
| | | /** |
| | | * The protocol op type for modify DN requests. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_DN_REQUEST = 0x6C; |
| | | |
| | | /** |
| | | * The protocol op type for modify DN responses. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_DN_RESPONSE = 0x6D; |
| | | /** |
| | | * The protocol op type for modify DN responses. |
| | | */ |
| | | public static final byte OP_TYPE_MODIFY_DN_RESPONSE = 0x6D; |
| | | |
| | | /** |
| | | * The protocol op type for compare requests. |
| | | */ |
| | | public static final byte OP_TYPE_COMPARE_REQUEST = 0x6E; |
| | | /** |
| | | * The protocol op type for compare requests. |
| | | */ |
| | | public static final byte OP_TYPE_COMPARE_REQUEST = 0x6E; |
| | | |
| | | /** |
| | | * The protocol op type for compare responses. |
| | | */ |
| | | public static final byte OP_TYPE_COMPARE_RESPONSE = 0x6F; |
| | | /** |
| | | * The protocol op type for compare responses. |
| | | */ |
| | | public static final byte OP_TYPE_COMPARE_RESPONSE = 0x6F; |
| | | |
| | | /** |
| | | * The protocol op type for abandon requests. |
| | | */ |
| | | public static final byte OP_TYPE_ABANDON_REQUEST = 0x50; |
| | | /** |
| | | * The protocol op type for abandon requests. |
| | | */ |
| | | public static final byte OP_TYPE_ABANDON_REQUEST = 0x50; |
| | | |
| | | /** |
| | | * The protocol op type for extended requests. |
| | | */ |
| | | public static final byte OP_TYPE_EXTENDED_REQUEST = 0x77; |
| | | /** |
| | | * The protocol op type for extended requests. |
| | | */ |
| | | public static final byte OP_TYPE_EXTENDED_REQUEST = 0x77; |
| | | |
| | | /** |
| | | * The protocol op type for extended responses. |
| | | */ |
| | | public static final byte OP_TYPE_EXTENDED_RESPONSE = 0x78; |
| | | /** |
| | | * The protocol op type for extended responses. |
| | | */ |
| | | public static final byte OP_TYPE_EXTENDED_RESPONSE = 0x78; |
| | | |
| | | /** |
| | | * The protocol op type for intermediate responses. |
| | | */ |
| | | public static final byte OP_TYPE_INTERMEDIATE_RESPONSE = 0x79; |
| | | /** |
| | | * The protocol op type for intermediate responses. |
| | | */ |
| | | public static final byte OP_TYPE_INTERMEDIATE_RESPONSE = 0x79; |
| | | |
| | | /** |
| | | * The BER type to use for encoding the sequence of controls in an LDAP |
| | | * message. |
| | | */ |
| | | public static final byte TYPE_CONTROL_SEQUENCE = (byte) 0xA0; |
| | | /** |
| | | * The BER type to use for encoding the sequence of controls in an LDAP |
| | | * message. |
| | | */ |
| | | public static final byte TYPE_CONTROL_SEQUENCE = (byte) 0xA0; |
| | | |
| | | /** |
| | | * The BER type to use for encoding the sequence of referral URLs in an |
| | | * LDAPResult element. |
| | | */ |
| | | public static final byte TYPE_REFERRAL_SEQUENCE = (byte) 0xA3; |
| | | /** |
| | | * The BER type to use for encoding the sequence of referral URLs in an |
| | | * LDAPResult element. |
| | | */ |
| | | public static final byte TYPE_REFERRAL_SEQUENCE = (byte) 0xA3; |
| | | |
| | | /** |
| | | * The BER type to use for the AuthenticationChoice element in a bind request |
| | | * when simple authentication is to be used. |
| | | */ |
| | | public static final byte TYPE_AUTHENTICATION_SIMPLE = (byte) 0x80; |
| | | /** |
| | | * The BER type to use for the AuthenticationChoice element in a bind |
| | | * request when simple authentication is to be used. |
| | | */ |
| | | public static final byte TYPE_AUTHENTICATION_SIMPLE = (byte) 0x80; |
| | | |
| | | /** |
| | | * The BER type to use for the AuthenticationChoice element in a bind request |
| | | * when SASL authentication is to be used. |
| | | */ |
| | | public static final byte TYPE_AUTHENTICATION_SASL = (byte) 0xA3; |
| | | /** |
| | | * The BER type to use for the AuthenticationChoice element in a bind |
| | | * request when SASL authentication is to be used. |
| | | */ |
| | | public static final byte TYPE_AUTHENTICATION_SASL = (byte) 0xA3; |
| | | |
| | | /** |
| | | * The BER type to use for the server SASL credentials in a bind response. |
| | | */ |
| | | public static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87; |
| | | /** |
| | | * The BER type to use for the server SASL credentials in a bind response. |
| | | */ |
| | | public static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87; |
| | | |
| | | /** |
| | | * The BER type to use for AND filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_AND = (byte) 0xA0; |
| | | /** |
| | | * The BER type to use for AND filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_AND = (byte) 0xA0; |
| | | |
| | | /** |
| | | * The BER type to use for OR filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_OR = (byte) 0xA1; |
| | | /** |
| | | * The BER type to use for OR filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_OR = (byte) 0xA1; |
| | | |
| | | /** |
| | | * The BER type to use for NOT filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_NOT = (byte) 0xA2; |
| | | /** |
| | | * The BER type to use for NOT filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_NOT = (byte) 0xA2; |
| | | |
| | | /** |
| | | * The BER type to use for equality filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_EQUALITY = (byte) 0xA3; |
| | | /** |
| | | * The BER type to use for equality filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_EQUALITY = (byte) 0xA3; |
| | | |
| | | /** |
| | | * The BER type to use for substring filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_SUBSTRING = (byte) 0xA4; |
| | | /** |
| | | * The BER type to use for substring filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_SUBSTRING = (byte) 0xA4; |
| | | |
| | | /** |
| | | * The BER type to use for greater than or equal to filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_GREATER_OR_EQUAL = (byte) 0xA5; |
| | | /** |
| | | * The BER type to use for greater than or equal to filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_GREATER_OR_EQUAL = (byte) 0xA5; |
| | | |
| | | /** |
| | | * The BER type to use for less than or equal to filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_LESS_OR_EQUAL = (byte) 0xA6; |
| | | /** |
| | | * The BER type to use for less than or equal to filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_LESS_OR_EQUAL = (byte) 0xA6; |
| | | |
| | | /** |
| | | * The BER type to use for presence filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_PRESENCE = (byte) 0x87; |
| | | /** |
| | | * The BER type to use for presence filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_PRESENCE = (byte) 0x87; |
| | | |
| | | /** |
| | | * The BER type to use for approximate filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_APPROXIMATE = (byte) 0xA8; |
| | | /** |
| | | * The BER type to use for approximate filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_APPROXIMATE = (byte) 0xA8; |
| | | |
| | | /** |
| | | * The BER type to use for extensible matching filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_EXTENSIBLE_MATCH = (byte) 0xA9; |
| | | /** |
| | | * The BER type to use for extensible matching filter components. |
| | | */ |
| | | public static final byte TYPE_FILTER_EXTENSIBLE_MATCH = (byte) 0xA9; |
| | | |
| | | /** |
| | | * The BER type to use for the subInitial component of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBINITIAL = (byte) 0x80; |
| | | /** |
| | | * The BER type to use for the subInitial component of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBINITIAL = (byte) 0x80; |
| | | |
| | | /** |
| | | * The BER type to use for the subAny component(s) of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBANY = (byte) 0x81; |
| | | /** |
| | | * The BER type to use for the subAny component(s) of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBANY = (byte) 0x81; |
| | | |
| | | /** |
| | | * The BER type to use for the subFinal components of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBFINAL = (byte) 0x82; |
| | | /** |
| | | * The BER type to use for the subFinal components of a substring filter. |
| | | */ |
| | | public static final byte TYPE_SUBFINAL = (byte) 0x82; |
| | | |
| | | /** |
| | | * The BER type to use for the matching rule OID in a matching rule assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_ID = (byte) 0x81; |
| | | /** |
| | | * The BER type to use for the matching rule OID in a matching rule |
| | | * assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_ID = (byte) 0x81; |
| | | |
| | | /** |
| | | * The BER type to use for the attribute type in a matching rule assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_TYPE = (byte) 0x82; |
| | | /** |
| | | * The BER type to use for the attribute type in a matching rule assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_TYPE = (byte) 0x82; |
| | | |
| | | /** |
| | | * The BER type to use for the assertion value in a matching rule assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_VALUE = (byte) 0x83; |
| | | /** |
| | | * The BER type to use for the assertion value in a matching rule assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_VALUE = (byte) 0x83; |
| | | |
| | | /** |
| | | * The BER type to use for the DN attributes flag in a matching rule |
| | | * assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_DN_ATTRIBUTES = (byte) 0x84; |
| | | /** |
| | | * The BER type to use for the DN attributes flag in a matching rule |
| | | * assertion. |
| | | */ |
| | | public static final byte TYPE_MATCHING_RULE_DN_ATTRIBUTES = (byte) 0x84; |
| | | |
| | | /** |
| | | * The BER type to use for the newSuperior component of a modify DN request. |
| | | */ |
| | | public static final byte TYPE_MODIFY_DN_NEW_SUPERIOR = (byte) 0x80; |
| | | /** |
| | | * The BER type to use for the newSuperior component of a modify DN request. |
| | | */ |
| | | public static final byte TYPE_MODIFY_DN_NEW_SUPERIOR = (byte) 0x80; |
| | | |
| | | /** |
| | | * The BER type to use for the OID of an extended request. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80; |
| | | /** |
| | | * The BER type to use for the OID of an extended request. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80; |
| | | |
| | | /** |
| | | * The BER type to use for the value of an extended request. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81; |
| | | /** |
| | | * The BER type to use for the value of an extended request. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81; |
| | | |
| | | /** |
| | | * The BER type to use for the OID of an extended response. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_RESPONSE_OID = (byte) 0x8A; |
| | | /** |
| | | * The BER type to use for the OID of an extended response. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_RESPONSE_OID = (byte) 0x8A; |
| | | |
| | | /** |
| | | * The BER type to use for the value of an extended response. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_RESPONSE_VALUE = (byte) 0x8B; |
| | | /** |
| | | * The BER type to use for the value of an extended response. |
| | | */ |
| | | public static final byte TYPE_EXTENDED_RESPONSE_VALUE = (byte) 0x8B; |
| | | |
| | | /** |
| | | * The BER type to use for the OID of an intermediate response message. |
| | | */ |
| | | public static final byte TYPE_INTERMEDIATE_RESPONSE_OID = (byte) 0x80; |
| | | /** |
| | | * The BER type to use for the OID of an intermediate response message. |
| | | */ |
| | | public static final byte TYPE_INTERMEDIATE_RESPONSE_OID = (byte) 0x80; |
| | | |
| | | /** |
| | | * The BER type to use for the value of an intermediate response message. |
| | | */ |
| | | public static final byte TYPE_INTERMEDIATE_RESPONSE_VALUE = (byte) 0x81; |
| | | /** |
| | | * The BER type to use for the value of an intermediate response message. |
| | | */ |
| | | public static final byte TYPE_INTERMEDIATE_RESPONSE_VALUE = (byte) 0x81; |
| | | |
| | | /** |
| | | * The OID for the Kerberos V GSSAPI mechanism. |
| | | */ |
| | | public static final String OID_GSSAPI_KERBEROS_V = "1.2.840.113554.1.2.2"; |
| | | /** |
| | | * The OID for the Kerberos V GSSAPI mechanism. |
| | | */ |
| | | public static final String OID_GSSAPI_KERBEROS_V = "1.2.840.113554.1.2.2"; |
| | | |
| | | /** |
| | | * The OID for the LDAP notice of disconnection extended operation. |
| | | */ |
| | | public static final String OID_NOTICE_OF_DISCONNECTION = "1.3.6.1.4.1.1466.20036"; |
| | | /** |
| | | * The OID for the LDAP notice of disconnection extended operation. |
| | | */ |
| | | public static final String OID_NOTICE_OF_DISCONNECTION = "1.3.6.1.4.1.1466.20036"; |
| | | |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be the BER type for a new element. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_TYPE = 0; |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be the BER type for a new element. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_TYPE = 0; |
| | | |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be the first byte for the element length. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE = 1; |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be the first byte for the element length. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_FIRST_LENGTH_BYTE = 1; |
| | | |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be additional bytes of a multi-byte length. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES = 2; |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be additional bytes of a multi-byte length. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_ADDITIONAL_LENGTH_BYTES = 2; |
| | | |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be applied to the value of the element. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_VALUE_BYTES = 3; |
| | | /** |
| | | * The ASN.1 element decoding state that indicates that the next byte read |
| | | * should be applied to the value of the element. |
| | | */ |
| | | public static final int ELEMENT_READ_STATE_NEED_VALUE_BYTES = 3; |
| | | |
| | | |
| | | |
| | | private LDAPConstants() |
| | | { |
| | | // Prevent instantiation. |
| | | } |
| | | private LDAPConstants() { |
| | | // Prevent instantiation. |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.DecodeOptions; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Extended result future implementation. |
| | | * |
| | | * @param <R> |
| | | * The type of result returned by this future. |
| | | * The type of result returned by this future. |
| | | */ |
| | | final class LDAPExtendedFutureResultImpl<R extends ExtendedResult> extends |
| | | AbstractLDAPFutureResultImpl<R> |
| | | { |
| | | private final ExtendedRequest<R> request; |
| | | AbstractLDAPFutureResultImpl<R> { |
| | | private final ExtendedRequest<R> request; |
| | | |
| | | LDAPExtendedFutureResultImpl(final int requestID, final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPExtendedFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | LDAPExtendedFutureResultImpl(final int requestID, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected boolean isCancelable() { |
| | | return !request.getOID().equals(StartTLSExtendedRequest.OID); |
| | | } |
| | | |
| | | R decodeResult(final ExtendedResult result, final DecodeOptions options) throws DecodeException { |
| | | return request.getResultDecoder().decodeExtendedResult(result, options); |
| | | } |
| | | |
| | | ExtendedRequest<R> getRequest() { |
| | | return request; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPExtendedFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected boolean isCancelable() { |
| | | return !request.getOID().equals(StartTLSExtendedRequest.OID); |
| | | } |
| | | |
| | | |
| | | |
| | | R decodeResult(final ExtendedResult result, final DecodeOptions options) |
| | | throws DecodeException |
| | | { |
| | | return request.getResultDecoder().decodeExtendedResult(result, options); |
| | | } |
| | | |
| | | |
| | | |
| | | ExtendedRequest<R> getRequest() |
| | | { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | R newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) |
| | | { |
| | | return request.getResultDecoder().newExtendedErrorResult(resultCode, "", |
| | | diagnosticMessage); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | R newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return request.getResultDecoder().newExtendedErrorResult(resultCode, "", diagnosticMessage); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Result future implementation. |
| | | */ |
| | | final class LDAPFutureResultImpl extends AbstractLDAPFutureResultImpl<Result> |
| | | { |
| | | private final Request request; |
| | | final class LDAPFutureResultImpl extends AbstractLDAPFutureResultImpl<Result> { |
| | | private final Request request; |
| | | |
| | | LDAPFutureResultImpl(final int requestID, final Request request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | LDAPFutureResultImpl(final int requestID, final Request request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | Request getRequest() { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | Request getRequest() |
| | | { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | Result newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | Result newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return Responses.newResult(resultCode).setDiagnosticMessage(diagnosticMessage).setCause( |
| | | cause); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.io.Closeable; |
| | | import java.io.IOException; |
| | | import java.net.SocketAddress; |
| | |
| | | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | |
| | | |
| | | |
| | | /** |
| | | * LDAP listener implementation. |
| | | */ |
| | | public final class LDAPListenerImpl implements Closeable |
| | | { |
| | | private final TCPNIOTransport transport; |
| | | private final FilterChain defaultFilterChain; |
| | | private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory; |
| | | private final TCPNIOServerConnection serverConnection; |
| | | public final class LDAPListenerImpl implements Closeable { |
| | | private final TCPNIOTransport transport; |
| | | private final FilterChain defaultFilterChain; |
| | | private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory; |
| | | private final TCPNIOServerConnection serverConnection; |
| | | |
| | | /** |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections using the provided address and connection options. |
| | | * |
| | | * @param address |
| | | * The address to listen on. |
| | | * @param factory |
| | | * The server connection factory which will be used to create |
| | | * server connections. |
| | | * @param options |
| | | * The LDAP listener options. |
| | | * @throws IOException |
| | | * If an error occurred while trying to listen on the provided |
| | | * address. |
| | | */ |
| | | public LDAPListenerImpl(final SocketAddress address, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory, |
| | | final LDAPListenerOptions options) throws IOException { |
| | | if (options.getTCPNIOTransport() == null) { |
| | | this.transport = DefaultTCPNIOTransport.getInstance(); |
| | | } else { |
| | | this.transport = options.getTCPNIOTransport(); |
| | | } |
| | | this.connectionFactory = factory; |
| | | |
| | | final DecodeOptions decodeOptions = new DecodeOptions(options.getDecodeOptions()); |
| | | this.defaultFilterChain = |
| | | FilterChainBuilder.stateless().add(new TransportFilter()).add( |
| | | new LDAPServerFilter(this, new LDAPReader(decodeOptions), 0)).build(); |
| | | |
| | | /** |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections using the provided address and connection options. |
| | | * |
| | | * @param address |
| | | * The address to listen on. |
| | | * @param factory |
| | | * The server connection factory which will be used to create server |
| | | * connections. |
| | | * @param options |
| | | * The LDAP listener options. |
| | | * @throws IOException |
| | | * If an error occurred while trying to listen on the provided |
| | | * address. |
| | | */ |
| | | public LDAPListenerImpl(final SocketAddress address, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory, |
| | | final LDAPListenerOptions options) throws IOException |
| | | { |
| | | if (options.getTCPNIOTransport() == null) |
| | | { |
| | | this.transport = DefaultTCPNIOTransport.getInstance(); |
| | | this.serverConnection = transport.bind(address, options.getBacklog()); |
| | | this.serverConnection.setProcessor(defaultFilterChain); |
| | | } |
| | | else |
| | | { |
| | | this.transport = options.getTCPNIOTransport(); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close() { |
| | | try { |
| | | serverConnection.close().get(); |
| | | } catch (final InterruptedException e) { |
| | | // Cannot handle here. |
| | | Thread.currentThread().interrupt(); |
| | | } catch (final Exception e) { |
| | | // Ignore the exception. |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) { |
| | | StaticUtils.DEBUG_LOG.log(Level.WARNING, |
| | | "Exception occurred while closing listener:" + e.getMessage(), e); |
| | | } |
| | | } |
| | | } |
| | | this.connectionFactory = factory; |
| | | |
| | | final DecodeOptions decodeOptions = new DecodeOptions(options |
| | | .getDecodeOptions()); |
| | | this.defaultFilterChain = FilterChainBuilder |
| | | .stateless() |
| | | .add(new TransportFilter()) |
| | | .add(new LDAPServerFilter(this, new LDAPReader(decodeOptions), 0)) |
| | | .build(); |
| | | |
| | | this.serverConnection = transport.bind(address, options.getBacklog()); |
| | | this.serverConnection.setProcessor(defaultFilterChain); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close() |
| | | { |
| | | try |
| | | { |
| | | serverConnection.close().get(); |
| | | /** |
| | | * Returns the address that this LDAP listener is listening on. |
| | | * |
| | | * @return The address that this LDAP listener is listening on. |
| | | */ |
| | | public SocketAddress getSocketAddress() { |
| | | return serverConnection.getLocalAddress(); |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | // Cannot handle here. |
| | | Thread.currentThread().interrupt(); |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPListener("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Ignore the exception. |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.log(Level.WARNING, |
| | | "Exception occurred while closing listener:" + e.getMessage(), e); |
| | | } |
| | | |
| | | ServerConnectionFactory<LDAPClientContext, Integer> getConnectionFactory() { |
| | | return connectionFactory; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the address that this LDAP listener is listening on. |
| | | * |
| | | * @return The address that this LDAP listener is listening on. |
| | | */ |
| | | public SocketAddress getSocketAddress() |
| | | { |
| | | return serverConnection.getLocalAddress(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPListener("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | ServerConnectionFactory<LDAPClientContext, Integer> getConnectionFactory() |
| | | { |
| | | return connectionFactory; |
| | | } |
| | | |
| | | |
| | | |
| | | FilterChain getDefaultFilterChain() |
| | | { |
| | | return defaultFilterChain; |
| | | } |
| | | FilterChain getDefaultFilterChain() { |
| | | return defaultFilterChain; |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.IntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | |
| | | /** |
| | | * LDAP message handler interface. |
| | | * |
| | | * @param <P> |
| | | * A user provided handler parameter. |
| | | * A user provided handler parameter. |
| | | */ |
| | | interface LDAPMessageHandler<P> |
| | | { |
| | | void abandonRequest(P param, int messageID, AbandonRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | interface LDAPMessageHandler<P> { |
| | | void abandonRequest(P param, int messageID, AbandonRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void addRequest(P param, int messageID, AddRequest request) throws UnexpectedRequestException, |
| | | IOException; |
| | | |
| | | void addResult(P param, int messageID, Result result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void addRequest(P param, int messageID, AddRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | void bindRequest(P param, int messageID, int version, GenericBindRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void bindResult(P param, int messageID, BindResult result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void compareRequest(P param, int messageID, CompareRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void addResult(P param, int messageID, Result result) |
| | | throws UnexpectedResponseException, IOException; |
| | | void compareResult(P param, int messageID, CompareResult result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | void deleteRequest(P param, int messageID, DeleteRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void deleteResult(P param, int messageID, Result result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void bindRequest(P param, int messageID, int version, |
| | | GenericBindRequest request) throws UnexpectedRequestException, |
| | | IOException; |
| | | <R extends ExtendedResult> void extendedRequest(P param, int messageID, |
| | | ExtendedRequest<R> request) throws UnexpectedRequestException, IOException; |
| | | |
| | | void extendedResult(P param, int messageID, ExtendedResult result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | void intermediateResponse(P param, int messageID, IntermediateResponse response) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | void bindResult(P param, int messageID, BindResult result) |
| | | throws UnexpectedResponseException, IOException; |
| | | void modifyDNRequest(P param, int messageID, ModifyDNRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void modifyDNResult(P param, int messageID, Result result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void modifyRequest(P param, int messageID, ModifyRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void compareRequest(P param, int messageID, CompareRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | void modifyResult(P param, int messageID, Result result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void searchRequest(P param, int messageID, SearchRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void searchResult(P param, int messageID, Result result) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | void compareResult(P param, int messageID, CompareResult result) |
| | | throws UnexpectedResponseException, IOException; |
| | | void searchResultEntry(P param, int messageID, SearchResultEntry entry) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | void searchResultReference(P param, int messageID, SearchResultReference reference) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | void unbindRequest(P param, int messageID, UnbindRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | void deleteRequest(P param, int messageID, DeleteRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | |
| | | |
| | | void deleteResult(P param, int messageID, Result result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | <R extends ExtendedResult> void extendedRequest(P param, int messageID, |
| | | ExtendedRequest<R> request) throws UnexpectedRequestException, |
| | | IOException; |
| | | |
| | | |
| | | |
| | | void extendedResult(P param, int messageID, ExtendedResult result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | void intermediateResponse(P param, int messageID, |
| | | IntermediateResponse response) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | |
| | | |
| | | void modifyDNRequest(P param, int messageID, ModifyDNRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | |
| | | |
| | | void modifyDNResult(P param, int messageID, Result result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | void modifyRequest(P param, int messageID, ModifyRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | |
| | | |
| | | void modifyResult(P param, int messageID, Result result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | void searchRequest(P param, int messageID, SearchRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | |
| | | |
| | | void searchResult(P param, int messageID, Result result) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | void searchResultEntry(P param, int messageID, SearchResultEntry entry) |
| | | throws UnexpectedResponseException, IOException; |
| | | |
| | | |
| | | |
| | | void searchResultReference(P param, int messageID, |
| | | SearchResultReference reference) throws UnexpectedResponseException, |
| | | IOException; |
| | | |
| | | |
| | | |
| | | void unbindRequest(P param, int messageID, UnbindRequest request) |
| | | throws UnexpectedRequestException, IOException; |
| | | |
| | | |
| | | |
| | | void unrecognizedMessage(P param, int messageID, byte messageTag, |
| | | ByteString messageBytes) throws UnsupportedMessageException, IOException; |
| | | void unrecognizedMessage(P param, int messageID, byte messageTag, ByteString messageBytes) |
| | | throws UnsupportedMessageException, IOException; |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.*; |
| | | import static org.forgerock.opendj.asn1.ASN1Constants.UNIVERSAL_BOOLEAN_TYPE; |
| | | import static org.forgerock.opendj.asn1.ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE; |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizedIllegalArgumentException; |
| | | import org.forgerock.opendj.asn1.ASN1Reader; |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.Attribute; |
| | | import org.forgerock.opendj.ldap.AttributeDescription; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DN; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.DecodeOptions; |
| | | import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.opendj.ldap.Filter; |
| | | import org.forgerock.opendj.ldap.Modification; |
| | | import org.forgerock.opendj.ldap.ModificationType; |
| | | import org.forgerock.opendj.ldap.RDN; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.controls.Control; |
| | | import org.forgerock.opendj.ldap.controls.GenericControl; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.Request; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.GenericExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.GenericIntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Response; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Static methods for decoding LDAP messages. |
| | | */ |
| | | final class LDAPReader |
| | | { |
| | | static SearchResultEntry decodeEntry(final ASN1Reader reader, |
| | | final DecodeOptions options) throws IOException |
| | | { |
| | | Entry entry; |
| | | final class LDAPReader { |
| | | static SearchResultEntry decodeEntry(final ASN1Reader reader, final DecodeOptions options) |
| | | throws IOException { |
| | | Entry entry; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | DN dn; |
| | | try |
| | | { |
| | | dn = DN.valueOf(dnString, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | AttributeDescription ad; |
| | | try |
| | | { |
| | | ad = AttributeDescription.valueOf(ads, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | DN dn; |
| | | try { |
| | | dn = DN.valueOf(dnString, schema); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | |
| | | final Attribute attribute = options.getAttributeFactory() |
| | | .newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSet(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Responses.newSearchResultEntry(entry); |
| | | } |
| | | |
| | | |
| | | |
| | | private final DecodeOptions options; |
| | | |
| | | |
| | | |
| | | LDAPReader(final DecodeOptions options) |
| | | { |
| | | this.options = options; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP message. |
| | | * |
| | | * @param <P> |
| | | * The type of {@code param}. |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle a decoded |
| | | * message. |
| | | * @param param |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | <P> void decode(final ASN1Reader reader, final LDAPMessageHandler<P> handler, |
| | | final P param) throws IOException |
| | | { |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final int messageID = (int) reader.readInteger(); |
| | | decodeProtocolOp(reader, messageID, handler, param); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP abandon |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAbandonRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | final int msgToAbandon = (int) reader.readInteger(OP_TYPE_ABANDON_REQUEST); |
| | | final AbandonRequest message = Requests.newAbandonRequest(msgToAbandon); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.abandonRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP add request |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAddRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Entry entry; |
| | | |
| | | reader.readStartSequence(OP_TYPE_ADD_REQUEST); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, |
| | | schema); |
| | | final Attribute attribute = options.getAttributeFactory() |
| | | .newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSet(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final AddRequest message = Requests.newAddRequest(entry); |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.addRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an add response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAddResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_ADD_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String |
| | | .format("DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.addResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | private AttributeDescription decodeAttributeDescription( |
| | | final String attributeDescription, final Schema schema) |
| | | throws DecodeException |
| | | { |
| | | try |
| | | { |
| | | return AttributeDescription.valueOf(attributeDescription, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP bind request |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeBindRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | reader.readStartSequence(OP_TYPE_BIND_REQUEST); |
| | | try |
| | | { |
| | | final int protocolVersion = (int) reader.readInteger(); |
| | | final String authName = reader.readOctetStringAsString(); |
| | | final byte authType = reader.peekType(); |
| | | final byte[] authBytes = reader.readOctetString(authType).toByteArray(); |
| | | |
| | | final GenericBindRequest request = Requests.newGenericBindRequest( |
| | | authName, authType, authBytes); |
| | | |
| | | decodeControls(reader, request); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)", |
| | | messageID, request.getAuthenticationType(), request)); |
| | | } |
| | | |
| | | handler.bindRequest(p, messageID, protocolVersion, request); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a bind response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeBindResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | BindResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_BIND_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newBindResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_SERVER_SASL_CREDENTIALS)) |
| | | { |
| | | message.setServerSASLCredentials(reader |
| | | .readOctetString(TYPE_SERVER_SASL_CREDENTIALS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.bindResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP compare |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeCompareRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | CompareRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_COMPARE_REQUEST); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, schema); |
| | | final ByteString assertionValue = reader.readOctetString(); |
| | | message = Requests.newCompareRequest(dn, ad, assertionValue); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.compareRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a compare response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeCompareResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | CompareResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_COMPARE_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newCompareResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.compareResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP control. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param request |
| | | * The decoded request to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControl(final ASN1Reader reader, final Request request) |
| | | throws IOException |
| | | { |
| | | String oid; |
| | | boolean isCritical; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | oid = reader.readOctetStringAsString(); |
| | | isCritical = false; |
| | | value = null; |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) |
| | | { |
| | | isCritical = reader.readBoolean(); |
| | | } |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) |
| | | { |
| | | value = reader.readOctetString(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final Control c = GenericControl.newControl(oid, isCritical, value); |
| | | request.addControl(c); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP control. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param response |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControl(final ASN1Reader reader, final Response response) |
| | | throws IOException |
| | | { |
| | | String oid; |
| | | boolean isCritical; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | oid = reader.readOctetStringAsString(); |
| | | isCritical = false; |
| | | value = null; |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) |
| | | { |
| | | isCritical = reader.readBoolean(); |
| | | } |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) |
| | | { |
| | | value = reader.readOctetString(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final Control c = GenericControl.newControl(oid, isCritical, value); |
| | | response.addControl(c); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a set of controls. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param request |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControls(final ASN1Reader reader, final Request request) |
| | | throws IOException |
| | | { |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) |
| | | { |
| | | reader.readStartSequence(TYPE_CONTROL_SEQUENCE); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | decodeControl(reader, request); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a set of controls. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param response |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControls(final ASN1Reader reader, final Response response) |
| | | throws IOException |
| | | { |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) |
| | | { |
| | | reader.readStartSequence(TYPE_CONTROL_SEQUENCE); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | decodeControl(reader, response); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP delete |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeDeleteRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | final String dnString = reader |
| | | .readOctetStringAsString(OP_TYPE_DELETE_REQUEST); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | final DeleteRequest message = Requests.newDeleteRequest(dn); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.deleteRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a delete response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeDeleteResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_DELETE_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.deleteResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | private DN decodeDN(final String dn, final Schema schema) |
| | | throws DecodeException |
| | | { |
| | | try |
| | | { |
| | | return DN.valueOf(dn, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP extended |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeExtendedRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | String oid; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(OP_TYPE_EXTENDED_REQUEST); |
| | | try |
| | | { |
| | | oid = reader.readOctetStringAsString(TYPE_EXTENDED_REQUEST_OID); |
| | | value = null; |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_EXTENDED_REQUEST_VALUE)) |
| | | { |
| | | value = reader.readOctetString(TYPE_EXTENDED_REQUEST_VALUE); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final GenericExtendedRequest message = Requests.newGenericExtendedRequest( |
| | | oid, value); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.extendedRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a extended response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeExtendedResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | |
| | | GenericExtendedResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_EXTENDED_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newGenericExtendedResult(resultCode).setMatchedDN( |
| | | matchedDN).setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_EXTENDED_RESPONSE_OID)) |
| | | { |
| | | message.setOID(reader |
| | | .readOctetStringAsString(TYPE_EXTENDED_RESPONSE_OID)); |
| | | } |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_EXTENDED_RESPONSE_VALUE)) |
| | | { |
| | | message.setValue(reader.readOctetString(TYPE_EXTENDED_RESPONSE_VALUE)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.extendedResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP intermediate |
| | | * response protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeIntermediateResponse(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | GenericIntermediateResponse message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE); |
| | | try |
| | | { |
| | | message = Responses.newGenericIntermediateResponse(); |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_OID)) |
| | | { |
| | | message.setOID(reader |
| | | .readOctetStringAsString(TYPE_INTERMEDIATE_RESPONSE_OID)); |
| | | } |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_VALUE)) |
| | | { |
| | | message.setValue(reader |
| | | .readOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)", |
| | | messageID, message)); |
| | | } |
| | | |
| | | handler.intermediateResponse(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify DN request |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyDNRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | ModifyDNRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_DN_REQUEST); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | |
| | | final String newRDNString = reader.readOctetStringAsString(); |
| | | final RDN newRDN = decodeRDN(newRDNString, schema); |
| | | |
| | | message = Requests.newModifyDNRequest(dn, newRDN); |
| | | |
| | | message.setDeleteOldRDN(reader.readBoolean()); |
| | | |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_MODIFY_DN_NEW_SUPERIOR)) |
| | | { |
| | | final String newSuperiorString = reader |
| | | .readOctetStringAsString(TYPE_MODIFY_DN_NEW_SUPERIOR); |
| | | final DN newSuperior = decodeDN(newSuperiorString, schema); |
| | | message.setNewSuperior(newSuperior); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.modifyDNRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify DN response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyDNResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_DN_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.modifyDNResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP modify |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | ModifyRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_REQUEST); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | message = Requests.newModifyRequest(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final int typeIntValue = reader.readEnumerated(); |
| | | final ModificationType type = ModificationType |
| | | .valueOf(typeIntValue); |
| | | if (type == null) |
| | | { |
| | | throw DecodeException |
| | | .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE |
| | | .get(typeIntValue)); |
| | | } |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, |
| | | schema); |
| | | final Attribute attribute = options.getAttributeFactory() |
| | | .newAttribute(ad); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | reader.readStartSequence(); |
| | | try { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | AttributeDescription ad; |
| | | try { |
| | | ad = AttributeDescription.valueOf(ads, schema); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | |
| | | reader.readStartSet(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | attribute.add(reader.readOctetString()); |
| | | final Attribute attribute = options.getAttributeFactory().newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } finally { |
| | | reader.readEndSet(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | message.addModification(new Modification(type, attribute)); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSet(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | |
| | | return Responses.newSearchResultEntry(entry); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | private final DecodeOptions options; |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | LDAPReader(final DecodeOptions options) { |
| | | this.options = options; |
| | | } |
| | | |
| | | handler.modifyRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_RESPONSE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.modifyResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeProtocolOp(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | final byte type = reader.peekType(); |
| | | |
| | | switch (type) |
| | | { |
| | | case OP_TYPE_UNBIND_REQUEST: // 0x42 |
| | | decodeUnbindRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x43: // 0x43 |
| | | case 0x44: // 0x44 |
| | | case 0x45: // 0x45 |
| | | case 0x46: // 0x46 |
| | | case 0x47: // 0x47 |
| | | case 0x48: // 0x48 |
| | | case 0x49: // 0x49 |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_DELETE_REQUEST: // 0x4A |
| | | decodeDeleteRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x4B: // 0x4B |
| | | case 0x4C: // 0x4C |
| | | case 0x4D: // 0x4D |
| | | case 0x4E: // 0x4E |
| | | case 0x4F: // 0x4F |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_ABANDON_REQUEST: // 0x50 |
| | | decodeAbandonRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x51: // 0x51 |
| | | case 0x52: // 0x52 |
| | | case 0x53: // 0x53 |
| | | case 0x54: // 0x54 |
| | | case 0x55: // 0x55 |
| | | case 0x56: // 0x56 |
| | | case 0x57: // 0x57 |
| | | case 0x58: // 0x58 |
| | | case 0x59: // 0x59 |
| | | case 0x5A: // 0x5A |
| | | case 0x5B: // 0x5B |
| | | case 0x5C: // 0x5C |
| | | case 0x5D: // 0x5D |
| | | case 0x5E: // 0x5E |
| | | case 0x5F: // 0x5F |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_BIND_REQUEST: // 0x60 |
| | | decodeBindRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_BIND_RESPONSE: // 0x61 |
| | | decodeBindResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x62: // 0x62 |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_SEARCH_REQUEST: // 0x63 |
| | | decodeSearchRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64 |
| | | decodeSearchResultEntry(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_DONE: // 0x65 |
| | | decodeSearchResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_REQUEST: // 0x66 |
| | | decodeModifyRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_RESPONSE: // 0x67 |
| | | decodeModifyResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_ADD_REQUEST: // 0x68 |
| | | decodeAddRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_ADD_RESPONSE: // 0x69 |
| | | decodeAddResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x6A: // 0x6A |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_DELETE_RESPONSE: // 0x6B |
| | | decodeDeleteResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_DN_REQUEST: // 0x6C |
| | | decodeModifyDNRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D |
| | | decodeModifyDNResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_COMPARE_REQUEST: // 0x6E |
| | | decodeCompareRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_COMPARE_RESPONSE: // 0x6F |
| | | decodeCompareResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x70: // 0x70 |
| | | case 0x71: // 0x71 |
| | | case 0x72: // 0x72 |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73 |
| | | decodeSearchResultReference(reader, messageID, handler, p); |
| | | break; |
| | | case 0x74: // 0x74 |
| | | case 0x75: // 0x75 |
| | | case 0x76: // 0x76 |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_EXTENDED_REQUEST: // 0x77 |
| | | decodeExtendedRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_EXTENDED_RESPONSE: // 0x78 |
| | | decodeExtendedResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79 |
| | | decodeIntermediateResponse(reader, messageID, handler, p); |
| | | break; |
| | | default: |
| | | handler.unrecognizedMessage(p, messageID, type, reader |
| | | .readOctetString(type)); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private RDN decodeRDN(final String rdn, final Schema schema) |
| | | throws DecodeException |
| | | { |
| | | try |
| | | { |
| | | return RDN.valueOf(rdn, schema); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void decodeResponseReferrals(final ASN1Reader reader, |
| | | final Result message) throws IOException |
| | | { |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_REFERRAL_SEQUENCE)) |
| | | { |
| | | reader.readStartSequence(TYPE_REFERRAL_SEQUENCE); |
| | | try |
| | | { |
| | | // Should have at least 1. |
| | | do |
| | | { |
| | | message.addReferralURI((reader.readOctetStringAsString())); |
| | | } |
| | | while (reader.hasNextElement()); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP search |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | SearchRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_REQUEST); |
| | | try |
| | | { |
| | | final String baseDNString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema( |
| | | baseDNString); |
| | | final DN baseDN = decodeDN(baseDNString, schema); |
| | | |
| | | final int scopeIntValue = reader.readEnumerated(); |
| | | final SearchScope scope = SearchScope.valueOf(scopeIntValue); |
| | | if (scope == null) |
| | | { |
| | | throw DecodeException |
| | | .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE |
| | | .get(scopeIntValue)); |
| | | } |
| | | |
| | | final int dereferencePolicyIntValue = reader.readEnumerated(); |
| | | final DereferenceAliasesPolicy dereferencePolicy = DereferenceAliasesPolicy |
| | | .valueOf(dereferencePolicyIntValue); |
| | | if (dereferencePolicy == null) |
| | | { |
| | | throw DecodeException |
| | | .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF |
| | | .get(dereferencePolicyIntValue)); |
| | | } |
| | | |
| | | final int sizeLimit = (int) reader.readInteger(); |
| | | final int timeLimit = (int) reader.readInteger(); |
| | | final boolean typesOnly = reader.readBoolean(); |
| | | final Filter filter = LDAPUtils.decodeFilter(reader); |
| | | |
| | | message = Requests.newSearchRequest(baseDN, scope, filter); |
| | | message.setDereferenceAliasesPolicy(dereferencePolicy); |
| | | try |
| | | { |
| | | message.setTimeLimit(timeLimit); |
| | | message.setSizeLimit(sizeLimit); |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | message.setTypesOnly(typesOnly); |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | message.addAttribute(reader.readOctetStringAsString()); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.searchRequest(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a search result done |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResult(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_DONE); |
| | | try |
| | | { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = Responses.newResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.searchResult(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP search |
| | | * result entry protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResultEntry(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | Entry entry; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); |
| | | try |
| | | { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, |
| | | schema); |
| | | final Attribute attribute = options.getAttributeFactory() |
| | | .newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try |
| | | { |
| | | while (reader.hasNextElement()) |
| | | { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSet(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP message. |
| | | * |
| | | * @param <P> |
| | | * The type of {@code param}. |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle a decoded |
| | | * message. |
| | | * @param param |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | <P> void decode(final ASN1Reader reader, final LDAPMessageHandler<P> handler, final P param) |
| | | throws IOException { |
| | | reader.readStartSequence(); |
| | | try { |
| | | final int messageID = (int) reader.readInteger(); |
| | | decodeProtocolOp(reader, messageID, handler, param); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final SearchResultEntry message = Responses.newSearchResultEntry(entry); |
| | | decodeControls(reader, message); |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP abandon |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAbandonRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | final int msgToAbandon = (int) reader.readInteger(OP_TYPE_ABANDON_REQUEST); |
| | | final AbandonRequest message = Requests.newAbandonRequest(msgToAbandon); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, |
| | | message)); |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.abandonRequest(p, messageID, message); |
| | | } |
| | | |
| | | handler.searchResultEntry(p, messageID, message); |
| | | } |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP add |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAddRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Entry entry; |
| | | |
| | | reader.readStartSequence(OP_TYPE_ADD_REQUEST); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | reader.readStartSequence(); |
| | | try { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, schema); |
| | | final Attribute attribute = options.getAttributeFactory().newAttribute(ad); |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a search result |
| | | * reference protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResultReference(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | SearchResultReference message; |
| | | reader.readStartSet(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } finally { |
| | | reader.readEndSet(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE); |
| | | try |
| | | { |
| | | message = Responses.newSearchResultReference(reader |
| | | .readOctetStringAsString()); |
| | | while (reader.hasNextElement()) |
| | | { |
| | | message.addURI(reader.readOctetStringAsString()); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | final AddRequest message = Requests.newAddRequest(entry); |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.addRequest(p, messageID, message); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an add response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeAddResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Result message; |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", |
| | | messageID, message)); |
| | | reader.readStartSequence(OP_TYPE_ADD_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( |
| | | diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.addResult(p, messageID, message); |
| | | } |
| | | |
| | | handler.searchResultReference(p, messageID, message); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP unbind request |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this decoded |
| | | * message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeUnbindRequest(final ASN1Reader reader, |
| | | final int messageID, final LDAPMessageHandler<P> handler, final P p) |
| | | throws IOException |
| | | { |
| | | UnbindRequest message; |
| | | reader.readNull(OP_TYPE_UNBIND_REQUEST); |
| | | message = Requests.newUnbindRequest(); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID, |
| | | message)); |
| | | private AttributeDescription decodeAttributeDescription(final String attributeDescription, |
| | | final Schema schema) throws DecodeException { |
| | | try { |
| | | return AttributeDescription.valueOf(attributeDescription, schema); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | handler.unbindRequest(p, messageID, message); |
| | | } |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP bind request |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeBindRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | reader.readStartSequence(OP_TYPE_BIND_REQUEST); |
| | | try { |
| | | final int protocolVersion = (int) reader.readInteger(); |
| | | final String authName = reader.readOctetStringAsString(); |
| | | final byte authType = reader.peekType(); |
| | | final byte[] authBytes = reader.readOctetString(authType).toByteArray(); |
| | | |
| | | final GenericBindRequest request = |
| | | Requests.newGenericBindRequest(authName, authType, authBytes); |
| | | |
| | | decodeControls(reader, request); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)", messageID, |
| | | request.getAuthenticationType(), request)); |
| | | } |
| | | |
| | | handler.bindRequest(p, messageID, protocolVersion, request); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a bind response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeBindResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | BindResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_BIND_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newBindResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_SERVER_SASL_CREDENTIALS)) { |
| | | message.setServerSASLCredentials(reader |
| | | .readOctetString(TYPE_SERVER_SASL_CREDENTIALS)); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.bindResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP compare |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeCompareRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | CompareRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_COMPARE_REQUEST); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, schema); |
| | | final ByteString assertionValue = reader.readOctetString(); |
| | | message = Requests.newCompareRequest(dn, ad, assertionValue); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.compareRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a compare response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeCompareResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | CompareResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_COMPARE_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newCompareResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.compareResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP control. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param request |
| | | * The decoded request to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControl(final ASN1Reader reader, final Request request) throws IOException { |
| | | String oid; |
| | | boolean isCritical; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | oid = reader.readOctetStringAsString(); |
| | | isCritical = false; |
| | | value = null; |
| | | if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) { |
| | | isCritical = reader.readBoolean(); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) { |
| | | value = reader.readOctetString(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final Control c = GenericControl.newControl(oid, isCritical, value); |
| | | request.addControl(c); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP control. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param response |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControl(final ASN1Reader reader, final Response response) throws IOException { |
| | | String oid; |
| | | boolean isCritical; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | oid = reader.readOctetStringAsString(); |
| | | isCritical = false; |
| | | value = null; |
| | | if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) { |
| | | isCritical = reader.readBoolean(); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) { |
| | | value = reader.readOctetString(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final Control c = GenericControl.newControl(oid, isCritical, value); |
| | | response.addControl(c); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a set of controls. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param request |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControls(final ASN1Reader reader, final Request request) throws IOException { |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) { |
| | | reader.readStartSequence(TYPE_CONTROL_SEQUENCE); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | decodeControl(reader, request); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a set of controls. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param response |
| | | * The decoded message to decode controls for. |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private void decodeControls(final ASN1Reader reader, final Response response) |
| | | throws IOException { |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) { |
| | | reader.readStartSequence(TYPE_CONTROL_SEQUENCE); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | decodeControl(reader, response); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP delete |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeDeleteRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | final String dnString = reader.readOctetStringAsString(OP_TYPE_DELETE_REQUEST); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | final DeleteRequest message = Requests.newDeleteRequest(dn); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.deleteRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a delete response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeDeleteResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_DELETE_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( |
| | | diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.deleteResult(p, messageID, message); |
| | | } |
| | | |
| | | private DN decodeDN(final String dn, final Schema schema) throws DecodeException { |
| | | try { |
| | | return DN.valueOf(dn, schema); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP extended |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeExtendedRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | String oid; |
| | | ByteString value; |
| | | |
| | | reader.readStartSequence(OP_TYPE_EXTENDED_REQUEST); |
| | | try { |
| | | oid = reader.readOctetStringAsString(TYPE_EXTENDED_REQUEST_OID); |
| | | value = null; |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_REQUEST_VALUE)) { |
| | | value = reader.readOctetString(TYPE_EXTENDED_REQUEST_VALUE); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final GenericExtendedRequest message = Requests.newGenericExtendedRequest(oid, value); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.extendedRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a extended |
| | | * response protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeExtendedResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | |
| | | GenericExtendedResult message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_EXTENDED_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newGenericExtendedResult(resultCode).setMatchedDN(matchedDN) |
| | | .setDiagnosticMessage(diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_RESPONSE_OID)) { |
| | | message.setOID(reader.readOctetStringAsString(TYPE_EXTENDED_RESPONSE_OID)); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_RESPONSE_VALUE)) { |
| | | message.setValue(reader.readOctetString(TYPE_EXTENDED_RESPONSE_VALUE)); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.extendedResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP |
| | | * intermediate response protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeIntermediateResponse(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | GenericIntermediateResponse message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE); |
| | | try { |
| | | message = Responses.newGenericIntermediateResponse(); |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_OID)) { |
| | | message.setOID(reader.readOctetStringAsString(TYPE_INTERMEDIATE_RESPONSE_OID)); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_VALUE)) { |
| | | message.setValue(reader.readOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE)); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.intermediateResponse(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify DN |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyDNRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | ModifyDNRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_DN_REQUEST); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | |
| | | final String newRDNString = reader.readOctetStringAsString(); |
| | | final RDN newRDN = decodeRDN(newRDNString, schema); |
| | | |
| | | message = Requests.newModifyDNRequest(dn, newRDN); |
| | | |
| | | message.setDeleteOldRDN(reader.readBoolean()); |
| | | |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_MODIFY_DN_NEW_SUPERIOR)) { |
| | | final String newSuperiorString = |
| | | reader.readOctetStringAsString(TYPE_MODIFY_DN_NEW_SUPERIOR); |
| | | final DN newSuperior = decodeDN(newSuperiorString, schema); |
| | | message.setNewSuperior(newSuperior); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.modifyDNRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify DN |
| | | * response protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyDNResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_DN_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( |
| | | diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.modifyDNResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP modify |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | ModifyRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_REQUEST); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | message = Requests.newModifyRequest(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | reader.readStartSequence(); |
| | | try { |
| | | final int typeIntValue = reader.readEnumerated(); |
| | | final ModificationType type = ModificationType.valueOf(typeIntValue); |
| | | if (type == null) { |
| | | throw DecodeException |
| | | .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE |
| | | .get(typeIntValue)); |
| | | } |
| | | reader.readStartSequence(); |
| | | try { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, schema); |
| | | final Attribute attribute = |
| | | options.getAttributeFactory().newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | message.addModification(new Modification(type, attribute)); |
| | | } finally { |
| | | reader.readEndSet(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.modifyRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a modify response |
| | | * protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeModifyResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_MODIFY_RESPONSE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( |
| | | diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.modifyResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP protocol |
| | | * op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeProtocolOp(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | final byte type = reader.peekType(); |
| | | |
| | | switch (type) { |
| | | case OP_TYPE_UNBIND_REQUEST: // 0x42 |
| | | decodeUnbindRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x43: // 0x43 |
| | | case 0x44: // 0x44 |
| | | case 0x45: // 0x45 |
| | | case 0x46: // 0x46 |
| | | case 0x47: // 0x47 |
| | | case 0x48: // 0x48 |
| | | case 0x49: // 0x49 |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_DELETE_REQUEST: // 0x4A |
| | | decodeDeleteRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x4B: // 0x4B |
| | | case 0x4C: // 0x4C |
| | | case 0x4D: // 0x4D |
| | | case 0x4E: // 0x4E |
| | | case 0x4F: // 0x4F |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_ABANDON_REQUEST: // 0x50 |
| | | decodeAbandonRequest(reader, messageID, handler, p); |
| | | break; |
| | | case 0x51: // 0x51 |
| | | case 0x52: // 0x52 |
| | | case 0x53: // 0x53 |
| | | case 0x54: // 0x54 |
| | | case 0x55: // 0x55 |
| | | case 0x56: // 0x56 |
| | | case 0x57: // 0x57 |
| | | case 0x58: // 0x58 |
| | | case 0x59: // 0x59 |
| | | case 0x5A: // 0x5A |
| | | case 0x5B: // 0x5B |
| | | case 0x5C: // 0x5C |
| | | case 0x5D: // 0x5D |
| | | case 0x5E: // 0x5E |
| | | case 0x5F: // 0x5F |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_BIND_REQUEST: // 0x60 |
| | | decodeBindRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_BIND_RESPONSE: // 0x61 |
| | | decodeBindResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x62: // 0x62 |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_SEARCH_REQUEST: // 0x63 |
| | | decodeSearchRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64 |
| | | decodeSearchResultEntry(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_DONE: // 0x65 |
| | | decodeSearchResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_REQUEST: // 0x66 |
| | | decodeModifyRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_RESPONSE: // 0x67 |
| | | decodeModifyResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_ADD_REQUEST: // 0x68 |
| | | decodeAddRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_ADD_RESPONSE: // 0x69 |
| | | decodeAddResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x6A: // 0x6A |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_DELETE_RESPONSE: // 0x6B |
| | | decodeDeleteResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_DN_REQUEST: // 0x6C |
| | | decodeModifyDNRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D |
| | | decodeModifyDNResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_COMPARE_REQUEST: // 0x6E |
| | | decodeCompareRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_COMPARE_RESPONSE: // 0x6F |
| | | decodeCompareResult(reader, messageID, handler, p); |
| | | break; |
| | | case 0x70: // 0x70 |
| | | case 0x71: // 0x71 |
| | | case 0x72: // 0x72 |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73 |
| | | decodeSearchResultReference(reader, messageID, handler, p); |
| | | break; |
| | | case 0x74: // 0x74 |
| | | case 0x75: // 0x75 |
| | | case 0x76: // 0x76 |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | case OP_TYPE_EXTENDED_REQUEST: // 0x77 |
| | | decodeExtendedRequest(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_EXTENDED_RESPONSE: // 0x78 |
| | | decodeExtendedResult(reader, messageID, handler, p); |
| | | break; |
| | | case OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79 |
| | | decodeIntermediateResponse(reader, messageID, handler, p); |
| | | break; |
| | | default: |
| | | handler.unrecognizedMessage(p, messageID, type, reader.readOctetString(type)); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | private RDN decodeRDN(final String rdn, final Schema schema) throws DecodeException { |
| | | try { |
| | | return RDN.valueOf(rdn, schema); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | } |
| | | |
| | | private void decodeResponseReferrals(final ASN1Reader reader, final Result message) |
| | | throws IOException { |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_REFERRAL_SEQUENCE)) { |
| | | reader.readStartSequence(TYPE_REFERRAL_SEQUENCE); |
| | | try { |
| | | // Should have at least 1. |
| | | do { |
| | | message.addReferralURI((reader.readOctetStringAsString())); |
| | | } while (reader.hasNextElement()); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP search |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | SearchRequest message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_REQUEST); |
| | | try { |
| | | final String baseDNString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(baseDNString); |
| | | final DN baseDN = decodeDN(baseDNString, schema); |
| | | |
| | | final int scopeIntValue = reader.readEnumerated(); |
| | | final SearchScope scope = SearchScope.valueOf(scopeIntValue); |
| | | if (scope == null) { |
| | | throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE |
| | | .get(scopeIntValue)); |
| | | } |
| | | |
| | | final int dereferencePolicyIntValue = reader.readEnumerated(); |
| | | final DereferenceAliasesPolicy dereferencePolicy = |
| | | DereferenceAliasesPolicy.valueOf(dereferencePolicyIntValue); |
| | | if (dereferencePolicy == null) { |
| | | throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF |
| | | .get(dereferencePolicyIntValue)); |
| | | } |
| | | |
| | | final int sizeLimit = (int) reader.readInteger(); |
| | | final int timeLimit = (int) reader.readInteger(); |
| | | final boolean typesOnly = reader.readBoolean(); |
| | | final Filter filter = LDAPUtils.decodeFilter(reader); |
| | | |
| | | message = Requests.newSearchRequest(baseDN, scope, filter); |
| | | message.setDereferenceAliasesPolicy(dereferencePolicy); |
| | | try { |
| | | message.setTimeLimit(timeLimit); |
| | | message.setSizeLimit(sizeLimit); |
| | | } catch (final LocalizedIllegalArgumentException e) { |
| | | throw DecodeException.error(e.getMessageObject()); |
| | | } |
| | | message.setTypesOnly(typesOnly); |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | message.addAttribute(reader.readOctetStringAsString()); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.searchRequest(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a search result |
| | | * done protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResult(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | |
| | | Result message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_DONE); |
| | | try { |
| | | final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); |
| | | final String matchedDN = reader.readOctetStringAsString(); |
| | | final String diagnosticMessage = reader.readOctetStringAsString(); |
| | | message = |
| | | Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( |
| | | diagnosticMessage); |
| | | decodeResponseReferrals(reader, message); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.searchResult(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as an LDAP search |
| | | * result entry protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResultEntry(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | Entry entry; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); |
| | | try { |
| | | final String dnString = reader.readOctetStringAsString(); |
| | | final Schema schema = options.getSchemaResolver().resolveSchema(dnString); |
| | | final DN dn = decodeDN(dnString, schema); |
| | | entry = options.getEntryFactory().newEntry(dn); |
| | | |
| | | reader.readStartSequence(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | reader.readStartSequence(); |
| | | try { |
| | | final String ads = reader.readOctetStringAsString(); |
| | | final AttributeDescription ad = decodeAttributeDescription(ads, schema); |
| | | final Attribute attribute = options.getAttributeFactory().newAttribute(ad); |
| | | |
| | | reader.readStartSet(); |
| | | try { |
| | | while (reader.hasNextElement()) { |
| | | attribute.add(reader.readOctetString()); |
| | | } |
| | | entry.addAttribute(attribute); |
| | | } finally { |
| | | reader.readEndSet(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | final SearchResultEntry message = Responses.newSearchResultEntry(entry); |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.searchResultEntry(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 reader as a search result |
| | | * reference protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeSearchResultReference(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | SearchResultReference message; |
| | | |
| | | reader.readStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE); |
| | | try { |
| | | message = Responses.newSearchResultReference(reader.readOctetStringAsString()); |
| | | while (reader.hasNextElement()) { |
| | | message.addURI(reader.readOctetStringAsString()); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", messageID, |
| | | message)); |
| | | } |
| | | |
| | | handler.searchResultReference(p, messageID, message); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the elements from the provided ASN.1 read as an LDAP unbind |
| | | * request protocol op. |
| | | * |
| | | * @param reader |
| | | * The ASN.1 reader. |
| | | * @param messageID |
| | | * The decoded message ID for this message. |
| | | * @param handler |
| | | * The <code>LDAPMessageHandler</code> that will handle this |
| | | * decoded message. |
| | | * @param p |
| | | * The parameter to pass into the <code>LDAPMessageHandler</code> |
| | | * @throws IOException |
| | | * If an error occurred while reading bytes to decode. |
| | | */ |
| | | private <P> void decodeUnbindRequest(final ASN1Reader reader, final int messageID, |
| | | final LDAPMessageHandler<P> handler, final P p) throws IOException { |
| | | UnbindRequest message; |
| | | reader.readNull(OP_TYPE_UNBIND_REQUEST); |
| | | message = Requests.newUnbindRequest(); |
| | | |
| | | decodeControls(reader, message); |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { |
| | | StaticUtils.DEBUG_LOG.finer(String.format( |
| | | "DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID, message)); |
| | | } |
| | | |
| | | handler.unbindRequest(p, messageID, message); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.Connection; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Search result future implementation. |
| | | */ |
| | | final class LDAPSearchFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<Result> implements SearchResultHandler |
| | | { |
| | | final class LDAPSearchFutureResultImpl extends AbstractLDAPFutureResultImpl<Result> implements |
| | | SearchResultHandler { |
| | | |
| | | private SearchResultHandler searchResultHandler; |
| | | private SearchResultHandler searchResultHandler; |
| | | |
| | | private final SearchRequest request; |
| | | private final SearchRequest request; |
| | | |
| | | |
| | | |
| | | LDAPSearchFutureResultImpl(final int requestID, final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) |
| | | { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | this.searchResultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | public boolean handleEntry(final SearchResultEntry entry) |
| | | { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) |
| | | { |
| | | updateTimestamp(); |
| | | if (searchResultHandler != null) |
| | | { |
| | | if (!searchResultHandler.handleEntry(entry)) |
| | | { |
| | | searchResultHandler = null; |
| | | } |
| | | } |
| | | LDAPSearchFutureResultImpl(final int requestID, final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final Connection connection) { |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | this.searchResultHandler = resultHandler; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | public boolean handleReference(final SearchResultReference reference) |
| | | { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) |
| | | { |
| | | updateTimestamp(); |
| | | if (searchResultHandler != null) |
| | | { |
| | | if (!searchResultHandler.handleReference(reference)) |
| | | { |
| | | searchResultHandler = null; |
| | | public boolean handleEntry(final SearchResultEntry entry) { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) { |
| | | updateTimestamp(); |
| | | if (searchResultHandler != null) { |
| | | if (!searchResultHandler.handleEntry(entry)) { |
| | | searchResultHandler = null; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | public boolean handleReference(final SearchResultReference reference) { |
| | | // FIXME: there's a potential race condition here - the future could |
| | | // get cancelled between the isDone() call and the handler |
| | | // invocation. We'd need to add support for intermediate handlers in |
| | | // the synchronizer. |
| | | if (!isDone()) { |
| | | updateTimestamp(); |
| | | if (searchResultHandler != null) { |
| | | if (!searchResultHandler.handleReference(reference)) { |
| | | searchResultHandler = null; |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPSearchFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder sb = new StringBuilder(); |
| | | sb.append("LDAPSearchFutureResultImpl("); |
| | | sb.append("request = "); |
| | | sb.append(request); |
| | | super.toString(sb); |
| | | sb.append(")"); |
| | | return sb.toString(); |
| | | } |
| | | SearchRequest getRequest() { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | SearchRequest getRequest() |
| | | { |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | Result newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newResult(resultCode).setDiagnosticMessage( |
| | | diagnosticMessage).setCause(cause); |
| | | } |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | Result newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | | return Responses.newResult(resultCode).setDiagnosticMessage(diagnosticMessage).setCause( |
| | | cause); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.OID_NOTICE_OF_DISCONNECTION; |
| | | |
| | | import java.io.IOException; |
| | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ConnectionSecurityLayer; |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.IntermediateResponseHandler; |
| | | import org.forgerock.opendj.ldap.LDAPClientContext; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.ResultHandler; |
| | | import org.forgerock.opendj.ldap.SearchResultHandler; |
| | | import org.forgerock.opendj.ldap.ServerConnection; |
| | | import org.forgerock.opendj.ldap.controls.Control; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | import org.forgerock.opendj.ldap.requests.AbandonRequest; |
| | | import org.forgerock.opendj.ldap.requests.AddRequest; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.GenericBindRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.requests.UnbindRequest; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.CompareResult; |
| | | import org.forgerock.opendj.ldap.responses.ExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.GenericExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.IntermediateResponse; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.Connection; |
| | | import org.glassfish.grizzly.Grizzly; |
| | | import org.glassfish.grizzly.attributes.Attribute; |
| | | import org.glassfish.grizzly.filterchain.*; |
| | | import org.glassfish.grizzly.filterchain.BaseFilter; |
| | | import org.glassfish.grizzly.filterchain.Filter; |
| | | import org.glassfish.grizzly.filterchain.FilterChain; |
| | | import org.glassfish.grizzly.filterchain.FilterChainBuilder; |
| | | import org.glassfish.grizzly.filterchain.FilterChainContext; |
| | | import org.glassfish.grizzly.filterchain.NextAction; |
| | | import org.glassfish.grizzly.ssl.SSLEngineConfigurator; |
| | | import org.glassfish.grizzly.ssl.SSLFilter; |
| | | import org.glassfish.grizzly.ssl.SSLUtils; |
| | |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Grizzly filter implementation for decoding LDAP requests and handling server |
| | | * side logic for SSL and SASL operations over LDAP. |
| | | */ |
| | | final class LDAPServerFilter extends BaseFilter |
| | | { |
| | | private abstract class AbstractHandler<R extends Result> implements |
| | | IntermediateResponseHandler, ResultHandler<R> |
| | | { |
| | | protected final int messageID; |
| | | protected final Connection<?> connection; |
| | | final class LDAPServerFilter extends BaseFilter { |
| | | private abstract class AbstractHandler<R extends Result> implements |
| | | IntermediateResponseHandler, ResultHandler<R> { |
| | | protected final int messageID; |
| | | protected final Connection<?> connection; |
| | | |
| | | |
| | | |
| | | protected AbstractHandler(final int messageID, |
| | | final Connection<?> connection) |
| | | { |
| | | this.messageID = messageID; |
| | | this.connection = connection; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final boolean handleIntermediateResponse( |
| | | final IntermediateResponse response) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.intermediateResponse(asn1Writer, messageID, response); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class AddHandler extends AbstractHandler<Result> |
| | | { |
| | | private AddHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.addResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class BindHandler extends AbstractHandler<BindResult> |
| | | { |
| | | private BindHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof BindResult) |
| | | { |
| | | handleResult((BindResult) result); |
| | | } |
| | | else |
| | | { |
| | | final BindResult newResult = Responses.newBindResult(result |
| | | .getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) |
| | | { |
| | | newResult.addControl(control); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final BindResult result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.bindResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class ClientContextImpl implements LDAPClientContext |
| | | { |
| | | private final Connection<?> connection; |
| | | |
| | | private volatile boolean isClosed = false; |
| | | |
| | | private ServerConnection<Integer> serverConnection = null; |
| | | |
| | | |
| | | |
| | | private ClientContextImpl(final Connection<?> connection) |
| | | { |
| | | this.connection = connection; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void disconnect() |
| | | { |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, null, null); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void disconnect(final ResultCode resultCode, final String message) |
| | | { |
| | | Validator.ensureNotNull(resultCode); |
| | | |
| | | final GenericExtendedResult notification = Responses |
| | | .newGenericExtendedResult(resultCode) |
| | | .setOID(OID_NOTICE_OF_DISCONNECTION).setDiagnosticMessage(message); |
| | | sendUnsolicitedNotification(notification); |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, resultCode, |
| | | message); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public InetSocketAddress getLocalAddress() |
| | | { |
| | | return (InetSocketAddress) connection.getLocalAddress(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public InetSocketAddress getPeerAddress() |
| | | { |
| | | return (InetSocketAddress) connection.getPeerAddress(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public int getSecurityStrengthFactor() |
| | | { |
| | | int ssf = 0; |
| | | final SSLEngine sslEngine = SSLUtils.getSSLEngine(connection); |
| | | if (sslEngine != null) |
| | | { |
| | | final String cipherString = sslEngine.getSession().getCipherSuite(); |
| | | for (final Map.Entry<String, Integer> mapEntry : CIPHER_KEY_SIZES |
| | | .entrySet()) |
| | | { |
| | | if (cipherString.indexOf(mapEntry.getKey()) >= 0) |
| | | { |
| | | ssf = mapEntry.getValue(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return ssf; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() |
| | | { |
| | | return isClosed; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void sendUnsolicitedNotification(final ExtendedResult notification) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.extendedResult(asn1Writer, 0, notification); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | LDAPServerFilter.notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void enableConnectionSecurityLayer( |
| | | final ConnectionSecurityLayer layer) |
| | | { |
| | | synchronized (this) |
| | | { |
| | | installFilter(new ConnectionSecurityLayerFilter(layer, connection |
| | | .getTransport().getMemoryManager())); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void enableTLS(final SSLContext sslContext, |
| | | final String[] protocols, final String[] suites, |
| | | final boolean wantClientAuth, final boolean needClientAuth) |
| | | { |
| | | Validator.ensureNotNull(sslContext); |
| | | synchronized (this) |
| | | { |
| | | if (isTLSEnabled()) |
| | | { |
| | | throw new IllegalStateException("TLS already enabled"); |
| | | protected AbstractHandler(final int messageID, final Connection<?> connection) { |
| | | this.messageID = messageID; |
| | | this.connection = connection; |
| | | } |
| | | |
| | | SSLEngineConfigurator sslEngineConfigurator = |
| | | new SSLEngineConfigurator(sslContext, false, false, false); |
| | | sslEngineConfigurator.setEnabledCipherSuites(suites); |
| | | sslEngineConfigurator.setEnabledProtocols(protocols); |
| | | sslEngineConfigurator.setWantClientAuth(wantClientAuth); |
| | | sslEngineConfigurator.setNeedClientAuth(needClientAuth); |
| | | installFilter(new SSLFilter(sslEngineConfigurator, null)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPClientContext("); |
| | | builder.append(getLocalAddress()); |
| | | builder.append(','); |
| | | builder.append(getPeerAddress()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | private void close() |
| | | { |
| | | isClosed = true; |
| | | } |
| | | |
| | | |
| | | |
| | | private ServerConnection<Integer> getServerConnection() |
| | | { |
| | | return serverConnection; |
| | | } |
| | | |
| | | |
| | | |
| | | private void setServerConnection( |
| | | final ServerConnection<Integer> serverConnection) |
| | | { |
| | | this.serverConnection = serverConnection; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Installs a new Grizzly filter (e.g. SSL/SASL) beneath the top-level LDAP |
| | | * filter. |
| | | * |
| | | * @param filter |
| | | * The filter to be installed. |
| | | */ |
| | | private void installFilter(final Filter filter) |
| | | { |
| | | // Determine the index where the filter should be added. |
| | | final FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); |
| | | int filterIndex = oldFilterChain.size() - 1; |
| | | if (filter instanceof SSLFilter) |
| | | { |
| | | // Beneath any ConnectionSecurityLayerFilters if present, otherwise |
| | | // beneath the LDAP filter. |
| | | for (int i = oldFilterChain.size() - 2; i >= 0; i--) |
| | | { |
| | | if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) |
| | | { |
| | | filterIndex = i + 1; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Create the new filter chain. |
| | | final FilterChain newFilterChain = FilterChainBuilder.stateless() |
| | | .addAll(oldFilterChain).add(filterIndex, filter).build(); |
| | | connection.setProcessor(newFilterChain); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether or not TLS is enabled this provided connection. |
| | | * |
| | | * @return {@code true} if TLS is enabled on this connection, otherwise |
| | | * {@code false}. |
| | | */ |
| | | private boolean isTLSEnabled() |
| | | { |
| | | synchronized (this) |
| | | { |
| | | final FilterChain currentFilterChain = (FilterChain) connection |
| | | .getProcessor(); |
| | | for (Filter filter : currentFilterChain) |
| | | { |
| | | if (filter instanceof SSLFilter) |
| | | { |
| | | @Override |
| | | public final boolean handleIntermediateResponse(final IntermediateResponse response) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.intermediateResponse(asn1Writer, messageID, response); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final class CompareHandler extends AbstractHandler<CompareResult> |
| | | { |
| | | private CompareHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof CompareResult) |
| | | { |
| | | handleResult((CompareResult) result); |
| | | } |
| | | else |
| | | { |
| | | final CompareResult newResult = Responses.newCompareResult(result |
| | | .getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) |
| | | { |
| | | newResult.addControl(control); |
| | | private final class AddHandler extends AbstractHandler<Result> { |
| | | private AddHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final CompareResult result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.compareResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class DeleteHandler extends AbstractHandler<Result> |
| | | { |
| | | private DeleteHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.deleteResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class ExtendedHandler<R extends ExtendedResult> extends |
| | | AbstractHandler<R> |
| | | { |
| | | private ExtendedHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof ExtendedResult) |
| | | { |
| | | handleResult((ExtendedResult) result); |
| | | } |
| | | else |
| | | { |
| | | final ExtendedResult newResult = Responses |
| | | .newGenericExtendedResult(result.getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) |
| | | { |
| | | newResult.addControl(control); |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.addResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class BindHandler extends AbstractHandler<BindResult> { |
| | | private BindHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof BindResult) { |
| | | handleResult((BindResult) result); |
| | | } else { |
| | | final BindResult newResult = Responses.newBindResult(result.getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) { |
| | | newResult.addControl(control); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final BindResult result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.bindResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class ClientContextImpl implements LDAPClientContext { |
| | | private final Connection<?> connection; |
| | | |
| | | private volatile boolean isClosed = false; |
| | | |
| | | private ServerConnection<Integer> serverConnection = null; |
| | | |
| | | private ClientContextImpl(final Connection<?> connection) { |
| | | this.connection = connection; |
| | | } |
| | | |
| | | @Override |
| | | public void disconnect() { |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, null, null); |
| | | } |
| | | |
| | | @Override |
| | | public void disconnect(final ResultCode resultCode, final String message) { |
| | | Validator.ensureNotNull(resultCode); |
| | | |
| | | final GenericExtendedResult notification = |
| | | Responses.newGenericExtendedResult(resultCode).setOID( |
| | | OID_NOTICE_OF_DISCONNECTION).setDiagnosticMessage(message); |
| | | sendUnsolicitedNotification(notification); |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, resultCode, message); |
| | | } |
| | | |
| | | @Override |
| | | public InetSocketAddress getLocalAddress() { |
| | | return (InetSocketAddress) connection.getLocalAddress(); |
| | | } |
| | | |
| | | @Override |
| | | public InetSocketAddress getPeerAddress() { |
| | | return (InetSocketAddress) connection.getPeerAddress(); |
| | | } |
| | | |
| | | @Override |
| | | public int getSecurityStrengthFactor() { |
| | | int ssf = 0; |
| | | final SSLEngine sslEngine = SSLUtils.getSSLEngine(connection); |
| | | if (sslEngine != null) { |
| | | final String cipherString = sslEngine.getSession().getCipherSuite(); |
| | | for (final Map.Entry<String, Integer> mapEntry : CIPHER_KEY_SIZES.entrySet()) { |
| | | if (cipherString.indexOf(mapEntry.getKey()) >= 0) { |
| | | ssf = mapEntry.getValue(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return ssf; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() { |
| | | return isClosed; |
| | | } |
| | | |
| | | @Override |
| | | public void sendUnsolicitedNotification(final ExtendedResult notification) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.extendedResult(asn1Writer, 0, notification); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | LDAPServerFilter.notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void enableConnectionSecurityLayer(final ConnectionSecurityLayer layer) { |
| | | synchronized (this) { |
| | | installFilter(new ConnectionSecurityLayerFilter(layer, connection.getTransport() |
| | | .getMemoryManager())); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void enableTLS(final SSLContext sslContext, final String[] protocols, |
| | | final String[] suites, final boolean wantClientAuth, final boolean needClientAuth) { |
| | | Validator.ensureNotNull(sslContext); |
| | | synchronized (this) { |
| | | if (isTLSEnabled()) { |
| | | throw new IllegalStateException("TLS already enabled"); |
| | | } |
| | | |
| | | SSLEngineConfigurator sslEngineConfigurator = |
| | | new SSLEngineConfigurator(sslContext, false, false, false); |
| | | sslEngineConfigurator.setEnabledCipherSuites(suites); |
| | | sslEngineConfigurator.setEnabledProtocols(protocols); |
| | | sslEngineConfigurator.setWantClientAuth(wantClientAuth); |
| | | sslEngineConfigurator.setNeedClientAuth(needClientAuth); |
| | | installFilter(new SSLFilter(sslEngineConfigurator, null)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPClientContext("); |
| | | builder.append(getLocalAddress()); |
| | | builder.append(','); |
| | | builder.append(getPeerAddress()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | private void close() { |
| | | isClosed = true; |
| | | } |
| | | |
| | | private ServerConnection<Integer> getServerConnection() { |
| | | return serverConnection; |
| | | } |
| | | |
| | | private void setServerConnection(final ServerConnection<Integer> serverConnection) { |
| | | this.serverConnection = serverConnection; |
| | | } |
| | | |
| | | /** |
| | | * Installs a new Grizzly filter (e.g. SSL/SASL) beneath the top-level |
| | | * LDAP filter. |
| | | * |
| | | * @param filter |
| | | * The filter to be installed. |
| | | */ |
| | | private void installFilter(final Filter filter) { |
| | | // Determine the index where the filter should be added. |
| | | final FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); |
| | | int filterIndex = oldFilterChain.size() - 1; |
| | | if (filter instanceof SSLFilter) { |
| | | // Beneath any ConnectionSecurityLayerFilters if present, |
| | | // otherwise |
| | | // beneath the LDAP filter. |
| | | for (int i = oldFilterChain.size() - 2; i >= 0; i--) { |
| | | if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) { |
| | | filterIndex = i + 1; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Create the new filter chain. |
| | | final FilterChain newFilterChain = |
| | | FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter) |
| | | .build(); |
| | | connection.setProcessor(newFilterChain); |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether or not TLS is enabled this provided connection. |
| | | * |
| | | * @return {@code true} if TLS is enabled on this connection, otherwise |
| | | * {@code false}. |
| | | */ |
| | | private boolean isTLSEnabled() { |
| | | synchronized (this) { |
| | | final FilterChain currentFilterChain = (FilterChain) connection.getProcessor(); |
| | | for (Filter filter : currentFilterChain) { |
| | | if (filter instanceof SSLFilter) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | private final class CompareHandler extends AbstractHandler<CompareResult> { |
| | | private CompareHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof CompareResult) { |
| | | handleResult((CompareResult) result); |
| | | } else { |
| | | final CompareResult newResult = Responses.newCompareResult(result.getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) { |
| | | newResult.addControl(control); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final CompareResult result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.compareResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class DeleteHandler extends AbstractHandler<Result> { |
| | | private DeleteHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.deleteResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class ExtendedHandler<R extends ExtendedResult> extends AbstractHandler<R> { |
| | | private ExtendedHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | final Result result = error.getResult(); |
| | | if (result instanceof ExtendedResult) { |
| | | handleResult((ExtendedResult) result); |
| | | } else { |
| | | final ExtendedResult newResult = |
| | | Responses.newGenericExtendedResult(result.getResultCode()); |
| | | newResult.setDiagnosticMessage(result.getDiagnosticMessage()); |
| | | newResult.setMatchedDN(result.getMatchedDN()); |
| | | newResult.setCause(result.getCause()); |
| | | for (final Control control : result.getControls()) { |
| | | newResult.addControl(control); |
| | | } |
| | | handleResult(newResult); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final ExtendedResult result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.extendedResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class ModifyDNHandler extends AbstractHandler<Result> { |
| | | private ModifyDNHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.modifyDNResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class ModifyHandler extends AbstractHandler<Result> { |
| | | private ModifyHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.modifyResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final class SearchHandler extends AbstractHandler<Result> implements |
| | | SearchResultHandler { |
| | | private SearchHandler(final int messageID, final Connection<?> connection) { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | @Override |
| | | public boolean handleEntry(final SearchResultEntry entry) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.searchResultEntry(asn1Writer, messageID, entry); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | @Override |
| | | public boolean handleReference(final SearchResultReference reference) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.searchResultReference(asn1Writer, messageID, reference); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try { |
| | | LDAP_WRITER.searchResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } catch (final IOException ioe) { |
| | | notifyConnectionException(connection, ioe); |
| | | } finally { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Map of cipher phrases to effective key size (bits). Taken from the |
| | | // following RFCs: 5289, 4346, 3268,4132 and 4162. |
| | | private static final Map<String, Integer> CIPHER_KEY_SIZES; |
| | | |
| | | static { |
| | | CIPHER_KEY_SIZES = new LinkedHashMap<String, Integer>(); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_256_CBC_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_256_CBC_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_256_GCM_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_3DES_EDE_CBC_", 112); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_128_GCM_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_SEED_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_128_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_128_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_IDEA_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_DES_CBC_", 56); |
| | | CIPHER_KEY_SIZES.put("_WITH_RC2_CBC_40_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_RC4_40_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_DES40_CBC_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_NULL_", 0); |
| | | } |
| | | |
| | | private static final LDAPWriter LDAP_WRITER = new LDAPWriter(); |
| | | |
| | | private static final Attribute<ClientContextImpl> LDAP_CONNECTION_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPServerConnection"); |
| | | |
| | | private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader"); |
| | | |
| | | private static void notifyConnectionClosed(final Connection<?> connection, final int messageID, |
| | | final UnbindRequest unbindRequest) { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.remove(connection); |
| | | if (clientContext != null) { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is |
| | | // invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext.getServerConnection(); |
| | | if (serverConnection != null) { |
| | | serverConnection.handleConnectionClosed(messageID, unbindRequest); |
| | | } |
| | | |
| | | // If this close was a result of an unbind request then the |
| | | // connection |
| | | // won't actually be closed yet. To avoid TIME_WAIT TCP state, let |
| | | // the |
| | | // client disconnect. |
| | | if (unbindRequest != null) { |
| | | return; |
| | | } |
| | | |
| | | // Close the connection. |
| | | try { |
| | | connection.close(); |
| | | } catch (final IOException e) { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void notifyConnectionDisconnected(final Connection<?> connection, |
| | | final ResultCode resultCode, final String message) { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.remove(connection); |
| | | if (clientContext != null) { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is |
| | | // invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext.getServerConnection(); |
| | | if (serverConnection != null) { |
| | | serverConnection.handleConnectionDisconnected(resultCode, message); |
| | | } |
| | | |
| | | // Close the connection. |
| | | try { |
| | | connection.close(); |
| | | } catch (final IOException e) { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private static void notifyConnectionException(final Connection<?> connection, |
| | | final Throwable error) { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.remove(connection); |
| | | if (clientContext != null) { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is |
| | | // invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext.getServerConnection(); |
| | | if (serverConnection != null) { |
| | | serverConnection.handleConnectionError(error); |
| | | } |
| | | |
| | | // Close the connection. |
| | | try { |
| | | connection.close(); |
| | | } catch (final IOException e) { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private final AbstractLDAPMessageHandler<FilterChainContext> serverRequestHandler = |
| | | new AbstractLDAPMessageHandler<FilterChainContext>() { |
| | | @Override |
| | | public void abandonRequest(final FilterChainContext ctx, final int messageID, |
| | | final AbandonRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | conn.handleAbandon(messageID, request); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void addRequest(final FilterChainContext ctx, final int messageID, |
| | | final AddRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final AddHandler handler = new AddHandler(messageID, ctx.getConnection()); |
| | | conn.handleAdd(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void bindRequest(final FilterChainContext ctx, final int messageID, |
| | | final int version, final GenericBindRequest bindContext) |
| | | throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final BindHandler handler = new BindHandler(messageID, ctx.getConnection()); |
| | | conn.handleBind(messageID, version, bindContext, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void compareRequest(final FilterChainContext ctx, final int messageID, |
| | | final CompareRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final CompareHandler handler = |
| | | new CompareHandler(messageID, ctx.getConnection()); |
| | | conn.handleCompare(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void deleteRequest(final FilterChainContext ctx, final int messageID, |
| | | final DeleteRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final DeleteHandler handler = |
| | | new DeleteHandler(messageID, ctx.getConnection()); |
| | | conn.handleDelete(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public <R extends ExtendedResult> void extendedRequest( |
| | | final FilterChainContext ctx, final int messageID, |
| | | final ExtendedRequest<R> request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final ExtendedHandler<R> handler = |
| | | new ExtendedHandler<R>(messageID, ctx.getConnection()); |
| | | conn.handleExtendedRequest(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void modifyDNRequest(final FilterChainContext ctx, final int messageID, |
| | | final ModifyDNRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final ModifyDNHandler handler = |
| | | new ModifyDNHandler(messageID, ctx.getConnection()); |
| | | conn.handleModifyDN(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void modifyRequest(final FilterChainContext ctx, final int messageID, |
| | | final ModifyRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final ModifyHandler handler = |
| | | new ModifyHandler(messageID, ctx.getConnection()); |
| | | conn.handleModify(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void searchRequest(final FilterChainContext ctx, final int messageID, |
| | | final SearchRequest request) throws UnexpectedRequestException { |
| | | final ClientContextImpl clientContext = |
| | | LDAP_CONNECTION_ATTR.get(ctx.getConnection()); |
| | | if (clientContext != null) { |
| | | final ServerConnection<Integer> conn = clientContext.getServerConnection(); |
| | | final SearchHandler handler = |
| | | new SearchHandler(messageID, ctx.getConnection()); |
| | | conn.handleSearch(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void unbindRequest(final FilterChainContext ctx, final int messageID, |
| | | final UnbindRequest request) { |
| | | notifyConnectionClosed(ctx.getConnection(), messageID, request); |
| | | } |
| | | |
| | | @Override |
| | | public void unrecognizedMessage(final FilterChainContext ctx, final int messageID, |
| | | final byte messageTag, final ByteString messageBytes) { |
| | | notifyConnectionException(ctx.getConnection(), new UnsupportedMessageException( |
| | | messageID, messageTag, messageBytes)); |
| | | } |
| | | }; |
| | | |
| | | private final int maxASN1ElementSize; |
| | | |
| | | private final LDAPReader ldapReader; |
| | | |
| | | private final LDAPListenerImpl listener; |
| | | |
| | | LDAPServerFilter(final LDAPListenerImpl listener, final LDAPReader ldapReader, |
| | | final int maxASN1ElementSize) { |
| | | this.listener = listener; |
| | | this.ldapReader = ldapReader; |
| | | this.maxASN1ElementSize = maxASN1ElementSize; |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final ExtendedResult result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.extendedResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | public void exceptionOccurred(final FilterChainContext ctx, final Throwable error) { |
| | | notifyConnectionException(ctx.getConnection(), error); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class ModifyDNHandler extends AbstractHandler<Result> |
| | | { |
| | | private ModifyDNHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | handleResult(error.getResult()); |
| | | public NextAction handleAccept(final FilterChainContext ctx) throws IOException { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | connection.configureBlocking(true); |
| | | try { |
| | | final ClientContextImpl clientContext = new ClientContextImpl(connection); |
| | | final ServerConnection<Integer> serverConn = |
| | | listener.getConnectionFactory().handleAccept(clientContext); |
| | | clientContext.setServerConnection(serverConn); |
| | | LDAP_CONNECTION_ATTR.set(connection, clientContext); |
| | | } catch (final ErrorResultException e) { |
| | | connection.close(); |
| | | } |
| | | |
| | | return ctx.getStopAction(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.modifyDNResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | public NextAction handleClose(final FilterChainContext ctx) throws IOException { |
| | | notifyConnectionClosed(ctx.getConnection(), -1, null); |
| | | return ctx.getStopAction(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class ModifyHandler extends AbstractHandler<Result> |
| | | { |
| | | private ModifyHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | handleResult(error.getResult()); |
| | | public NextAction handleRead(final FilterChainContext ctx) throws IOException { |
| | | final Buffer buffer = (Buffer) ctx.getMessage(); |
| | | ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR.get(ctx.getConnection()); |
| | | if (asn1Reader == null) { |
| | | asn1Reader = |
| | | new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection().getTransport() |
| | | .getMemoryManager()); |
| | | LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader); |
| | | } |
| | | asn1Reader.appendBytesRead(buffer); |
| | | |
| | | try { |
| | | while (asn1Reader.elementAvailable()) { |
| | | ldapReader.decode(asn1Reader, serverRequestHandler, ctx); |
| | | } |
| | | } finally { |
| | | asn1Reader.disposeBytesRead(); |
| | | } |
| | | |
| | | return ctx.getStopAction(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.modifyResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class SearchHandler extends AbstractHandler<Result> implements |
| | | SearchResultHandler |
| | | { |
| | | private SearchHandler(final int messageID, final Connection<?> connection) |
| | | { |
| | | super(messageID, connection); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean handleEntry(final SearchResultEntry entry) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.searchResultEntry(asn1Writer, messageID, entry); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean handleReference(final SearchResultReference reference) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.searchResultReference(asn1Writer, messageID, reference); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | return false; |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final Result result) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | | try |
| | | { |
| | | LDAP_WRITER.searchResult(asn1Writer, messageID, result); |
| | | connection.write(asn1Writer.getBuffer(), null); |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | notifyConnectionException(connection, ioe); |
| | | } |
| | | finally |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | // Map of cipher phrases to effective key size (bits). Taken from the |
| | | // following RFCs: 5289, 4346, 3268,4132 and 4162. |
| | | private static final Map<String, Integer> CIPHER_KEY_SIZES; |
| | | |
| | | static |
| | | { |
| | | CIPHER_KEY_SIZES = new LinkedHashMap<String, Integer>(); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_256_CBC_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_256_CBC_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_256_GCM_", 256); |
| | | CIPHER_KEY_SIZES.put("_WITH_3DES_EDE_CBC_", 112); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_128_GCM_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_SEED_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_CAMELLIA_128_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_AES_128_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_IDEA_CBC_", 128); |
| | | CIPHER_KEY_SIZES.put("_WITH_DES_CBC_", 56); |
| | | CIPHER_KEY_SIZES.put("_WITH_RC2_CBC_40_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_RC4_40_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_DES40_CBC_", 40); |
| | | CIPHER_KEY_SIZES.put("_WITH_NULL_", 0); |
| | | } |
| | | |
| | | private static final LDAPWriter LDAP_WRITER = new LDAPWriter(); |
| | | |
| | | private static final Attribute<ClientContextImpl> LDAP_CONNECTION_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPServerConnection"); |
| | | |
| | | private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader"); |
| | | |
| | | |
| | | |
| | | private static void notifyConnectionClosed(final Connection<?> connection, |
| | | final int messageID, final UnbindRequest unbindRequest) |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR |
| | | .remove(connection); |
| | | if (clientContext != null) |
| | | { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext |
| | | .getServerConnection(); |
| | | if (serverConnection != null) |
| | | { |
| | | serverConnection.handleConnectionClosed(messageID, unbindRequest); |
| | | } |
| | | |
| | | // If this close was a result of an unbind request then the connection |
| | | // won't actually be closed yet. To avoid TIME_WAIT TCP state, let the |
| | | // client disconnect. |
| | | if (unbindRequest != null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // Close the connection. |
| | | try |
| | | { |
| | | connection.close(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static void notifyConnectionDisconnected( |
| | | final Connection<?> connection, final ResultCode resultCode, |
| | | final String message) |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR |
| | | .remove(connection); |
| | | if (clientContext != null) |
| | | { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext |
| | | .getServerConnection(); |
| | | if (serverConnection != null) |
| | | { |
| | | serverConnection.handleConnectionDisconnected(resultCode, message); |
| | | } |
| | | |
| | | // Close the connection. |
| | | try |
| | | { |
| | | connection.close(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static void notifyConnectionException(final Connection<?> connection, |
| | | final Throwable error) |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR |
| | | .remove(connection); |
| | | if (clientContext != null) |
| | | { |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is invoked |
| | | // during accept. |
| | | final ServerConnection<Integer> serverConnection = clientContext |
| | | .getServerConnection(); |
| | | if (serverConnection != null) |
| | | { |
| | | serverConnection.handleConnectionError(error); |
| | | } |
| | | |
| | | // Close the connection. |
| | | try |
| | | { |
| | | connection.close(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | StaticUtils.DEBUG_LOG.warning("Error closing connection: " + e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final AbstractLDAPMessageHandler<FilterChainContext> serverRequestHandler = |
| | | new AbstractLDAPMessageHandler<FilterChainContext>() |
| | | { |
| | | @Override |
| | | public void abandonRequest(final FilterChainContext ctx, |
| | | final int messageID, final AbandonRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | conn.handleAbandon(messageID, request); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void addRequest(final FilterChainContext ctx, final int messageID, |
| | | final AddRequest request) throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final AddHandler handler = new AddHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleAdd(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void bindRequest(final FilterChainContext ctx, final int messageID, |
| | | final int version, final GenericBindRequest bindContext) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final BindHandler handler = new BindHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleBind(messageID, version, bindContext, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void compareRequest(final FilterChainContext ctx, |
| | | final int messageID, final CompareRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final CompareHandler handler = new CompareHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleCompare(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void deleteRequest(final FilterChainContext ctx, |
| | | final int messageID, final DeleteRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final DeleteHandler handler = new DeleteHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleDelete(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public <R extends ExtendedResult> void extendedRequest( |
| | | final FilterChainContext ctx, final int messageID, |
| | | final ExtendedRequest<R> request) throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final ExtendedHandler<R> handler = new ExtendedHandler<R>(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleExtendedRequest(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void modifyDNRequest(final FilterChainContext ctx, |
| | | final int messageID, final ModifyDNRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final ModifyDNHandler handler = new ModifyDNHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleModifyDN(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void modifyRequest(final FilterChainContext ctx, |
| | | final int messageID, final ModifyRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final ModifyHandler handler = new ModifyHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleModify(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void searchRequest(final FilterChainContext ctx, |
| | | final int messageID, final SearchRequest request) |
| | | throws UnexpectedRequestException |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx |
| | | .getConnection()); |
| | | if (clientContext != null) |
| | | { |
| | | final ServerConnection<Integer> conn = clientContext |
| | | .getServerConnection(); |
| | | final SearchHandler handler = new SearchHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleSearch(messageID, request, handler, handler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void unbindRequest(final FilterChainContext ctx, |
| | | final int messageID, final UnbindRequest request) |
| | | { |
| | | notifyConnectionClosed(ctx.getConnection(), messageID, request); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void unrecognizedMessage(final FilterChainContext ctx, |
| | | final int messageID, final byte messageTag, |
| | | final ByteString messageBytes) |
| | | { |
| | | notifyConnectionException(ctx.getConnection(), |
| | | new UnsupportedMessageException(messageID, messageTag, messageBytes)); |
| | | } |
| | | }; |
| | | |
| | | private final int maxASN1ElementSize; |
| | | |
| | | private final LDAPReader ldapReader; |
| | | |
| | | private final LDAPListenerImpl listener; |
| | | |
| | | |
| | | |
| | | LDAPServerFilter(final LDAPListenerImpl listener, |
| | | final LDAPReader ldapReader, final int maxASN1ElementSize) |
| | | { |
| | | this.listener = listener; |
| | | this.ldapReader = ldapReader; |
| | | this.maxASN1ElementSize = maxASN1ElementSize; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void exceptionOccurred(final FilterChainContext ctx, |
| | | final Throwable error) |
| | | { |
| | | notifyConnectionException(ctx.getConnection(), error); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public NextAction handleAccept(final FilterChainContext ctx) |
| | | throws IOException |
| | | { |
| | | final Connection<?> connection = ctx.getConnection(); |
| | | connection.configureBlocking(true); |
| | | try |
| | | { |
| | | final ClientContextImpl clientContext = new ClientContextImpl(connection); |
| | | final ServerConnection<Integer> serverConn = listener |
| | | .getConnectionFactory().handleAccept(clientContext); |
| | | clientContext.setServerConnection(serverConn); |
| | | LDAP_CONNECTION_ATTR.set(connection, clientContext); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | connection.close(); |
| | | } |
| | | |
| | | return ctx.getStopAction(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public NextAction handleClose(final FilterChainContext ctx) |
| | | throws IOException |
| | | { |
| | | notifyConnectionClosed(ctx.getConnection(), -1, null); |
| | | return ctx.getStopAction(); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public NextAction handleRead(final FilterChainContext ctx) throws IOException |
| | | { |
| | | final Buffer buffer = (Buffer) ctx.getMessage(); |
| | | ASN1BufferReader asn1Reader = LDAP_ASN1_READER_ATTR |
| | | .get(ctx.getConnection()); |
| | | if (asn1Reader == null) |
| | | { |
| | | asn1Reader = new ASN1BufferReader(maxASN1ElementSize, ctx.getConnection() |
| | | .getTransport().getMemoryManager()); |
| | | LDAP_ASN1_READER_ATTR.set(ctx.getConnection(), asn1Reader); |
| | | } |
| | | asn1Reader.appendBytesRead(buffer); |
| | | |
| | | try |
| | | { |
| | | while (asn1Reader.elementAvailable()) |
| | | { |
| | | ldapReader.decode(asn1Reader, serverRequestHandler, ctx); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | asn1Reader.disposeBytesRead(); |
| | | } |
| | | |
| | | return ctx.getStopAction(); |
| | | } |
| | | } |
| | |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt |
| | | * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt |
| | | * or http://forgerock.org/license/CDDLv1.0.html. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * file and include the License file at legal-notices/CDDLv1_0.txt. |
| | | * If applicable, add the following below this CDDL HEADER, with the |
| | | * fields enclosed by brackets "[]" replaced with your own identifying |
| | | * information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | |
| | | |
| | | package com.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static com.forgerock.opendj.ldap.LDAPConstants.*; |
| | | |
| | | import java.io.IOException; |
| | |
| | | |
| | | import org.forgerock.opendj.asn1.ASN1Reader; |
| | | import org.forgerock.opendj.asn1.ASN1Writer; |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeOptions; |
| | | import org.forgerock.opendj.ldap.Filter; |
| | | import org.forgerock.opendj.ldap.FilterVisitor; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Common LDAP utility methods which may be used when implementing new controls |
| | | * and extension. |
| | | */ |
| | | public final class LDAPUtils |
| | | { |
| | | public final class LDAPUtils { |
| | | |
| | | private static final FilterVisitor<IOException, ASN1Writer> ASN1_ENCODER = |
| | | new FilterVisitor<IOException, ASN1Writer>() |
| | | { |
| | | private static final FilterVisitor<IOException, ASN1Writer> ASN1_ENCODER = |
| | | new FilterVisitor<IOException, ASN1Writer>() { |
| | | |
| | | public IOException visitAndFilter(final ASN1Writer writer, |
| | | final List<Filter> subFilters) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_AND); |
| | | for (final Filter subFilter : subFilters) |
| | | { |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) |
| | | { |
| | | return e; |
| | | } |
| | | public IOException visitAndFilter(final ASN1Writer writer, |
| | | final List<Filter> subFilters) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_AND); |
| | | for (final Filter subFilter : subFilters) { |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) { |
| | | return e; |
| | | } |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitApproxMatchFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_APPROXIMATE); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitEqualityMatchFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_EQUALITY); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitExtensibleMatchFilter(final ASN1Writer writer, |
| | | final String matchingRule, final String attributeDescription, |
| | | final ByteString assertionValue, final boolean dnAttributes) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH); |
| | | |
| | | if (matchingRule != null) { |
| | | writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRule); |
| | | } |
| | | |
| | | if (attributeDescription != null) { |
| | | writer.writeOctetString(TYPE_MATCHING_RULE_TYPE, attributeDescription); |
| | | } |
| | | |
| | | writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, assertionValue); |
| | | |
| | | if (dnAttributes) { |
| | | writer.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true); |
| | | } |
| | | |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitGreaterOrEqualFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_GREATER_OR_EQUAL); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitLessOrEqualFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_LESS_OR_EQUAL); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitNotFilter(final ASN1Writer writer, final Filter subFilter) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_NOT); |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) { |
| | | return e; |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitOrFilter(final ASN1Writer writer, |
| | | final List<Filter> subFilters) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_OR); |
| | | for (final Filter subFilter : subFilters) { |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) { |
| | | return e; |
| | | } |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitPresentFilter(final ASN1Writer writer, |
| | | final String attributeDescription) { |
| | | try { |
| | | writer.writeOctetString(TYPE_FILTER_PRESENCE, attributeDescription); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitSubstringsFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString initialSubstring, |
| | | final List<ByteString> anySubstrings, final ByteString finalSubstring) { |
| | | try { |
| | | writer.writeStartSequence(TYPE_FILTER_SUBSTRING); |
| | | writer.writeOctetString(attributeDescription); |
| | | |
| | | writer.writeStartSequence(); |
| | | if (initialSubstring != null) { |
| | | writer.writeOctetString(TYPE_SUBINITIAL, initialSubstring); |
| | | } |
| | | |
| | | for (final ByteSequence anySubstring : anySubstrings) { |
| | | writer.writeOctetString(TYPE_SUBANY, anySubstring); |
| | | } |
| | | |
| | | if (finalSubstring != null) { |
| | | writer.writeOctetString(TYPE_SUBFINAL, finalSubstring); |
| | | } |
| | | writer.writeEndSequence(); |
| | | |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | public IOException visitUnrecognizedFilter(final ASN1Writer writer, |
| | | final byte filterTag, final ByteString filterBytes) { |
| | | try { |
| | | writer.writeOctetString(filterTag, filterBytes); |
| | | return null; |
| | | } catch (final IOException e) { |
| | | return e; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a |
| | | * {@code Filter}. |
| | | * |
| | | * @param reader |
| | | * The {@code ASN1Reader} from which the ASN.1 encoded |
| | | * {@code Filter} should be read. |
| | | * @return The decoded {@code Filter}. |
| | | * @throws IOException |
| | | * If an error occurs while reading from {@code reader}. |
| | | */ |
| | | public static Filter decodeFilter(final ASN1Reader reader) throws IOException { |
| | | final byte type = reader.peekType(); |
| | | |
| | | switch (type) { |
| | | case TYPE_FILTER_AND: |
| | | return decodeAndFilter(reader); |
| | | |
| | | case TYPE_FILTER_OR: |
| | | return decodeOrFilter(reader); |
| | | |
| | | case TYPE_FILTER_NOT: |
| | | return decodeNotFilter(reader); |
| | | |
| | | case TYPE_FILTER_EQUALITY: |
| | | return decodeEqualityMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_GREATER_OR_EQUAL: |
| | | return decodeGreaterOrEqualMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_LESS_OR_EQUAL: |
| | | return decodeLessOrEqualMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_APPROXIMATE: |
| | | return decodeApproxMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_SUBSTRING: |
| | | return decodeSubstringsFilter(reader); |
| | | |
| | | case TYPE_FILTER_PRESENCE: |
| | | return Filter.newPresentFilter(reader.readOctetStringAsString(type)); |
| | | |
| | | case TYPE_FILTER_EXTENSIBLE_MATCH: |
| | | return decodeExtensibleMatchFilter(reader); |
| | | |
| | | default: |
| | | return Filter.newUnrecognizedFilter(type, reader.readOctetString(type)); |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitApproxMatchFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_APPROXIMATE); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | /** |
| | | * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a |
| | | * {@code SearchResultEntry}. |
| | | * |
| | | * @param reader |
| | | * The {@code ASN1Reader} from which the ASN.1 encoded |
| | | * {@code SearchResultEntry} should be read. |
| | | * @param options |
| | | * The decode options to use when decoding the entry. |
| | | * @return The decoded {@code SearchResultEntry}. |
| | | * @throws IOException |
| | | * If an error occurs while reading from {@code reader}. |
| | | */ |
| | | public static SearchResultEntry decodeSearchResultEntry(final ASN1Reader reader, |
| | | final DecodeOptions options) throws IOException { |
| | | return LDAPReader.decodeEntry(reader, options); |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitEqualityMatchFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_EQUALITY); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | /** |
| | | * Writes the ASN.1 encoding of the provided {@code Filter} to the provided |
| | | * {@code ASN1Writer}. |
| | | * |
| | | * @param writer |
| | | * The {@code ASN1Writer} to which the ASN.1 encoding of the |
| | | * provided {@code Filter} should be written. |
| | | * @param filter |
| | | * The filter to be encoded. |
| | | * @return The updated {@code ASN1Writer}. |
| | | * @throws IOException |
| | | * If an error occurs while writing to {@code writer}. |
| | | */ |
| | | public static ASN1Writer encodeFilter(final ASN1Writer writer, final Filter filter) |
| | | throws IOException { |
| | | final IOException e = filter.accept(ASN1_ENCODER, writer); |
| | | if (e != null) { |
| | | throw e; |
| | | } else { |
| | | return writer; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Writes the ASN.1 encoding of the provided {@code SearchResultEntry} to |
| | | * the provided {@code ASN1Writer}. |
| | | * |
| | | * @param writer |
| | | * The {@code ASN1Writer} to which the ASN.1 encoding of the |
| | | * provided {@code SearchResultEntry} should be written. |
| | | * @param entry |
| | | * The Search Result Entry to be encoded. |
| | | * @return The updated {@code ASN1Writer}. |
| | | * @throws IOException |
| | | * If an error occurs while writing to {@code writer}. |
| | | */ |
| | | public static ASN1Writer encodeSearchResultEntry(final ASN1Writer writer, |
| | | final SearchResultEntry entry) throws IOException { |
| | | // FIXME: this should include Controls. |
| | | LDAPWriter.encodeEntry(writer, entry); |
| | | return writer; |
| | | } |
| | | |
| | | // Decodes an and filter. |
| | | private static Filter decodeAndFilter(final ASN1Reader reader) throws IOException { |
| | | Filter filter; |
| | | |
| | | public IOException visitExtensibleMatchFilter(final ASN1Writer writer, |
| | | final String matchingRule, final String attributeDescription, |
| | | final ByteString assertionValue, final boolean dnAttributes) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH); |
| | | |
| | | if (matchingRule != null) |
| | | { |
| | | writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRule); |
| | | reader.readStartSequence(TYPE_FILTER_AND); |
| | | try { |
| | | if (reader.hasNextElement()) { |
| | | final List<Filter> subFilters = new LinkedList<Filter>(); |
| | | do { |
| | | subFilters.add(decodeFilter(reader)); |
| | | } while (reader.hasNextElement()); |
| | | filter = Filter.newAndFilter(subFilters); |
| | | } else { |
| | | // No sub-filters - this is an RFC 4526 absolute true filter. |
| | | filter = Filter.getAbsoluteTrueFilter(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | if (attributeDescription != null) |
| | | { |
| | | writer |
| | | .writeOctetString(TYPE_MATCHING_RULE_TYPE, attributeDescription); |
| | | return filter; |
| | | } |
| | | |
| | | // Decodes an approximate match filter. |
| | | private static Filter decodeApproxMatchFilter(final ASN1Reader reader) throws IOException { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_APPROXIMATE); |
| | | try { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, assertionValue); |
| | | return Filter.newApproxMatchFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | if (dnAttributes) |
| | | { |
| | | writer.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true); |
| | | // Decodes an equality match filter. |
| | | private static Filter decodeEqualityMatchFilter(final ASN1Reader reader) throws IOException { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_EQUALITY); |
| | | try { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | return Filter.newEqualityMatchFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | // Decodes an extensible match filter. |
| | | private static Filter decodeExtensibleMatchFilter(final ASN1Reader reader) throws IOException { |
| | | String matchingRule; |
| | | String attributeDescription; |
| | | boolean dnAttributes; |
| | | ByteString assertionValue; |
| | | |
| | | |
| | | public IOException visitGreaterOrEqualFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_GREATER_OR_EQUAL); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitLessOrEqualFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString assertionValue) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_LESS_OR_EQUAL); |
| | | writer.writeOctetString(attributeDescription); |
| | | writer.writeOctetString(assertionValue); |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitNotFilter(final ASN1Writer writer, |
| | | final Filter subFilter) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_NOT); |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) |
| | | { |
| | | return e; |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitOrFilter(final ASN1Writer writer, |
| | | final List<Filter> subFilters) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_OR); |
| | | for (final Filter subFilter : subFilters) |
| | | { |
| | | final IOException e = subFilter.accept(this, writer); |
| | | if (e != null) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitPresentFilter(final ASN1Writer writer, |
| | | final String attributeDescription) |
| | | { |
| | | try |
| | | { |
| | | writer.writeOctetString(TYPE_FILTER_PRESENCE, attributeDescription); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public IOException visitSubstringsFilter(final ASN1Writer writer, |
| | | final String attributeDescription, final ByteString initialSubstring, |
| | | final List<ByteString> anySubstrings, final ByteString finalSubstring) |
| | | { |
| | | try |
| | | { |
| | | writer.writeStartSequence(TYPE_FILTER_SUBSTRING); |
| | | writer.writeOctetString(attributeDescription); |
| | | |
| | | writer.writeStartSequence(); |
| | | if (initialSubstring != null) |
| | | { |
| | | writer.writeOctetString(TYPE_SUBINITIAL, initialSubstring); |
| | | reader.readStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH); |
| | | try { |
| | | matchingRule = null; |
| | | if (reader.peekType() == TYPE_MATCHING_RULE_ID) { |
| | | matchingRule = reader.readOctetStringAsString(TYPE_MATCHING_RULE_ID); |
| | | } |
| | | attributeDescription = null; |
| | | if (reader.peekType() == TYPE_MATCHING_RULE_TYPE) { |
| | | attributeDescription = reader.readOctetStringAsString(TYPE_MATCHING_RULE_TYPE); |
| | | } |
| | | dnAttributes = false; |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_MATCHING_RULE_DN_ATTRIBUTES)) { |
| | | dnAttributes = reader.readBoolean(); |
| | | } |
| | | assertionValue = reader.readOctetString(TYPE_MATCHING_RULE_VALUE); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | for (final ByteSequence anySubstring : anySubstrings) |
| | | { |
| | | writer.writeOctetString(TYPE_SUBANY, anySubstring); |
| | | return Filter.newExtensibleMatchFilter(matchingRule, attributeDescription, assertionValue, |
| | | dnAttributes); |
| | | } |
| | | |
| | | // Decodes a greater than or equal filter. |
| | | private static Filter decodeGreaterOrEqualMatchFilter(final ASN1Reader reader) |
| | | throws IOException { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_GREATER_OR_EQUAL); |
| | | try { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | return Filter.newGreaterOrEqualFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | // Decodes a less than or equal filter. |
| | | private static Filter decodeLessOrEqualMatchFilter(final ASN1Reader reader) throws IOException { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_LESS_OR_EQUAL); |
| | | try { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | if (finalSubstring != null) |
| | | { |
| | | writer.writeOctetString(TYPE_SUBFINAL, finalSubstring); |
| | | return Filter.newLessOrEqualFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | // Decodes a not filter. |
| | | private static Filter decodeNotFilter(final ASN1Reader reader) throws IOException { |
| | | Filter subFilter; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_NOT); |
| | | try { |
| | | subFilter = decodeFilter(reader); |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | writer.writeEndSequence(); |
| | | |
| | | writer.writeEndSequence(); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | return Filter.newNotFilter(subFilter); |
| | | } |
| | | |
| | | // Decodes an or filter. |
| | | private static Filter decodeOrFilter(final ASN1Reader reader) throws IOException { |
| | | Filter filter; |
| | | |
| | | |
| | | public IOException visitUnrecognizedFilter(final ASN1Writer writer, |
| | | final byte filterTag, final ByteString filterBytes) |
| | | { |
| | | try |
| | | { |
| | | writer.writeOctetString(filterTag, filterBytes); |
| | | return null; |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | return e; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a |
| | | * {@code Filter}. |
| | | * |
| | | * @param reader |
| | | * The {@code ASN1Reader} from which the ASN.1 encoded {@code Filter} |
| | | * should be read. |
| | | * @return The decoded {@code Filter}. |
| | | * @throws IOException |
| | | * If an error occurs while reading from {@code reader}. |
| | | */ |
| | | public static Filter decodeFilter(final ASN1Reader reader) throws IOException |
| | | { |
| | | final byte type = reader.peekType(); |
| | | |
| | | switch (type) |
| | | { |
| | | case TYPE_FILTER_AND: |
| | | return decodeAndFilter(reader); |
| | | |
| | | case TYPE_FILTER_OR: |
| | | return decodeOrFilter(reader); |
| | | |
| | | case TYPE_FILTER_NOT: |
| | | return decodeNotFilter(reader); |
| | | |
| | | case TYPE_FILTER_EQUALITY: |
| | | return decodeEqualityMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_GREATER_OR_EQUAL: |
| | | return decodeGreaterOrEqualMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_LESS_OR_EQUAL: |
| | | return decodeLessOrEqualMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_APPROXIMATE: |
| | | return decodeApproxMatchFilter(reader); |
| | | |
| | | case TYPE_FILTER_SUBSTRING: |
| | | return decodeSubstringsFilter(reader); |
| | | |
| | | case TYPE_FILTER_PRESENCE: |
| | | return Filter.newPresentFilter(reader.readOctetStringAsString(type)); |
| | | |
| | | case TYPE_FILTER_EXTENSIBLE_MATCH: |
| | | return decodeExtensibleMatchFilter(reader); |
| | | |
| | | default: |
| | | return Filter.newUnrecognizedFilter(type, reader.readOctetString(type)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a |
| | | * {@code SearchResultEntry}. |
| | | * |
| | | * @param reader |
| | | * The {@code ASN1Reader} from which the ASN.1 encoded {@code |
| | | * SearchResultEntry} should be read. |
| | | * @param options |
| | | * The decode options to use when decoding the entry. |
| | | * @return The decoded {@code SearchResultEntry}. |
| | | * @throws IOException |
| | | * If an error occurs while reading from {@code reader}. |
| | | */ |
| | | public static SearchResultEntry decodeSearchResultEntry( |
| | | final ASN1Reader reader, final DecodeOptions options) throws IOException |
| | | { |
| | | return LDAPReader.decodeEntry(reader, options); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Writes the ASN.1 encoding of the provided {@code Filter} to the provided |
| | | * {@code ASN1Writer}. |
| | | * |
| | | * @param writer |
| | | * The {@code ASN1Writer} to which the ASN.1 encoding of the provided |
| | | * {@code Filter} should be written. |
| | | * @param filter |
| | | * The filter to be encoded. |
| | | * @return The updated {@code ASN1Writer}. |
| | | * @throws IOException |
| | | * If an error occurs while writing to {@code writer}. |
| | | */ |
| | | public static ASN1Writer encodeFilter(final ASN1Writer writer, |
| | | final Filter filter) throws IOException |
| | | { |
| | | final IOException e = filter.accept(ASN1_ENCODER, writer); |
| | | if (e != null) |
| | | { |
| | | throw e; |
| | | } |
| | | else |
| | | { |
| | | return writer; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Writes the ASN.1 encoding of the provided {@code SearchResultEntry} to the |
| | | * provided {@code ASN1Writer}. |
| | | * |
| | | * @param writer |
| | | * The {@code ASN1Writer} to which the ASN.1 encoding of the provided |
| | | * {@code SearchResultEntry} should be written. |
| | | * @param entry |
| | | * The Search Result Entry to be encoded. |
| | | * @return The updated {@code ASN1Writer}. |
| | | * @throws IOException |
| | | * If an error occurs while writing to {@code writer}. |
| | | */ |
| | | public static ASN1Writer encodeSearchResultEntry(final ASN1Writer writer, |
| | | final SearchResultEntry entry) throws IOException |
| | | { |
| | | // FIXME: this should include Controls. |
| | | LDAPWriter.encodeEntry(writer, entry); |
| | | return writer; |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes an and filter. |
| | | private static Filter decodeAndFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | Filter filter; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_AND); |
| | | try |
| | | { |
| | | if (reader.hasNextElement()) |
| | | { |
| | | final List<Filter> subFilters = new LinkedList<Filter>(); |
| | | do |
| | | { |
| | | subFilters.add(decodeFilter(reader)); |
| | | reader.readStartSequence(TYPE_FILTER_OR); |
| | | try { |
| | | if (reader.hasNextElement()) { |
| | | final List<Filter> subFilters = new LinkedList<Filter>(); |
| | | do { |
| | | subFilters.add(decodeFilter(reader)); |
| | | } while (reader.hasNextElement()); |
| | | filter = Filter.newOrFilter(subFilters); |
| | | } else { |
| | | // No sub-filters - this is an RFC 4526 absolute false filter. |
| | | filter = Filter.getAbsoluteFalseFilter(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | while (reader.hasNextElement()); |
| | | filter = Filter.newAndFilter(subFilters); |
| | | } |
| | | else |
| | | { |
| | | // No sub-filters - this is an RFC 4526 absolute true filter. |
| | | filter = Filter.getAbsoluteTrueFilter(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | |
| | | return filter; |
| | | } |
| | | |
| | | return filter; |
| | | } |
| | | // Decodes a sub-strings filter. |
| | | private static Filter decodeSubstringsFilter(final ASN1Reader reader) throws IOException { |
| | | ByteString initialSubstring = null; |
| | | List<ByteString> anySubstrings = null; |
| | | ByteString finalSubstring = null; |
| | | String attributeDescription; |
| | | |
| | | |
| | | |
| | | // Decodes an approximate match filter. |
| | | private static Filter decodeApproxMatchFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_APPROXIMATE); |
| | | try |
| | | { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Filter.newApproxMatchFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes an equality match filter. |
| | | private static Filter decodeEqualityMatchFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_EQUALITY); |
| | | try |
| | | { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Filter.newEqualityMatchFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes an extensible match filter. |
| | | private static Filter decodeExtensibleMatchFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | String matchingRule; |
| | | String attributeDescription; |
| | | boolean dnAttributes; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_EXTENSIBLE_MATCH); |
| | | try |
| | | { |
| | | matchingRule = null; |
| | | if (reader.peekType() == TYPE_MATCHING_RULE_ID) |
| | | { |
| | | matchingRule = reader.readOctetStringAsString(TYPE_MATCHING_RULE_ID); |
| | | } |
| | | attributeDescription = null; |
| | | if (reader.peekType() == TYPE_MATCHING_RULE_TYPE) |
| | | { |
| | | attributeDescription = reader |
| | | .readOctetStringAsString(TYPE_MATCHING_RULE_TYPE); |
| | | } |
| | | dnAttributes = false; |
| | | if (reader.hasNextElement() |
| | | && (reader.peekType() == TYPE_MATCHING_RULE_DN_ATTRIBUTES)) |
| | | { |
| | | dnAttributes = reader.readBoolean(); |
| | | } |
| | | assertionValue = reader.readOctetString(TYPE_MATCHING_RULE_VALUE); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Filter.newExtensibleMatchFilter(matchingRule, attributeDescription, |
| | | assertionValue, dnAttributes); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes a greater than or equal filter. |
| | | private static Filter decodeGreaterOrEqualMatchFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_GREATER_OR_EQUAL); |
| | | try |
| | | { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | return Filter.newGreaterOrEqualFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes a less than or equal filter. |
| | | private static Filter decodeLessOrEqualMatchFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | String attributeDescription; |
| | | ByteString assertionValue; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_LESS_OR_EQUAL); |
| | | try |
| | | { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | assertionValue = reader.readOctetString(); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Filter.newLessOrEqualFilter(attributeDescription, assertionValue); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes a not filter. |
| | | private static Filter decodeNotFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | Filter subFilter; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_NOT); |
| | | try |
| | | { |
| | | subFilter = decodeFilter(reader); |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return Filter.newNotFilter(subFilter); |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes an or filter. |
| | | private static Filter decodeOrFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | Filter filter; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_OR); |
| | | try |
| | | { |
| | | if (reader.hasNextElement()) |
| | | { |
| | | final List<Filter> subFilters = new LinkedList<Filter>(); |
| | | do |
| | | { |
| | | subFilters.add(decodeFilter(reader)); |
| | | reader.readStartSequence(TYPE_FILTER_SUBSTRING); |
| | | try { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | reader.readStartSequence(); |
| | | try { |
| | | // FIXME: There should be at least one element in this substring |
| | | // filter sequence. |
| | | if (reader.peekType() == TYPE_SUBINITIAL) { |
| | | initialSubstring = reader.readOctetString(TYPE_SUBINITIAL); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY)) { |
| | | anySubstrings = new LinkedList<ByteString>(); |
| | | do { |
| | | anySubstrings.add(reader.readOctetString(TYPE_SUBANY)); |
| | | } while (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY)); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBFINAL)) { |
| | | finalSubstring = reader.readOctetString(TYPE_SUBFINAL); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | } finally { |
| | | reader.readEndSequence(); |
| | | } |
| | | while (reader.hasNextElement()); |
| | | filter = Filter.newOrFilter(subFilters); |
| | | } |
| | | else |
| | | { |
| | | // No sub-filters - this is an RFC 4526 absolute false filter. |
| | | filter = Filter.getAbsoluteFalseFilter(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | |
| | | return filter; |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes a sub-strings filter. |
| | | private static Filter decodeSubstringsFilter(final ASN1Reader reader) |
| | | throws IOException |
| | | { |
| | | ByteString initialSubstring = null; |
| | | List<ByteString> anySubstrings = null; |
| | | ByteString finalSubstring = null; |
| | | String attributeDescription; |
| | | |
| | | reader.readStartSequence(TYPE_FILTER_SUBSTRING); |
| | | try |
| | | { |
| | | attributeDescription = reader.readOctetStringAsString(); |
| | | reader.readStartSequence(); |
| | | try |
| | | { |
| | | // FIXME: There should be at least one element in this substring |
| | | // filter sequence. |
| | | if (reader.peekType() == TYPE_SUBINITIAL) |
| | | { |
| | | initialSubstring = reader.readOctetString(TYPE_SUBINITIAL); |
| | | if (anySubstrings == null) { |
| | | anySubstrings = Collections.emptyList(); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY)) |
| | | { |
| | | anySubstrings = new LinkedList<ByteString>(); |
| | | do |
| | | { |
| | | anySubstrings.add(reader.readOctetString(TYPE_SUBANY)); |
| | | } |
| | | while (reader.hasNextElement() && (reader.peekType() == TYPE_SUBANY)); |
| | | } |
| | | if (reader.hasNextElement() && (reader.peekType() == TYPE_SUBFINAL)) |
| | | { |
| | | finalSubstring = reader.readOctetString(TYPE_SUBFINAL); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | reader.readEndSequence(); |
| | | |
| | | return Filter.newSubstringsFilter(attributeDescription, initialSubstring, anySubstrings, |
| | | finalSubstring); |
| | | } |
| | | |
| | | if (anySubstrings == null) |
| | | { |
| | | anySubstrings = Collections.emptyList(); |
| | | /** |
| | | * Prevent instantiation. |
| | | */ |
| | | private LDAPUtils() { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | return Filter.newSubstringsFilter(attributeDescription, initialSubstring, |
| | | anySubstrings, finalSubstring); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Prevent instantiation. |
| | | */ |
| | | private LDAPUtils() |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | } |
| opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPWriter.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/TimeoutChecker.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/UnexpectedRequestException.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/UnexpectedResponseException.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/UnsupportedMessageException.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/controls/AccountUsabilityRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/controls/AccountUsabilityResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/controls/RealAttributesOnlyRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/controls/VirtualAttributesOnlyRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/controls/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/GetConnectionIDExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/GetConnectionIDExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/GetSymmetricKeyExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/PasswordPolicyStateExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/PasswordPolicyStateExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/PasswordPolicyStateOperation.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/PasswordPolicyStateOperationContainer.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/PasswordPolicyStateOperationType.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/extensions/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/AsynchronousFutureResult.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Base64.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ByteSequenceOutputStream.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Collections2.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/CompletedFutureResult.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ConnectionDecorator.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Function.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Functions.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/FutureResultTransformer.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterators.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Predicate.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/RecursiveFutureResult.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/SizeLimitInputStream.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StringPrepProfile.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/SubstringReader.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Validator.java
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1ByteSequenceReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1Constants.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1InputStreamReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1OutputStreamWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1Reader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/ASN1Writer.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/AbstractASN1Reader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/AbstractASN1Writer.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/asn1/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AVA.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractAttribute.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractFilterVisitor.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Assertion.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AssertionFailureException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attribute.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AuthenticationException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AuthorizationException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteSequence.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteSequenceReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteString.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/CancelRequestListener.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/CancelledResultException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConditionResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connection.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionEventListener.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionSecurityLayer.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Connections.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConstraintViolationException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DecodeException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DecodeOptions.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DereferenceAliasesPolicy.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/EntryFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/EntryNotFoundException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ErrorResultException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ErrorResultIOException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/FailoverLoadBalancingAlgorithm.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Filter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/FilterVisitor.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/FixedConnectionPool.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/FutureResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/IntermediateResponseHandler.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/KeyManagers.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListener.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPUrl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LinkedAttribute.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LinkedHashMapEntry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LoadBalancingAlgorithm.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Matcher.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Modification.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ModificationType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MultipleEntriesFoundException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RDN.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ReferralException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RequestContext.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ResultCode.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/RoundRobinLoadBalancingAlgorithm.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SSLContextBuilder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SchemaResolver.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SearchResultReferenceIOException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SearchScope.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ServerConnection.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ServerConnectionFactory.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/SortKey.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/TimeoutResultException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/TreeMapEntry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/TrustManagers.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/AssertionRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/AuthorizationIdentityRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/AuthorizationIdentityResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/Control.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ControlDecoder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/EntryChangeNotificationResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/GenericControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/GetEffectiveRightsRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ManageDsaITRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/MatchedValuesRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordExpiredResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordExpiringResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordPolicyErrorType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordPolicyRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordPolicyResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PasswordPolicyWarningType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PermissiveModifyRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PersistentSearchChangeType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PersistentSearchRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PostReadRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PostReadResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PreReadRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/PreReadResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ProxiedAuthV1RequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ProxiedAuthV2RequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ServerSideSortRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/ServerSideSortResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/SimplePagedResultsControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/SubentriesRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/SubtreeDeleteRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/VirtualListViewRequestControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/VirtualListViewResponseControl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/controls/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbandonRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbandonRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractSASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractUnmodifiableBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractUnmodifiableExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractUnmodifiableRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AbstractUnmodifiableSASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AddRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AddRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AnonymousSASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/AnonymousSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/BindClient.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/BindClientImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/BindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CRAMMD5SASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CRAMMD5SASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CancelExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CancelExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CompareRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/CompareRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/DeleteRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/DeleteRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/DigestMD5SASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/DigestMD5SASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ExtendedRequestDecoder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ExternalSASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ExternalSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GSSAPISASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GSSAPISASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GenericBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GenericBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GenericExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/GenericExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ModifyDNRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ModifyDNRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ModifyRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/ModifyRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/PasswordModifyExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/PasswordModifyExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/PlainSASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/PlainSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/Request.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/Requests.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SASLBindClientImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SASLBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SearchRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SearchRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SimpleBindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/SimpleBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/StartTLSExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/StartTLSExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnbindRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnbindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableAbandonRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableAddRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableAnonymousSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableCRAMMD5SASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableCancelExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableCompareRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableDeleteRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableDigestMD5SASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableExternalSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableGSSAPISASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableGenericBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableGenericExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableModifyDNRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableModifyRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiablePasswordModifyExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiablePlainSASLBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableSearchRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableSimpleBindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableStartTLSExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableUnbindRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/UnmodifiableWhoAmIExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/WhoAmIExtendedRequest.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/WhoAmIExtendedRequestImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/requests/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractIntermediateResponse.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractResponseImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractUnmodifiableExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractUnmodifiableIntermediateResponseImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractUnmodifiableResponseImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/AbstractUnmodifiableResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/BindResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/BindResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/CompareResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/CompareResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/ExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/ExtendedResultDecoder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/GenericExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/GenericExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/GenericIntermediateResponse.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/GenericIntermediateResponseImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/IntermediateResponse.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/PasswordModifyExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/PasswordModifyExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/Response.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/Responses.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/Result.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/ResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/SearchResultEntry.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/SearchResultEntryImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/SearchResultReference.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/SearchResultReferenceImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableBindResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableCompareResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableGenericExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableGenericIntermediateResponseImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiablePasswordModifyExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableSearchResultEntryImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableSearchResultReferenceImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/UnmodifiableWhoAmIExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/WhoAmIExtendedResult.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/WhoAmIExtendedResultImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/responses/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeUsage.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AuthPasswordExactEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AuthPasswordSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/BinarySyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/BitStringEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/BitStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/BooleanEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/BooleanSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CertificateListSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CertificatePairSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CertificateSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ConflictingSchemaElementException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchema.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/CountryStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRule.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DeliveryMethodSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DoubleMetaphoneApproximateMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnumOrderingMatchingRule.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/FacsimileNumberSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/FaxSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GenerateCoreSchema.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/IA5StringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/IntegerEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/IntegerFirstComponentEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/IntegerOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/IntegerSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/JPEGSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUse.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameAndOptionalUIDSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassType.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OctetStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OtherMailboxSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/PostalAddressSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/PrintableStringSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/RegexSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaConstants.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaElement.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaValidationPolicy.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SubstringAssertionSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SupportedAlgorithmSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Syntax.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSubstringMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelephoneNumberSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TeletexTerminalIdentifierSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/TelexNumberSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UTCTimeSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UUIDEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UUIDOrderingMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UUIDSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UniqueMemberEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UnknownSchemaElementException.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordExactEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/UserPasswordSyntaxImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/WordEqualityMatchingRuleImpl.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/package-info.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFStream.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecord.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordVisitor.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordVisitorWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ChangeRecordWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ConnectionChangeRecordWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/EntryWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryReader.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFEntryWriter.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedChangeRecordListener.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/RejectedLDIFListener.java
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/package-info.java
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_de.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_es.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_fr.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_ja.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_ko.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_zh_CN.properties
opendj3/opendj-ldap-sdk/src/main/resources/org/forgerock/opendj/ldap/core_zh_TW.properties
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/ASN1BufferReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/ASN1BufferWriterTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/DefaultTCPNIOTransportTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/LDAPTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/controls/AccountUsabilityRequestControlTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/ldap/controls/AccountUsabilityResponseControlTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/Base64TestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/StaticUtilsTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/StringPrepProfileTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/UtilTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/asn1/ASN1ByteSequenceReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/asn1/ASN1InputStreamReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/asn1/ASN1OutputStreamWriterTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/asn1/ASN1ReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/asn1/ASN1WriterTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteSequenceTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ByteStringTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/ConnectionFactoryTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntriesTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/FilterTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPListenerTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPUrlTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LinkedAttributeTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/RDNTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/SdkTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/TypesTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/controls/ControlsTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/AbandonRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/AddRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/AnonymousSASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/BindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/CRAMMD5SASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/CompareRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/DeleteRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/DigestMD5SASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/ExtendedRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/ExternalSASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/GSSAPISASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/GenericBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/ModifyDNRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/ModifyRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/PlainSASLBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/RequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/RequestsTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/SimpleBindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/requests/UnbindRequestTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/responses/ResponsesTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/AbstractSchemaElementTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/ApproximateMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/AttributeTypeTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/BitStringEqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/BitStringSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/BooleanEqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/CoreSchemaTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/EntrySchemaCheckingTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/EnumSyntaxTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/GeneralizedTimeSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/GuideSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/IA5StringSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/OrderingMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/OtherMailboxSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/RegexSyntaxTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SubstitutionSyntaxTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SubstringMatchingRuleTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SyntaxTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/TelexSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/UTCTimeSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/UUIDSyntaxTest.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFChangeRecordReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryReaderTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFEntryWriterTestCase.java
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java
opendj3/opendj-ldap-sync/pom.xml
opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat
opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat
opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java
opendj3/opendj-ldap-toolkit/pom.xml
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/authrate.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldapcompare.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldapmodify.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldappasswordmodify.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldapsearch.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifdiff.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifmodify.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/ldifsearch.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/modrate.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/bat/searchrate.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/descriptor.xml
opendj3/opendj-ldap-toolkit/src/main/assembly/libbat/_client-script.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/libbat/_script-util.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/libbat/setcp.bat
opendj3/opendj-ldap-toolkit/src/main/assembly/libbin/_client-script.sh
opendj3/opendj-ldap-toolkit/src/main/assembly/libbin/_script-util.sh
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ApplicationKeyManager.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Argument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ArgumentException.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ArgumentGroup.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ArgumentParser.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthenticatedConnectionFactory.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/BooleanArgument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/CLIException.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConnectionFactoryProvider.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ConsoleApplication.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/DataSource.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/FileBasedArgument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/IntegerArgument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPCompare.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPModify.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPPasswordModify.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFDiff.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFModify.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDIFSearch.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MultiChoiceArgument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/MultiColumnPrinter.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PromptingTrustManager.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StringArgument.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ToolConstants.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
opendj3/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/package-info.java
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_de.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_es.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_fr.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_ja.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_ko.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_zh_CN.properties
opendj3/opendj-ldap-toolkit/src/main/resources/com/forgerock/opendj/ldap/tools/tools_zh_TW.properties
opendj3/opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ToolsTestCase.java
opendj3/opendj-rest2ldap/pom.xml
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompletionHandler.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadRequest.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/RestRequest.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Validator.java
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/package-info.java
opendj3/pom.xml
opendj3/src/site/resources/Example.ldif |