Multiple enhancements and bug fixes to the SDK (update from OpenDS by matthew_swift):
* Added a method, Entries.diffEntries(Entry,Entry), which returns a ModifyRequest containing the necessary changes to convert the first entry to the second.
* Improvements to the DIGEST-MD5 and GSSAPI SASL bind request interfaces + some bug fixes.
* Expose the LoadBalancingAlgorithm interface and also add support for Round Robin style load balancing to complement the existing Failover algorithm.
* Implement some simple examples: ldap search, ldap modify, async ldap search, an ldap proxy server, and an ldap data store. These can be found in the "examples" directory and are built and included with the SDK zip file as examples.zip.
* Various minor Javadoc improvements and bug fixes.
* Updated to latest Grizzly.
* Added an overview.html file which includes a very simple getting started example as well as pointers to key classes and interfaces (DISCLAIMER: this is just a start).
* Some more unit tests.
24 files added
81 files modified
| | |
| | | <mkdir dir="${classes.dir}" /> |
| | | <mkdir dir="${build.lib.dir}" /> |
| | | |
| | | <javac srcdir="${src.dir}:${srcgen.dir}" |
| | | <javac srcdir="${src.dir}:${srcgen.dir}:${examples.dir}" |
| | | destdir="${classes.dir}" |
| | | debug="on" |
| | | debuglevel="${build.debuglevel}" |
| | |
| | | |
| | | <jar jarfile="${pdir}/lib/${SHORT_NAME}.jar" |
| | | basedir="${classes.dir}" |
| | | excludes="**/*_fr.properties,**/*_ja.properties,**/*_de.properties,**/*_es.properties,**/*_zh_TW.properties,**/*_zh_CN.properties,**/*_ko.properties" |
| | | excludes="**/examples/**,**/*_fr.properties,**/*_ja.properties,**/*_de.properties,**/*_es.properties,**/*_zh_TW.properties,**/*_zh_CN.properties,**/*_ko.properties" |
| | | compress="true" |
| | | index="true" /> |
| | | |
| | | <jar jarfile="${pdir}/lib/${SHORT_NAME}_fr.jar" |
| | | <jar jarfile="${pdir}/lib/${SHORT_NAME}_fr.jar" |
| | | basedir="${classes.dir}" |
| | | includes="**/*_fr.properties" |
| | | compress="true" |
| | |
| | | includes="**/*_zh_TW.properties" |
| | | compress="true" |
| | | index="true" /> |
| | | |
| | | <mkdir dir="${build.dir}/examples"/> |
| | | |
| | | <!-- Create examples.zip --> |
| | | <jar jarfile="${build.dir}/examples/examples.jar" |
| | | basedir="${classes.dir}" |
| | | includes="**/examples/**" |
| | | compress="true" |
| | | index="true" /> |
| | | |
| | | <zip destfile="${build.dir}/examples/src.zip"> |
| | | <zipfileset dir="${examples.dir}" filemode="644" dirmode="755" /> |
| | | </zip> |
| | | |
| | | <copy todir="${build.dir}/examples"> |
| | | <fileset file="${resource.dir}/example-2000.ldif.zip" /> |
| | | </copy> |
| | | |
| | | <zip destfile="${pdir}/examples.zip"> |
| | | <zipfileset dir="${build.dir}/examples" |
| | | filemode="644" |
| | | dirmode="700" /> |
| | | </zip> |
| | | |
| | | <copy todir="${pdir}/lib"> |
| | | <fileset file="${lib.dir}/*.jar" /> |
| | |
| | | <mkdir dir="${javadoc.dir}" /> |
| | | |
| | | <javadoc access="protected" |
| | | windowtitle="${PRODUCT_NAME} API Documentation" |
| | | windowtitle="${PRODUCT_NAME} Documentation" |
| | | doctitle="${PRODUCT_NAME} Documentation" |
| | | maxmemory="${MEM}" |
| | | classpath="${lib.dir}/grizzly.jar" |
| | | destdir="${javadoc.dir}" |
| | | packagenames="org.opends.sdk.*" |
| | | source="1.5" |
| | | sourcepath="src:src-generated"> |
| | | sourcepath="src:src-generated" |
| | | overview="src/overview.html"> |
| | | <link href="http://java.sun.com/javase/6/docs/api/" /> |
| | | </javadoc> |
| | | </target> |
| | |
| | | <zipfileset dir="${srcgen.dir}" filemode="644" dirmode="755" /> |
| | | </zip> |
| | | </target> |
| | | |
| | | <!-- The build target that should be used for nightly builds. --> |
| | | <target name="nightly" |
| | | depends="nightlybuild,nightlytests" |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.examples.client.asyncsearch; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.CountDownLatch; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.ldif.LDIFEntryWriter; |
| | | import org.opends.sdk.requests.BindRequest; |
| | | import org.opends.sdk.requests.Requests; |
| | | import org.opends.sdk.requests.SearchRequest; |
| | | import org.opends.sdk.responses.BindResult; |
| | | import org.opends.sdk.responses.Result; |
| | | import org.opends.sdk.responses.SearchResultEntry; |
| | | import org.opends.sdk.responses.SearchResultReference; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server using the |
| | | * asynchronous APIs. This example takes the following command line parameters: |
| | | * |
| | | * <pre> |
| | | * <host> <port> <username> <password> |
| | | * <baseDN> <scope> <filter> [<attibute> <attribute> ...] |
| | | * </pre> |
| | | */ |
| | | public final class Main |
| | | { |
| | | 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.search(request, new SearchResultHandlerImpl()); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private static final class ConnectResultHandlerImpl implements |
| | | ResultHandler<AsynchronousConnection> |
| | | { |
| | | |
| | | /** |
| | | * {@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 AsynchronousConnection connection) |
| | | { |
| | | // Connect succeeded: save connection and initiate bind. |
| | | Main.connection = connection; |
| | | |
| | | final BindRequest request = Requests.newSimpleBindRequest(userName, |
| | | password); |
| | | connection.bind(request, 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 AsynchronousConnection 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.getAsynchronousConnection(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 Main() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server using the |
| | | * asynchronous APIs. |
| | | */ |
| | | package org.opends.sdk.examples.client.asyncsearch; |
| | | |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.examples.client.modify; |
| | | |
| | | |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.FileNotFoundException; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | |
| | | import org.opends.sdk.Connection; |
| | | import org.opends.sdk.ErrorResultException; |
| | | import org.opends.sdk.LDAPConnectionFactory; |
| | | import org.opends.sdk.ResultCode; |
| | | import org.opends.sdk.ldif.ChangeRecord; |
| | | import org.opends.sdk.ldif.ConnectionChangeRecordWriter; |
| | | import org.opends.sdk.ldif.LDIFChangeRecordReader; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An example client application which applies update operations to a Directory |
| | | * Server. The update operations will be read from an LDIF file, or stdin if no |
| | | * filename is provided. This example takes the following command line |
| | | * parameters (it will read from stdin if no LDIF file is provided): |
| | | * |
| | | * <pre> |
| | | * <host> <port> <username> <password> [<ldifFile>] |
| | | * </pre> |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * 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); |
| | | |
| | | // 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 Main() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * An example client application which applies update operations to a Directory |
| | | * Server. The update operations will be read from an LDIF file, or stdin if no |
| | | * filename is provided. |
| | | */ |
| | | package org.opends.sdk.examples.client.modify; |
| | | |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.examples.client.search; |
| | | |
| | | |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Arrays; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.ldif.ConnectionEntryReader; |
| | | import org.opends.sdk.ldif.LDIFEntryWriter; |
| | | import org.opends.sdk.responses.SearchResultEntry; |
| | | import org.opends.sdk.responses.SearchResultReference; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server. This example |
| | | * takes the following command line parameters: |
| | | * |
| | | * <pre> |
| | | * <host> <port> <username> <password> |
| | | * <baseDN> <scope> <filter> [<attibute> <attribute> ...] |
| | | * </pre> |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * 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); |
| | | |
| | | // 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 Main() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * An example client application which searches a Directory Server. |
| | | */ |
| | | package org.opends.sdk.examples.client.search; |
| | | |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.examples.server.proxy; |
| | | |
| | | |
| | | |
| | | import static org.opends.sdk.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.BindResult; |
| | | import org.opends.sdk.responses.CompareResult; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.Result; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An LDAP load balancing proxy which forwards requests to one or more remote |
| | | * Directory Servers. This is implementation is very simple and is only intended |
| | | * as an example: |
| | | * <ul> |
| | | * <li>It does not support SSL connections |
| | | * <li>It does not support StartTLS |
| | | * <li>It does not support Abandon or Cancel requests |
| | | * <li>Very basic authentication and authorization support. |
| | | * </ul> |
| | | * This example takes the following command line parameters: |
| | | * |
| | | * <pre> |
| | | * <listenAddress> <listenPort> <remoteAddress1> <remotePort1> |
| | | * [<remoteAddress2> <remotePort2> ...] |
| | | * </pre> |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * Proxy server connection factory implementation. |
| | | */ |
| | | private static final class Proxy implements |
| | | ServerConnectionFactory<LDAPClientContext, Integer> |
| | | { |
| | | private final class ServerConnectionImpl implements |
| | | ServerConnection<Integer> |
| | | { |
| | | |
| | | private volatile AsynchronousConnection connection = null; |
| | | |
| | | private volatile boolean isUnbindRequired = false; |
| | | |
| | | |
| | | |
| | | private AsynchronousConnection getConnection() |
| | | throws ErrorResultException |
| | | { |
| | | if (connection == null) |
| | | { |
| | | synchronized (this) |
| | | { |
| | | if (connection == null) |
| | | { |
| | | try |
| | | { |
| | | connection = factory.getAsynchronousConnection(null).get(); |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return connection; |
| | | } |
| | | |
| | | |
| | | |
| | | private ServerConnectionImpl(final LDAPClientContext clientContext) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer requestContext, |
| | | final AbandonRequest request) throws UnsupportedOperationException |
| | | { |
| | | // Not implemented. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final Integer requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().add(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final Integer requestContext, final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } |
| | | else |
| | | { |
| | | // Note that this connection has received a bind request: the |
| | | // connection should be reverted back to anonymous when the client |
| | | // unbinds. |
| | | isUnbindRequired = true; |
| | | |
| | | try |
| | | { |
| | | getConnection().bind(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final Integer requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().compare(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed(final Integer requestContext, |
| | | final UnbindRequest request) |
| | | { |
| | | // Client connection closed: release the proxy connection. |
| | | close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected(final ResultCode resultCode, |
| | | final String message) |
| | | { |
| | | // Client disconnected by server: release the proxy connection. |
| | | close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | // Client connection failed: release the proxy connection. |
| | | close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final Integer requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().delete(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final Integer requestContext, final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | 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. |
| | | try |
| | | { |
| | | getConnection().extendedRequest(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final Integer requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().modify(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final Integer requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().modifyDN(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final Integer requestContext, |
| | | final SearchRequest request, final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | try |
| | | { |
| | | getConnection().search(request, resultHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void close() |
| | | { |
| | | if (isUnbindRequired) |
| | | { |
| | | synchronized (this) |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.bind(Requests.newSimpleBindRequest(), |
| | | new ResultHandler<Result>() |
| | | { |
| | | |
| | | public void handleErrorResult(ErrorResultException error) |
| | | { |
| | | // The rebind failed - this is bad because if the |
| | | // connection is pooled it will remain authenticated as |
| | | // the wrong user. |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleResult(Result result) |
| | | { |
| | | synchronized (ServerConnectionImpl.this) |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final ConnectionFactory factory; |
| | | |
| | | |
| | | |
| | | private Proxy(final ConnectionFactory factory) |
| | | { |
| | | this.factory = factory; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | return new ServerConnectionImpl(clientContext); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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]); |
| | | |
| | | // Create load balancer. |
| | | final List<ConnectionFactory> factories = 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.newConnectionPool(new LDAPConnectionFactory( |
| | | // remoteAddress, remotePort), Integer.MAX_VALUE)); |
| | | factories.add(new LDAPConnectionFactory(remoteAddress, remotePort)); |
| | | } |
| | | final RoundRobinLoadBalancingAlgorithm algorithm = new RoundRobinLoadBalancingAlgorithm( |
| | | factories); |
| | | final ConnectionFactory factory = Connections.newLoadBalancer(algorithm); |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, new Proxy(factory), |
| | | 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 Main() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * An example LDAP proxy which forwards requests to a remote Directory Server. |
| | | */ |
| | | package org.opends.sdk.examples.server.proxy; |
| | | |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.examples.server.store; |
| | | |
| | | |
| | | |
| | | import static org.opends.sdk.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.FileNotFoundException; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.util.NavigableMap; |
| | | import java.util.concurrent.ConcurrentSkipListMap; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.ldif.LDIFEntryReader; |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An LDAP directory server which exposes data contained in an LDIF file. This |
| | | * is implementation is very simple and is only intended as an example: |
| | | * <ul> |
| | | * <li>It does not support SSL connections |
| | | * <li>It does not support StartTLS |
| | | * <li>It does not support Abandon or Cancel requests |
| | | * <li>Very basic authentication and authorization support. |
| | | * </ul> |
| | | * This example takes the following command line parameters: |
| | | * |
| | | * <pre> |
| | | * <listenAddress> <listenPort> [<ldifFile>] |
| | | * </pre> |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * Proxy server connection factory implementation. |
| | | */ |
| | | private static final class Store implements |
| | | ServerConnectionFactory<LDAPClientContext, Integer> |
| | | { |
| | | private final class ServerConnectionImpl implements |
| | | ServerConnection<Integer> |
| | | { |
| | | |
| | | private ServerConnectionImpl(final LDAPClientContext clientContext) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer requestContext, |
| | | final AbandonRequest request) throws UnsupportedOperationException |
| | | { |
| | | // Not implemented. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final Integer requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // 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")); |
| | | } |
| | | |
| | | 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 handleBind(final Integer requestContext, final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | 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 Integer requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed(final Integer requestContext, |
| | | final UnbindRequest request) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected(final ResultCode resultCode, |
| | | final String message) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final Integer requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // 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 Integer requestContext, final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Extended request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final Integer requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // 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 Integer requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "ModifyDN request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final Integer requestContext, |
| | | final SearchRequest request, final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // 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")); |
| | | } |
| | | |
| | | SearchScope scope = request.getScope(); |
| | | if (scope.equals(SearchScope.BASE_OBJECT)) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | } |
| | | else if (scope.equals(SearchScope.SINGLE_LEVEL)) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn, false); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isChildOf(dn)) |
| | | { |
| | | 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()) |
| | | { |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | 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)); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean sendEntry(SearchRequest request, |
| | | SearchResultHandler resultHandler, Entry entry) |
| | | { |
| | | // TODO: check filter, strip attributes. |
| | | return resultHandler.handleEntry(Responses.newSearchResultEntry(entry)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final ConcurrentSkipListMap<DN, Entry> entries; |
| | | |
| | | private final ReentrantReadWriteLock entryLock = new ReentrantReadWriteLock(); |
| | | |
| | | |
| | | |
| | | private Store(final ConcurrentSkipListMap<DN, Entry> entries) |
| | | { |
| | | this.entries = entries; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | return new ServerConnectionImpl(clientContext); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Main method. |
| | | * |
| | | * @param args |
| | | * The command line arguments: listen address, listen port, ldifFile |
| | | */ |
| | | public static void main(final String[] args) |
| | | { |
| | | if (args.length != 3) |
| | | { |
| | | System.err.println("Usage: listenAddress listenPort ldifFile"); |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | |
| | | // Read the LDIF. |
| | | InputStream ldif; |
| | | try |
| | | { |
| | | ldif = new FileInputStream(args[2]); |
| | | } |
| | | catch (final FileNotFoundException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | } |
| | | |
| | | final LDIFEntryReader reader = new LDIFEntryReader(ldif); |
| | | ConcurrentSkipListMap<DN, Entry> entries = new ConcurrentSkipListMap<DN, Entry>(); |
| | | 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; |
| | | } |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | if (!isValid) |
| | | { |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, new Store(entries), |
| | | 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 Main() |
| | | { |
| | | // Not used. |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * An example LDAP data store which exposes data which is contained within an |
| | | * LDIF file. |
| | | */ |
| | | package org.opends.sdk.examples.server.store; |
| | | |
| | | |
| | | |
| New file |
| | |
| | | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. |
| | | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. |
| | | nbproject/jdk.xml.data.CRC32=f285a38e |
| | | nbproject/jdk.xml.script.CRC32=5342cb35 |
| | | nbproject/jdk.xml.stylesheet.CRC32=c45af3dc |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project basedir=".." name="Directory Server-IDE"> |
| | | <!-- Import build.xml properties and targets --> |
| | | <import file="../build.xml"/> |
| | | <path id="opends.path"> |
| | | <pathelement path="build/classes:build/build-tools/classes:lib/activation.jar:lib/aspectjrt.jar:lib/je.jar:lib/mail.jar:build/quicksetup/classes:build/build-tools/build-tools.jar:build/unit-tests/classes:ext/testng/lib/testng-5.7b-jdk15.jar:ext/ant/lib/ant.jar:ext/svnkit/svnkit.jar:ext/emma/lib/emma.jar:build/dsml/classes:resource/dsml/lib/jaxb-api.jar:resource/dsml/lib/jaxb-impl.jar:resource/dsml/lib/jsr173_1.0_api.jar:resource/dsml/lib/saaj-1.3.jar:resource/dsml/lib/saaj-impl-1.3.jar:resource/dsml/lib/j2ee.jar"/> |
| | | <pathelement location="build/build-tools/classes"/> |
| | | <pathelement location="build/classes"/> |
| | | <pathelement location="build/quicksetup/classes"/> |
| | | <pathelement location="build/unit-tests/classes"/> |
| | | <pathelement location="build/dsml/classes"/> |
| | | <fileset dir="${opendmk.lib.dir}"> |
| | | <include name="*.jar"/> |
| | | </fileset> |
| | | </path> |
| | | <!-- Prepare testng unit tests environment --> |
| | | <taskdef resource="testngtasks"> |
| | | <classpath> |
| | | <fileset dir="${testng.lib.dir}"> |
| | | <include name="*.jar"/> |
| | | </fileset> |
| | | </classpath> |
| | | </taskdef> |
| | | <target name="prepare-test"> |
| | | <delete failonerror="false"> |
| | | <fileset dir="${unittest.report.dir}" includes="*"/> |
| | | </delete> |
| | | <mkdir dir="${unittest.report.dir}"/> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Run a selected testng file --> |
| | | <!-- --> |
| | | <target depends="prepare-test" name="run-selected-testng-file"> |
| | | <fail unless="run.class">Must set property 'run.class'</fail> |
| | | <echo message="Running test (normal): ${run.class}"/> |
| | | <testng dumpCommand="true" enableAssert="false" haltonfailure="false" listeners="org.opends.server.TestListener org.testng.reporters.FailedReporter" outputdir="${unittest.report.dir}" suiteRunnerClass="org.opends.server.SuiteRunner" useDefaultListeners="false" verbose="0"> |
| | | <classpath refid="opends.path"/> |
| | | <jvmarg value="-Dorg.opends.server.BuildRoot=${basedir}"/> |
| | | <jvmarg value="-Dorg.opends.server.RunningUnitTests=true"/> |
| | | <jvmarg value="-Dorg.opends.test.suppressOutput=false"/> |
| | | <jvmarg value="-Dorg.opends.test.pauseOnFailure=false"/> |
| | | <jvmarg value="-Dorg.opends.test.debug.target=false"/> |
| | | <jvmarg value="-Dorg.opends.server.snmp.opendmk=${opendmk.lib.dir}"/> |
| | | <jvmarg value="-Dorg.opends.test.copyClassesToTestPackage=true"/> |
| | | <jvmarg value="-Dtest.progress=all"/> |
| | | <jvmarg value="-Xms192M"/> |
| | | <jvmarg value="-Xmx192M"/> |
| | | <classfileset file="${unittest.classes.dir}/${run.class}.class"/> |
| | | </testng> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Debug a selected file in testng unit tests sources --> |
| | | <!-- --> |
| | | <target name="debug-selected-testng-file"> |
| | | <fail unless="debug.class">Must set property 'debug.class'</fail> |
| | | <echo message="Debugging test (normal): ${debug.class}"/> |
| | | <ant antfile="build.xml" inheritall="false" target="dynamicconstants"/> |
| | | <nbjpdastart addressproperty="jpda.address" name="Directory Server" transport="dt_socket"> |
| | | <classpath refid="opends.path"/> |
| | | </nbjpdastart> |
| | | <testng enableAssert="false" haltonfailure="false" listeners="org.opends.server.TestListener org.testng.reporters.FailedReporter" outputdir="${unittest.report.dir}" suiteRunnerClass="org.opends.server.SuiteRunner" useDefaultListeners="false" verbose="5"> |
| | | <classpath refid="opends.path"/> |
| | | <jvmarg value="-Dorg.opends.server.LdapPort=1389"/> |
| | | <jvmarg value="-Dorg.opends.server.BuildRoot=${basedir}"/> |
| | | <jvmarg value="-Dorg.opends.server.RunningUnitTests=true"/> |
| | | <jvmarg value="-Dorg.opends.test.suppressOutput=false"/> |
| | | <jvmarg value="-Dorg.opends.test.pauseOnFailure=false"/> |
| | | <jvmarg value="-Dorg.opends.test.debug.target=false"/> |
| | | <jvmarg value="-Dorg.opends.server.snmp.opendmk=${opendmk.lib.dir}"/> |
| | | <jvmarg value="-Dorg.opends.test.copyClassesToTestPackage=true"/> |
| | | <jvmarg value="-Dtest.progress=all"/> |
| | | <jvmarg value="-Xms192M"/> |
| | | <jvmarg value="-Xmx192M"/> |
| | | <jvmarg value="-Xdebug"/> |
| | | <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> |
| | | <classfileset file="${unittest.classes.dir}/${debug.class}.class"/> |
| | | </testng> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/server folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-server"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <!-- TODO decide on and define some value for ${build.classes.dir} --> |
| | | <mkdir dir="${classes.dir}"/> |
| | | <javac destdir="${classes.dir}" includes="${files}" source="1.5" srcdir="src/server"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in testng unit tests source folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-testng-file"> |
| | | <!-- Compile the test cases --> |
| | | <echo message="Compiling test (normal): ${files}"/> |
| | | <mkdir dir="${unittest.classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" deprecation="true" destdir="${unittest.classes.dir}" fork="true" includes="${files}" memoryInitialSize="${MEM}" memoryMaximumSize="${MEM}" source="1.5" srcdir="${unittest.testng.src.dir}" target="1.5"> |
| | | <compilerarg value="-Xlint:all"/> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Run a selected class in src/server folder --> |
| | | <!-- --> |
| | | <target depends="dynamicconstants" name="run-selected-file-in-server"> |
| | | <fail unless="run.class">Must set property 'run.class'</fail> |
| | | <property location="${package.dir}/${SHORT_NAME}-${VERSION_NUMBER_STRING}" name="pdir"/> |
| | | <ant antfile="build.xml" inheritall="false" target="dynamicconstants"/> |
| | | <java classname="${run.class}" failonerror="true" fork="true"> |
| | | <classpath refid="opends.path"/> |
| | | <jvmarg value="-Dorg.opends.server.BuildRoot=${pdir}"/> |
| | | <jvmarg value="-Dorg.opends.server.scriptName=start-ds"/> |
| | | <jvmarg value="-Dorg.opends.server.ServerRoot=${pdir}"/> |
| | | <arg value="--configClass=org.opends.server.extensions.ConfigFileHandler"/> |
| | | <arg value="--configFile=${pdir}/config/config.ldif"/> |
| | | <arg value="--nodetach"/> |
| | | </java> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Debug a selected file in src/server folder --> |
| | | <!-- --> |
| | | <target depends="dynamicconstants" name="debug-selected-file-in-server"> |
| | | <fail unless="debug.class">Must set property 'debug.class'</fail> |
| | | <property location="${package.dir}/${SHORT_NAME}-${VERSION_NUMBER_STRING}" name="pdir"/> |
| | | <ant antfile="build.xml" inheritall="false" target="dynamicconstants"/> |
| | | <nbjpdastart addressproperty="jpda.address" name="Directory Server" transport="dt_socket"> |
| | | <classpath refid="opends.path"/> |
| | | </nbjpdastart> |
| | | <java classname="${debug.class}" fork="true"> |
| | | <classpath refid="cp"/> |
| | | <jvmarg value="-Xdebug"/> |
| | | <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> |
| | | <jvmarg value="-Dorg.opends.server.BuildRoot=${pdir}"/> |
| | | <jvmarg value="-Dorg.opends.server.scriptName=start-ds"/> |
| | | <jvmarg value="-Dorg.opends.server.ServerRoot=${pdir}"/> |
| | | <jvmarg value="-Dorg.opends.server.debug.enabled=true"/> |
| | | <arg value="--configClass=org.opends.server.extensions.ConfigFileHandler"/> |
| | | <arg value="--configFile=${pdir}/config/config.ldif"/> |
| | | <arg value="--nodetach"/> |
| | | </java> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/ads folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-ads"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <mkdir dir="${classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${classes.dir}" includes="${files}" source="1.5" srcdir="src/ads"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/build-tools folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-build-tools"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <mkdir dir="${buildtools.classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${buildtools.classes.dir}" includes="${files}" source="1.5" srcdir="src/build-tools"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/guitools folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-guitools"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <mkdir dir="${classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${classes.dir}" includes="${files}" source="1.5" srcdir="src/guitools"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/messages/src folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-messages-src"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <mkdir dir="${classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${classes.dir}" includes="${files}" source="1.5" srcdir="src/messages/src"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/quicksetup folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-quicksetup"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <mkdir dir="${quicksetup.classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${quicksetup.classes.dir}" includes="${files}" source="1.5" srcdir="src/quicksetup"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/dsml folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-dsml"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <echo message="Compiling source (normal): ${files}"/> |
| | | <mkdir dir="${dsml.classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${dsml.classes.dir}" includes="${files}" source="1.5" srcdir="src/dsml"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | <!-- --> |
| | | <!-- Compile a selected file in src/snmp/src folder --> |
| | | <!-- --> |
| | | <target name="compile-selected-files-in-snmp"> |
| | | <fail unless="files">Must set property 'files'</fail> |
| | | <mkdir dir="${classes.dir}"/> |
| | | <javac debug="on" debuglevel="${build.debuglevel}" destdir="${classes.dir}" includes="${files}" source="1.5" srcdir="src/snmp/src"> |
| | | <classpath refid="opends.path"/> |
| | | </javac> |
| | | </target> |
| | | </project> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project basedir=".." name="Directory Server-IDE"> |
| | | |
| | | <!-- Import build.xml definitions --> |
| | | <import file="../build.xml"/> |
| | | |
| | | <!-- OpenDS path --> |
| | | <path id="opends.path"> |
| | | <pathelement path="build/classes:build/build-tools/classes:lib/activation.jar:lib/aspectjrt.jar:lib/je.jar:lib/mail.jar:build/quicksetup/classes:build/build-tools/build-tools.jar:build/unit-tests/classes:ext/testng/lib/testng-5.7b-jdk15.jar:ext/ant/lib/ant.jar:ext/svnkit/svnkit.jar:ext/emma/lib/emma.jar:build/dsml/classes:resource/dsml/lib/jaxb-api.jar:resource/dsml/lib/jaxb-impl.jar:resource/dsml/lib/jsr173_1.0_api.jar:resource/dsml/lib/saaj-1.3.jar:resource/dsml/lib/saaj-impl-1.3.jar:resource/dsml/lib/j2ee.jar"/> |
| | | <pathelement location="build/build-tools/classes"/> |
| | | <pathelement location="build/classes"/> |
| | | <pathelement location="build/quicksetup/classes"/> |
| | | <pathelement location="build/unit-tests/classes"/> |
| | | <pathelement location="build/dsml/classes"/> |
| | | </path> |
| | | |
| | | <!-- --> |
| | | <!-- Debug target call by NetBeans IDE --> |
| | | <!-- --> |
| | | <target depends="dynamicconstants" name="debug-nb"> |
| | | <!-- Set properties needed to find the packaged files --> |
| | | <property location="${package.dir}/${SHORT_NAME}-${VERSION_NUMBER_STRING}" name="pdir"/> |
| | | <nbjpdastart addressproperty="jpda.address" name="Directory Server" transport="dt_socket"> |
| | | <classpath refid="opends.path"/> |
| | | </nbjpdastart> |
| | | <java classname="org.opends.server.core.DirectoryServer" failonerror="true" fork="true"> |
| | | <classpath refid="opends.path"/> |
| | | <jvmarg value="-Dorg.opends.server.BuildRoot=${pdir}"/> |
| | | <jvmarg value="-Dorg.opends.server.scriptName=start-ds"/> |
| | | <jvmarg value="-Dorg.opends.server.ServerRoot=${pdir}"/> |
| | | <arg value="--configClass=org.opends.server.extensions.ConfigFileHandler"/> |
| | | <arg value="--configFile=${pdir}/config/config.ldif"/> |
| | | <arg value="--nodetach"/> |
| | | <jvmarg value="-Xdebug"/> |
| | | <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> |
| | | </java> |
| | | </target> |
| | | </project> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns="http://www.netbeans.org/ns/project/1"> |
| | | <type>org.netbeans.modules.ant.freeform</type> |
| | | <configuration> |
| | | <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1"> |
| | | <name>OpenDJ SDK</name> |
| | | </general-data> |
| | | <general-data xmlns="http://www.netbeans.org/ns/freeform-project/2"> |
| | | <!-- Do not use Project Properties customizer when editing this file manually. --> |
| | | <name>OpenDJ SDK</name> |
| | | <properties/> |
| | | <folders> |
| | | <source-folder> |
| | | <label>OpenDJ SDK</label> |
| | | <location>.</location> |
| | | <encoding>UTF-8</encoding> |
| | | </source-folder> |
| | | <source-folder> |
| | | <label>src</label> |
| | | <type>java</type> |
| | | <location>src</location> |
| | | <encoding>UTF-8</encoding> |
| | | </source-folder> |
| | | <source-folder> |
| | | <label>tests/unit-tests-testng/src</label> |
| | | <type>java</type> |
| | | <location>tests/unit-tests-testng/src</location> |
| | | <encoding>UTF-8</encoding> |
| | | </source-folder> |
| | | </folders> |
| | | <ide-actions> |
| | | <action name="build"> |
| | | <script>build.xml</script> |
| | | <target>package</target> |
| | | </action> |
| | | <action name="clean"> |
| | | <script>build.xml</script> |
| | | <target>clean</target> |
| | | </action> |
| | | <action name="javadoc"> |
| | | <script>build.xml</script> |
| | | <target>javadoc</target> |
| | | </action> |
| | | <action name="run"> |
| | | <script>build.xml</script> |
| | | <target>run-server</target> |
| | | </action> |
| | | <action name="test"> |
| | | <script>build.xml</script> |
| | | <target>test</target> |
| | | </action> |
| | | <action name="rebuild"> |
| | | <script>build.xml</script> |
| | | <target>clean</target> |
| | | <target>package</target> |
| | | </action> |
| | | <action name="debug"> |
| | | <script>nbproject/ide-targets.xml</script> |
| | | <target>debug-nb</target> |
| | | </action> |
| | | <action name="run.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>run-selected-testng-file</target> |
| | | <context> |
| | | <property>run.class</property> |
| | | <folder>tests/unit-tests-testng/src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path-noext</format> |
| | | <arity> |
| | | <one-file-only/> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="debug.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>debug-selected-testng-file</target> |
| | | <context> |
| | | <property>debug.class</property> |
| | | <folder>tests/unit-tests-testng/src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path-noext</format> |
| | | <arity> |
| | | <one-file-only/> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-server</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-testng-file</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>tests/unit-tests-testng/src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="run.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>run-selected-file-in-server</target> |
| | | <context> |
| | | <property>run.class</property> |
| | | <folder>src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>java-name</format> |
| | | <arity> |
| | | <one-file-only/> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="debug.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>debug-selected-file-in-server</target> |
| | | <context> |
| | | <property>debug.class</property> |
| | | <folder>src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>java-name</format> |
| | | <arity> |
| | | <one-file-only/> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-ads</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/ads</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-build-tools</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/build-tools</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-guitools</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/guitools</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-messages-src</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/messages/src</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-quicksetup</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/quicksetup</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-dsml</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/dsml</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-snmp</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>src/snmp/src</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | <action name="compile.single"> |
| | | <script>nbproject/ide-file-targets.xml</script> |
| | | <target>compile-selected-files-in-server</target> |
| | | <context> |
| | | <property>files</property> |
| | | <folder>tests/unit-tests-testng/src/server</folder> |
| | | <pattern>\.java$</pattern> |
| | | <format>relative-path</format> |
| | | <arity> |
| | | <separated-files>,</separated-files> |
| | | </arity> |
| | | </context> |
| | | </action> |
| | | </ide-actions> |
| | | <view> |
| | | <items> |
| | | <source-folder style="packages"> |
| | | <label>src</label> |
| | | <location>src</location> |
| | | </source-folder> |
| | | <source-folder style="packages"> |
| | | <label>tests/unit-tests-testng/src</label> |
| | | <location>tests/unit-tests-testng/src</location> |
| | | </source-folder> |
| | | <source-file> |
| | | <location>build.xml</location> |
| | | </source-file> |
| | | </items> |
| | | <context-menu> |
| | | <ide-action name="build"/> |
| | | <ide-action name="rebuild"/> |
| | | <ide-action name="clean"/> |
| | | <ide-action name="javadoc"/> |
| | | <ide-action name="run"/> |
| | | <ide-action name="test"/> |
| | | <ide-action name="debug"/> |
| | | </context-menu> |
| | | </view> |
| | | <subprojects/> |
| | | </general-data> |
| | | <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3"> |
| | | <compilation-unit> |
| | | <package-root>src</package-root> |
| | | <classpath mode="compile">src-generated</classpath> |
| | | <source-level>1.6</source-level> |
| | | </compilation-unit> |
| | | <compilation-unit> |
| | | <package-root>tests/unit-tests-testng/src</package-root> |
| | | <unit-tests/> |
| | | <source-level>1.6</source-level> |
| | | </compilation-unit> |
| | | </java-data> |
| | | </configuration> |
| | | </project> |
| | |
| | | import org.opends.sdk.requests.AbstractExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequestDecoder; |
| | | import org.opends.sdk.responses.AbstractExtendedResultDecoder; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<GetConnectionIDExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<GetConnectionIDExtendedResult> |
| | | { |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GetConnectionIDExtendedResult adaptExtendedErrorResult( |
| | | public GetConnectionIDExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| | |
| | | import org.opends.sdk.requests.AbstractExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequestDecoder; |
| | | import org.opends.sdk.responses.AbstractExtendedResultDecoder; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.Responses; |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<ExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<ExtendedResult> |
| | | { |
| | | |
| | | public ExtendedResult adaptExtendedErrorResult(final ResultCode resultCode, |
| | | public ExtendedResult newExtendedErrorResult(final ResultCode resultCode, |
| | | final String matchedDN, final String diagnosticMessage) |
| | | { |
| | | return Responses.newGenericExtendedResult(resultCode).setMatchedDN( |
| | |
| | | import org.opends.sdk.requests.AbstractExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequest; |
| | | import org.opends.sdk.requests.ExtendedRequestDecoder; |
| | | import org.opends.sdk.responses.AbstractExtendedResultDecoder; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<PasswordPolicyStateExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<PasswordPolicyStateExtendedResult> |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public PasswordPolicyStateExtendedResult adaptExtendedErrorResult( |
| | | public PasswordPolicyStateExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| | |
| | | import org.opends.sdk.asn1.ASN1Reader; |
| | | import org.opends.sdk.asn1.AbstractASN1Reader; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.memory.ByteBuffersBuffer; |
| | | import com.sun.grizzly.memory.CompositeBuffer; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.memory.ByteBuffersBuffer; |
| | | import org.glassfish.grizzly.memory.CompositeBuffer; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | |
| | | import org.opends.sdk.asn1.ASN1Writer; |
| | | import org.opends.sdk.asn1.AbstractASN1Writer; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.Cacheable; |
| | | import com.sun.grizzly.ThreadCache; |
| | | import com.sun.grizzly.memory.ByteBufferWrapper; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.Cacheable; |
| | | import org.glassfish.grizzly.ThreadCache; |
| | | import org.glassfish.grizzly.memory.ByteBufferWrapper; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.ldap; |
| | |
| | | import org.opends.sdk.responses.IntermediateResponse; |
| | | import org.opends.sdk.responses.Result; |
| | | |
| | | import com.sun.opends.sdk.util.AbstractFutureResult; |
| | | import com.sun.opends.sdk.util.AsynchronousFutureResult; |
| | | |
| | | |
| | | |
| | |
| | | * The type of result returned by this future. |
| | | */ |
| | | abstract class AbstractLDAPFutureResultImpl<S extends Result> extends |
| | | AbstractFutureResult<S> implements FutureResult<S>, |
| | | IntermediateResponseHandler |
| | | AsynchronousFutureResult<S> implements IntermediateResponseHandler |
| | | { |
| | | private final AsynchronousConnection connection; |
| | | |
| | | private final int messageID; |
| | | private final int requestID; |
| | | |
| | | private IntermediateResponseHandler intermediateResponseHandler; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | AbstractLDAPFutureResultImpl(final int messageID, |
| | | AbstractLDAPFutureResultImpl(final int requestID, |
| | | final ResultHandler<? super S> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(resultHandler); |
| | | this.messageID = messageID; |
| | | this.requestID = requestID; |
| | | this.connection = connection; |
| | | this.intermediateResponseHandler = intermediateResponseHandler; |
| | | this.timestamp = System.currentTimeMillis(); |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final int getRequestID() |
| | | { |
| | | return messageID; |
| | | return requestID; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final boolean handleIntermediateResponse( |
| | | final IntermediateResponse response) |
| | | { |
| | |
| | | protected final ErrorResultException handleCancelRequest( |
| | | final boolean mayInterruptIfRunning) |
| | | { |
| | | connection.abandon(Requests.newAbandonRequest(messageID)); |
| | | connection.abandon(Requests.newAbandonRequest(requestID)); |
| | | return null; |
| | | } |
| | | |
| | |
| | | @Override |
| | | protected void toString(final StringBuilder sb) |
| | | { |
| | | sb.append(" messageID = "); |
| | | sb.append(messageID); |
| | | 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()); |
| | | final S errorResult = newErrorResult(result.getResultCode(), |
| | | result.getDiagnosticMessage(), result.getCause()); |
| | | setResultOrError(errorResult); |
| | | } |
| | | |
| | |
| | | |
| | | import java.io.IOException; |
| | | |
| | | import com.sun.grizzly.TransportFactory; |
| | | import com.sun.grizzly.nio.NIOTransportFactory; |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import com.sun.grizzly.nio.transport.UDPNIOTransport; |
| | | import com.sun.grizzly.threadpool.ThreadPoolConfig; |
| | | import org.glassfish.grizzly.TransportFactory; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.nio.transport.UDPNIOTransport; |
| | | import org.glassfish.grizzly.threadpool.ThreadPoolConfig; |
| | | |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | |
| | | /** |
| | | * A static Grizzly transport that can be used by default globally in the SDK. |
| | | */ |
| | | public final class GlobalTransportFactory extends NIOTransportFactory |
| | | public final class GlobalTransportFactory extends TransportFactory |
| | | { |
| | | private static final GlobalTransportFactory INSTANCE = new GlobalTransportFactory(); |
| | | private static boolean isInitialized = false; |
| | | |
| | | |
| | | |
| | |
| | | * |
| | | * @return The global Grizzly transport factory. |
| | | */ |
| | | public static TransportFactory getInstance() |
| | | public static synchronized TransportFactory getInstance() |
| | | { |
| | | return INSTANCE; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the global Grizzly transport factory. |
| | | * |
| | | * @param factory |
| | | * The global Grizzly transport factory. |
| | | */ |
| | | public static void setInstance(final TransportFactory factory) |
| | | { |
| | | throw new UnsupportedOperationException("not yet implemented"); |
| | | if (!isInitialized) |
| | | { |
| | | TransportFactory.setInstance(new GlobalTransportFactory()); |
| | | isInitialized = true; |
| | | } |
| | | return TransportFactory.getInstance(); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Close the {@link com.sun.grizzly.TransportFactory} and release all |
| | | * Close the {@link org.glassfish.grizzly.TransportFactory} and release all |
| | | * resources. |
| | | */ |
| | | @Override |
| | |
| | | |
| | | |
| | | /** |
| | | * Create instance of TCP {@link com.sun.grizzly.Transport}. |
| | | * Create instance of TCP {@link org.glassfish.grizzly.Transport}. |
| | | * |
| | | * @return instance of TCP {@link com.sun.grizzly.Transport}. |
| | | * @return instance of TCP {@link org.glassfish.grizzly.Transport}. |
| | | */ |
| | | @Override |
| | | public synchronized TCPNIOTransport createTCPTransport() |
| | |
| | | |
| | | |
| | | /** |
| | | * Creating an UDP transport is unsupported with this factory. A {@code |
| | | * UnsupportedOperationException} will be thrown when this method is called. |
| | | * Creating an UDP transport is unsupported with this factory. A |
| | | * {@code UnsupportedOperationException} will be thrown when this method is |
| | | * called. |
| | | * |
| | | * @return This method will always throw {@code UnsupportedOperationException} |
| | | * . |
| | |
| | | |
| | | super.initialize(); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import org.opends.sdk.LDAPListenerOptions; |
| | | |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | import org.opends.sdk.LDAPOptions; |
| | | |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | |
| | | |
| | | |
| | |
| | | public final class InternalConnection extends AbstractAsynchronousConnection |
| | | { |
| | | private static final class InternalBindFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<BindResult> implements |
| | | FutureResult<BindResult> |
| | | AbstractLDAPFutureResultImpl<BindResult> |
| | | { |
| | | private final BindRequest bindRequest; |
| | | |
| | |
| | | BindResult newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newBindResult(resultCode).setDiagnosticMessage( |
| | | diagnosticMessage).setCause(cause); |
| | | return Responses.newBindResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | } |
| | | } |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Void> abandon(final AbandonRequest request) |
| | | throws UnsupportedOperationException, IllegalStateException, |
| | | NullPointerException |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> add(final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addConnectionEventListener(final ConnectionEventListener listener) |
| | | throws IllegalStateException, NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<BindResult> bind(final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void close(final UnbindRequest request, final String reason) |
| | | { |
| | | final int i = messageID.getAndIncrement(); |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<CompareResult> compare(final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> delete(final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> FutureResult<R> extendedRequest( |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isClosed() |
| | | { |
| | | // FIXME: this should be true after close has been called. |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isValid() |
| | | { |
| | | // FIXME: this should be false if this connection is disconnected. |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modify(final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> modifyDN(final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeConnectionEventListener( |
| | | final ConnectionEventListener listener) throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<Result> search(final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | |
| | | final int i = messageID.getAndIncrement(); |
| | | final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(i, |
| | | request, resultHandler, intermediateResponseHandler, this); |
| | | serverConnection.handleSearch(i, request, future, future, future); |
| | | 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(); |
| | | } |
| | | |
| | | } |
| | |
| | | * Bind result future implementation. |
| | | */ |
| | | final class LDAPBindFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<BindResult> implements |
| | | FutureResult<BindResult> |
| | | AbstractLDAPFutureResultImpl<BindResult> |
| | | { |
| | | private final BindClient bindClient; |
| | | |
| | | |
| | | |
| | | LDAPBindFutureResultImpl(final int messageID, final BindClient bindClient, |
| | | LDAPBindFutureResultImpl(final int requestID, final BindClient bindClient, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.bindClient = bindClient; |
| | | } |
| | | |
| | |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.Connection; |
| | | import com.sun.grizzly.EmptyCompletionHandler; |
| | | import com.sun.grizzly.Grizzly; |
| | | import com.sun.grizzly.attributes.Attribute; |
| | | import com.sun.grizzly.filterchain.BaseFilter; |
| | | import com.sun.grizzly.filterchain.FilterChainContext; |
| | | import com.sun.grizzly.filterchain.NextAction; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.Connection; |
| | | import org.glassfish.grizzly.EmptyCompletionHandler; |
| | | import org.glassfish.grizzly.Grizzly; |
| | | import org.glassfish.grizzly.attributes.Attribute; |
| | | import org.glassfish.grizzly.filterchain.BaseFilter; |
| | | import org.glassfish.grizzly.filterchain.FilterChainContext; |
| | | import org.glassfish.grizzly.filterchain.NextAction; |
| | | |
| | | |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.ldap; |
| | |
| | | * Compare result future implementation. |
| | | */ |
| | | final class LDAPCompareFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<CompareResult> implements |
| | | FutureResult<CompareResult> |
| | | AbstractLDAPFutureResultImpl<CompareResult> |
| | | { |
| | | private final CompareRequest request; |
| | | |
| | | |
| | | |
| | | LDAPCompareFutureResultImpl(final int messageID, |
| | | LDAPCompareFutureResultImpl(final int requestID, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.grizzly.CompletionHandler; |
| | | import com.sun.grizzly.filterchain.DefaultFilterChain; |
| | | import com.sun.grizzly.filterchain.Filter; |
| | | import com.sun.grizzly.filterchain.FilterChain; |
| | | import com.sun.grizzly.ssl.SSLEngineConfigurator; |
| | | import com.sun.grizzly.ssl.SSLFilter; |
| | | import org.glassfish.grizzly.CompletionHandler; |
| | | import org.glassfish.grizzly.filterchain.DefaultFilterChain; |
| | | import org.glassfish.grizzly.filterchain.Filter; |
| | | import org.glassfish.grizzly.filterchain.FilterChain; |
| | | import org.glassfish.grizzly.ssl.SSLEngineConfigurator; |
| | | import org.glassfish.grizzly.ssl.SSLFilter; |
| | | import com.sun.opends.sdk.util.CompletedFutureResult; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | import com.sun.opends.sdk.util.Validator; |
| | |
| | | final class LDAPConnection extends AbstractAsynchronousConnection implements |
| | | AsynchronousConnection |
| | | { |
| | | private final com.sun.grizzly.Connection<?> connection; |
| | | private final org.glassfish.grizzly.Connection<?> connection; |
| | | |
| | | private Result connectionInvalidReason; |
| | | |
| | |
| | | |
| | | private boolean bindOrStartTLSInProgress = false; |
| | | |
| | | private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> |
| | | pendingRequests = |
| | | new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>(); |
| | | private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests = |
| | | new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>(); |
| | | |
| | | private final Object stateLock = new Object(); |
| | | |
| | |
| | | * @param options |
| | | * The LDAP client options. |
| | | */ |
| | | LDAPConnection(final com.sun.grizzly.Connection<?> connection, |
| | | LDAPConnection(final org.glassfish.grizzly.Connection<?> connection, |
| | | final LDAPOptions options) |
| | | { |
| | | this.connection = connection; |
| | |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | return new CompletedFutureResult<Void>(ErrorResultException |
| | | .wrap(connectionInvalidReason), messageID); |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(connectionInvalidReason), messageID); |
| | | } |
| | | if (bindOrStartTLSInProgress) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress"); |
| | | return new CompletedFutureResult<Void>(ErrorResultException |
| | | .wrap(errorResult), messageID); |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(errorResult), messageID); |
| | | } |
| | | |
| | | // First remove the future associated with the request to be abandoned. |
| | | pendingRequest = pendingRequests.remove(request.getMessageID()); |
| | | pendingRequest = pendingRequests.remove(request.getRequestID()); |
| | | } |
| | | |
| | | if (pendingRequest == null) |
| | |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | return new CompletedFutureResult<Void>(ErrorResultException |
| | | .wrap(errorResult), messageID); |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(errorResult), messageID); |
| | | } |
| | | } |
| | | |
| | |
| | | BindClient context; |
| | | try |
| | | { |
| | | context = request.createBindClient( |
| | | connection.getPeerAddress() instanceof InetSocketAddress ? |
| | | ((InetSocketAddress)connection.getPeerAddress()).getHostName() : |
| | | connection.getPeerAddress().toString()); |
| | | 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 Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred while creating a bind context").setCause(e); |
| | | final ErrorResultException error = ErrorResultException.wrap(errorResult); |
| | | if (resultHandler != null) |
| | | { |
| | |
| | | // 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 : ""))); |
| | | close( |
| | | request, |
| | | false, |
| | | Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setDiagnosticMessage( |
| | | "Connection closed by client" |
| | | + (reason != null ? ": " + reason : ""))); |
| | | } |
| | | |
| | | |
| | |
| | | if (bindOrStartTLSInProgress) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .adaptExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "Bind or Start TLS operation in progress")); |
| | | return future; |
| | | } |
| | |
| | | if (!pendingRequests.isEmpty()) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .adaptExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "There are pending operations on this connection")); |
| | | return future; |
| | | } |
| | | if (isTLSEnabled()) |
| | | { |
| | | future.setResultOrError(request.getResultDecoder() |
| | | .adaptExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | .newExtendedErrorResult(ResultCode.OPERATIONS_ERROR, "", |
| | | "This connection is already TLS enabled")); |
| | | } |
| | | bindOrStartTLSInProgress = true; |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@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 addPendingRequest(final AbstractLDAPFutureResultImpl<?> request) |
| | | throws ErrorResultException |
| | | { |
| | | final int newMsgID = nextMsgID.getAndIncrement(); |
| | | synchronized(stateLock) |
| | | synchronized (stateLock) |
| | | { |
| | | if(connectionInvalidReason != null) |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | throw ErrorResultException.wrap(connectionInvalidReason); |
| | | } |
| | |
| | | { |
| | | for (int requestID : pendingRequests.keySet()) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> future = |
| | | pendingRequests.get(requestID); |
| | | if(future != null) |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests |
| | | .get(requestID); |
| | | if (future != null) |
| | | { |
| | | final long diff = (future.getTimestamp() + timeout) - currentTime; |
| | | if (diff <= 0 && pendingRequests.remove(requestID) != null) |
| | |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (isClosed || connectionInvalidReason != null) |
| | | if (isClosed) { |
| | | // Already closed. |
| | | return; |
| | | } |
| | | |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | // Already closed. |
| | | isClosed = true; |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // Mark the connection as invalid. |
| | | connectionInvalidReason = |
| | | reason.getResultCode() == ResultCode.CLIENT_SIDE_USER_CANCELLED ? |
| | | reason : Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_USER_CANCELLED).setCause( |
| | | ErrorResultException.wrap(reason)).setDiagnosticMessage( |
| | | "Connection closed: " + reason.getDiagnosticMessage()); |
| | | connectionInvalidReason = reason; |
| | | } |
| | | |
| | | // First abort all outstanding requests. |
| | | for (int requestID : pendingRequests.keySet()) |
| | | { |
| | | final AbstractLDAPFutureResultImpl<?> future = |
| | | pendingRequests.remove(requestID); |
| | | if(future != null) |
| | | final AbstractLDAPFutureResultImpl<?> future = pendingRequests |
| | | .remove(requestID); |
| | | if (future != null) |
| | | { |
| | | future.adaptErrorResult(reason); |
| | | } |
| | |
| | | { |
| | | if (customFilterChain == null) |
| | | { |
| | | customFilterChain = new DefaultFilterChain((FilterChain) connection |
| | | .getProcessor()); |
| | | customFilterChain = new DefaultFilterChain( |
| | | (FilterChain) connection.getProcessor()); |
| | | connection.setProcessor(customFilterChain); |
| | | } |
| | | |
| | |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.Result; |
| | | |
| | | import com.sun.grizzly.CompletionHandler; |
| | | import com.sun.grizzly.Connection; |
| | | import com.sun.grizzly.EmptyCompletionHandler; |
| | | import com.sun.grizzly.filterchain.DefaultFilterChain; |
| | | import com.sun.grizzly.filterchain.FilterChain; |
| | | import com.sun.grizzly.filterchain.TransportFilter; |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.CompletionHandler; |
| | | import org.glassfish.grizzly.Connection; |
| | | import org.glassfish.grizzly.EmptyCompletionHandler; |
| | | import org.glassfish.grizzly.filterchain.DefaultFilterChain; |
| | | import org.glassfish.grizzly.filterchain.FilterChain; |
| | | import org.glassfish.grizzly.filterchain.TransportFilter; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | import com.sun.opends.sdk.util.CompletedFutureResult; |
| | | import com.sun.opends.sdk.util.FutureResultTransformer; |
| | | import com.sun.opends.sdk.util.RecursiveFutureResult; |
| | |
| | | // Ensure that the connection is closed. |
| | | try |
| | | { |
| | | connection.close(); |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | |
| | | @Override |
| | | public void failed(final Throwable throwable) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause( |
| | | throwable).setDiagnosticMessage( |
| | | throwable.getMessage()); |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR) |
| | | .setCause(throwable) |
| | | .setDiagnosticMessage(throwable.getMessage()); |
| | | handler.handleErrorResult(ErrorResultException |
| | | .wrap(errorResult)); |
| | | } |
| | |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | final Result errorResult = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause(ioe) |
| | | .setDiagnosticMessage(ioe.getMessage()); |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR) |
| | | .setCause(ioe).setDiagnosticMessage(ioe.getMessage()); |
| | | throw ErrorResultException.wrap(errorResult); |
| | | } |
| | | } |
| | |
| | | |
| | | this.socketAddress = address; |
| | | this.options = new LDAPOptions(options); |
| | | this.clientFilter = new LDAPClientFilter(new LDAPReader(this.options |
| | | .getDecodeOptions()), 0); |
| | | this.clientFilter = new LDAPClientFilter(new LDAPReader( |
| | | this.options.getDecodeOptions()), 0); |
| | | this.defaultFilterChain = new DefaultFilterChain(); |
| | | this.defaultFilterChain.add(new TransportFilter()); |
| | | this.defaultFilterChain.add(clientFilter); |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the address of the Directory Server. |
| | | * |
| | | * @return The address of the Directory Server. |
| | | */ |
| | | public SocketAddress getSocketAddress() |
| | | { |
| | | return socketAddress; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LDAPConnectionFactory("); |
| | | builder.append(getSocketAddress().toString()); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | private LDAPConnection adaptConnection(final Connection<?> connection) |
| | | { |
| | | // Test shows that its much faster with non block writes but risk |
| | |
| | | t = t.getCause(); |
| | | } |
| | | |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause(t).setDiagnosticMessage( |
| | | t.getMessage()); |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause(t) |
| | | .setDiagnosticMessage(t.getMessage()); |
| | | return ErrorResultException.wrap(result); |
| | | } |
| | | } |
| | |
| | | * The type of result returned by this future. |
| | | */ |
| | | final class LDAPExtendedFutureResultImpl<R extends ExtendedResult> extends |
| | | AbstractLDAPFutureResultImpl<R> implements FutureResult<R> |
| | | AbstractLDAPFutureResultImpl<R> |
| | | { |
| | | private final ExtendedRequest<R> request; |
| | | |
| | | |
| | | |
| | | LDAPExtendedFutureResultImpl(final int messageID, |
| | | LDAPExtendedFutureResultImpl(final int requestID, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | |
| | | R newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) |
| | | { |
| | | return request.getResultDecoder().adaptExtendedErrorResult(resultCode, "", |
| | | return request.getResultDecoder().newExtendedErrorResult(resultCode, "", |
| | | diagnosticMessage); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.AsynchronousConnection; |
| | | import org.opends.sdk.IntermediateResponseHandler; |
| | | import org.opends.sdk.ResultCode; |
| | | import org.opends.sdk.ResultHandler; |
| | | import org.opends.sdk.requests.Request; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.Result; |
| | |
| | | * Result future implementation. |
| | | */ |
| | | final class LDAPFutureResultImpl extends AbstractLDAPFutureResultImpl<Result> |
| | | implements FutureResult<Result> |
| | | { |
| | | private final Request request; |
| | | |
| | | |
| | | |
| | | LDAPFutureResultImpl(final int messageID, final Request request, |
| | | LDAPFutureResultImpl(final int requestID, final Request request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | } |
| | | |
| | |
| | | Result newErrorResult(final ResultCode resultCode, |
| | | final String diagnosticMessage, final Throwable cause) |
| | | { |
| | | return Responses.newResult(resultCode).setDiagnosticMessage( |
| | | diagnosticMessage).setCause(cause); |
| | | return Responses.newResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | } |
| | | } |
| | |
| | | import java.io.Closeable; |
| | | import java.io.IOException; |
| | | import java.net.SocketAddress; |
| | | import java.util.logging.Level; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import org.glassfish.grizzly.filterchain.DefaultFilterChain; |
| | | import org.glassfish.grizzly.filterchain.FilterChain; |
| | | import org.glassfish.grizzly.filterchain.TransportFilter; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOServerConnection; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.ssl.SSLEngineConfigurator; |
| | | import org.glassfish.grizzly.ssl.SSLFilter; |
| | | import org.opends.sdk.DecodeOptions; |
| | | import org.opends.sdk.LDAPClientContext; |
| | | import org.opends.sdk.LDAPListenerOptions; |
| | | import org.opends.sdk.ServerConnectionFactory; |
| | | |
| | | import com.sun.grizzly.filterchain.DefaultFilterChain; |
| | | import com.sun.grizzly.filterchain.FilterChain; |
| | | import com.sun.grizzly.filterchain.TransportFilter; |
| | | import com.sun.grizzly.nio.transport.TCPNIOServerConnection; |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import com.sun.grizzly.ssl.SSLEngineConfigurator; |
| | | import com.sun.grizzly.ssl.SSLFilter; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void close() throws IOException |
| | | @Override |
| | | public void close() |
| | | { |
| | | transport.unbind(serverConnection); |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 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(); |
| | | } |
| | | |
| | | |
| | |
| | | * Search result future implementation. |
| | | */ |
| | | final class LDAPSearchFutureResultImpl extends |
| | | AbstractLDAPFutureResultImpl<Result> implements FutureResult<Result>, |
| | | SearchResultHandler |
| | | AbstractLDAPFutureResultImpl<Result> implements SearchResultHandler |
| | | { |
| | | |
| | | private SearchResultHandler searchResultHandler; |
| | |
| | | |
| | | |
| | | |
| | | LDAPSearchFutureResultImpl(final int messageID, final SearchRequest request, |
| | | LDAPSearchFutureResultImpl(final int requestID, final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final AsynchronousConnection connection) |
| | | { |
| | | super(messageID, resultHandler, intermediateResponseHandler, connection); |
| | | super(requestID, resultHandler, intermediateResponseHandler, connection); |
| | | this.request = request; |
| | | this.searchResultHandler = resultHandler; |
| | | } |
| | |
| | | |
| | | import java.io.IOException; |
| | | import java.net.InetSocketAddress; |
| | | import java.util.*; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.Map; |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | import javax.net.ssl.SSLEngine; |
| | | |
| | | 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.ssl.SSLEngineConfigurator; |
| | | import org.glassfish.grizzly.ssl.SSLFilter; |
| | | import org.glassfish.grizzly.ssl.SSLUtils; |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.Connection; |
| | | import com.sun.grizzly.Grizzly; |
| | | import com.sun.grizzly.attributes.Attribute; |
| | | import com.sun.grizzly.filterchain.*; |
| | | import com.sun.grizzly.ssl.SSLEngineConfigurator; |
| | | import com.sun.grizzly.ssl.SSLFilter; |
| | | import com.sun.grizzly.ssl.SSLUtils; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | |
| | | |
| | | |
| | | @Override |
| | | public boolean handleIntermediateResponse( |
| | | public final boolean handleIntermediateResponse( |
| | | final IntermediateResponse response) |
| | | { |
| | | final ASN1BufferWriter asn1Writer = ASN1BufferWriter.getWriter(); |
| | |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | private final Connection<?> connection; |
| | | |
| | | // Connection state guarded by stateLock. |
| | | private final Object stateLock = new Object(); |
| | | private List<ConnectionEventListener> connectionEventListeners = null; |
| | | private boolean isClosed = false; |
| | | private Throwable connectionError = null; |
| | | private ExtendedResult disconnectNotification = null; |
| | | private volatile boolean isClosed = false; |
| | | |
| | | private ServerConnection<Integer> serverConnection = null; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addConnectionEventListener( |
| | | final ConnectionEventListener listener) throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | |
| | | boolean invokeImmediately = false; |
| | | synchronized (stateLock) |
| | | { |
| | | if (isClosed) |
| | | { |
| | | invokeImmediately = true; |
| | | } |
| | | else |
| | | { |
| | | if (connectionEventListeners == null) |
| | | { |
| | | connectionEventListeners = new LinkedList<ConnectionEventListener>(); |
| | | } |
| | | connectionEventListeners.add(listener); |
| | | } |
| | | } |
| | | |
| | | // Invoke listener immediately if this connection is already closed. |
| | | if (invokeImmediately) |
| | | { |
| | | invokeListener(listener); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void disconnect() |
| | | { |
| | | LDAPServerFilter.notifyConnectionClosed(connection, -1, null); |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, null, null); |
| | | } |
| | | |
| | | |
| | |
| | | .newGenericExtendedResult(resultCode) |
| | | .setOID(OID_NOTICE_OF_DISCONNECTION).setDiagnosticMessage(message); |
| | | sendUnsolicitedNotification(notification); |
| | | disconnect(); |
| | | LDAPServerFilter.notifyConnectionDisconnected(connection, resultCode, |
| | | message); |
| | | } |
| | | |
| | | |
| | |
| | | @Override |
| | | public boolean isClosed() |
| | | { |
| | | final boolean tmp; |
| | | synchronized (stateLock) |
| | | { |
| | | tmp = isClosed; |
| | | } |
| | | return tmp; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeConnectionEventListener( |
| | | final ConnectionEventListener listener) throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (connectionEventListeners != null) |
| | | { |
| | | connectionEventListeners.remove(listener); |
| | | } |
| | | } |
| | | return isClosed; |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | asn1Writer.recycle(); |
| | | } |
| | | |
| | | // Update state and notify event listeners if necessary, only if the |
| | | // notification was sent successfully. |
| | | if (notification.getOID().equals(OID_NOTICE_OF_DISCONNECTION)) |
| | | { |
| | | // Don't notify listeners yet - wait for disconnect. |
| | | synchronized (stateLock) |
| | | { |
| | | disconnectNotification = notification; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // Notify listeners. |
| | | List<ConnectionEventListener> tmpList = null; |
| | | synchronized (stateLock) |
| | | { |
| | | if (!isClosed && connectionEventListeners != null) |
| | | { |
| | | tmpList = new ArrayList<ConnectionEventListener>( |
| | | connectionEventListeners); |
| | | } |
| | | } |
| | | |
| | | if (tmpList != null) |
| | | { |
| | | for (final ConnectionEventListener listener : tmpList) |
| | | { |
| | | listener.handleUnsolicitedNotification(notification); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@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 invokeListener(final ConnectionEventListener listener) |
| | | { |
| | | if (connectionError != null) |
| | | { |
| | | final Result result; |
| | | if (connectionError instanceof DecodeException) |
| | | { |
| | | final DecodeException e = (DecodeException) connectionError; |
| | | result = Responses.newResult(ResultCode.PROTOCOL_ERROR) |
| | | .setDiagnosticMessage(e.getMessage()).setCause(connectionError); |
| | | } |
| | | else |
| | | { |
| | | result = Responses.newResult(ResultCode.OTHER) |
| | | .setDiagnosticMessage(connectionError.getMessage()) |
| | | .setCause(connectionError); |
| | | } |
| | | listener |
| | | .handleConnectionError(false, ErrorResultException.wrap(result)); |
| | | } |
| | | else if (disconnectNotification != null) |
| | | { |
| | | listener.handleConnectionError(true, |
| | | ErrorResultException.wrap(disconnectNotification)); |
| | | } |
| | | else |
| | | { |
| | | listener.handleConnectionClosed(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void notifyConnectionClosed(final int messageID, |
| | | final UnbindRequest unbindRequest) |
| | | { |
| | | final List<ConnectionEventListener> tmpList; |
| | | synchronized (stateLock) |
| | | { |
| | | if (!isClosed) |
| | | { |
| | | isClosed = true; |
| | | } |
| | | tmpList = connectionEventListeners; |
| | | connectionEventListeners = null; |
| | | } |
| | | if (tmpList != null) |
| | | { |
| | | for (final ConnectionEventListener listener : tmpList) |
| | | { |
| | | invokeListener(listener); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void notifyConnectionException(final Throwable error) |
| | | { |
| | | final List<ConnectionEventListener> tmpList; |
| | | synchronized (stateLock) |
| | | { |
| | | if (!isClosed) |
| | | { |
| | | connectionError = error; |
| | | isClosed = true; |
| | | } |
| | | tmpList = connectionEventListeners; |
| | | connectionEventListeners = null; |
| | | } |
| | | if (tmpList != null) |
| | | { |
| | | for (final ConnectionEventListener listener : tmpList) |
| | | { |
| | | invokeListener(listener); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void setServerConnection( |
| | | final ServerConnection<Integer> serverConnection) |
| | | { |
| | |
| | | private static final LDAPWriter LDAP_WRITER = new LDAPWriter(); |
| | | |
| | | private static final Attribute<ClientContextImpl> LDAP_CONNECTION_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER |
| | | .createAttribute("LDAPServerConnection"); |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPServerConnection"); |
| | | |
| | | private static final Attribute<ASN1BufferReader> LDAP_ASN1_READER_ATTR = |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER |
| | | .createAttribute("LDAPASN1Reader"); |
| | | Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute("LDAPASN1Reader"); |
| | | |
| | | |
| | | |
| | |
| | | .remove(connection); |
| | | if (clientContext != null) |
| | | { |
| | | // First notify connection event listeners. |
| | | clientContext.notifyConnectionClosed(messageID, unbindRequest); |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is invoked |
| | | // during accept. |
| | |
| | | |
| | | |
| | | |
| | | private static void notifyConnectionException(final Connection<?> connection, |
| | | final Throwable error) |
| | | private static void notifyConnectionDisconnected( |
| | | final Connection<?> connection, final ResultCode resultCode, |
| | | final String message) |
| | | { |
| | | final ClientContextImpl clientContext = LDAP_CONNECTION_ATTR |
| | | .remove(connection); |
| | | if (clientContext != null) |
| | | { |
| | | // First notify connection event listeners. |
| | | clientContext.notifyConnectionException(error); |
| | | // Close the connection context. |
| | | clientContext.close(); |
| | | |
| | | // Notify the server connection: it may be null if disconnect is invoked |
| | | // during accept. |
| | |
| | | .getServerConnection(); |
| | | if (serverConnection != null) |
| | | { |
| | | serverConnection.handleConnectionException(error); |
| | | 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. |
| | |
| | | ctx.getConnection()).getServerConnection(); |
| | | final SearchHandler handler = new SearchHandler(messageID, |
| | | ctx.getConnection()); |
| | | conn.handleSearch(messageID, request, handler, handler, handler); |
| | | conn.handleSearch(messageID, request, handler, handler); |
| | | } |
| | | |
| | | |
| | |
| | | new UnsupportedMessageException(messageID, messageTag, messageBytes)); |
| | | } |
| | | }; |
| | | |
| | | private final int maxASN1ElementSize; |
| | | |
| | | private final LDAPReader ldapReader; |
| | |
| | | { |
| | | final ClientContextImpl clientContext = new ClientContextImpl(connection); |
| | | final ServerConnection<Integer> serverConn = listener |
| | | .getConnectionFactory().accept(clientContext); |
| | | .getConnectionFactory().handleAccept(clientContext); |
| | | clientContext.setServerConnection(serverConn); |
| | | LDAP_CONNECTION_ATTR.set(connection, clientContext); |
| | | } |
| | |
| | | |
| | | |
| | | private synchronized void installFilter(final Connection<?> connection, |
| | | final com.sun.grizzly.filterchain.Filter filter) |
| | | final org.glassfish.grizzly.filterchain.Filter filter) |
| | | { |
| | | FilterChain filterChain = (FilterChain) connection.getProcessor(); |
| | | if (filter instanceof SSLFilter) |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.ldap; |
| | |
| | | request)); |
| | | } |
| | | encodeMessageHeader(writer, messageID); |
| | | writer.writeInteger(OP_TYPE_ABANDON_REQUEST, request.getMessageID()); |
| | | writer.writeInteger(OP_TYPE_ABANDON_REQUEST, request.getRequestID()); |
| | | encodeMessageFooter(writer, request); |
| | | } |
| | | |
| | |
| | | import org.opends.sdk.ConnectionSecurityLayer; |
| | | import org.opends.sdk.ErrorResultException; |
| | | |
| | | import com.sun.grizzly.*; |
| | | import com.sun.grizzly.attributes.AttributeStorage; |
| | | import com.sun.grizzly.memory.MemoryManager; |
| | | import com.sun.grizzly.memory.MemoryUtils; |
| | | import org.glassfish.grizzly.*; |
| | | import org.glassfish.grizzly.attributes.AttributeStorage; |
| | | import org.glassfish.grizzly.memory.Buffers; |
| | | import org.glassfish.grizzly.memory.MemoryManager; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | try |
| | | { |
| | | final Buffer output = MemoryUtils.wrap(memoryManager, bindContext.unwrap( |
| | | final Buffer output = Buffers.wrap(memoryManager, bindContext.unwrap( |
| | | buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } |
| | |
| | | import org.opends.sdk.ConnectionSecurityLayer; |
| | | import org.opends.sdk.ErrorResultException; |
| | | |
| | | import com.sun.grizzly.*; |
| | | import com.sun.grizzly.attributes.AttributeStorage; |
| | | import com.sun.grizzly.memory.MemoryManager; |
| | | import com.sun.grizzly.memory.MemoryUtils; |
| | | import org.glassfish.grizzly.*; |
| | | import org.glassfish.grizzly.attributes.AttributeStorage; |
| | | import org.glassfish.grizzly.memory.Buffers; |
| | | import org.glassfish.grizzly.memory.MemoryManager; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | try |
| | | { |
| | | final Buffer output = MemoryUtils.wrap(memoryManager, bindContext.wrap( |
| | | final Buffer output = Buffers.wrap(memoryManager, bindContext.wrap( |
| | | buffer, 0, len)); |
| | | return TransformationResult.createCompletedResult(output, input); |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.ldap; |
| | |
| | | |
| | | import org.opends.sdk.ConnectionSecurityLayer; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.filterchain.AbstractCodecFilter; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.filterchain.AbstractCodecFilter; |
| | | |
| | | |
| | | |
| | |
| | | import java.util.concurrent.locks.Condition; |
| | | import java.util.concurrent.locks.ReentrantLock; |
| | | |
| | | import com.sun.grizzly.utils.LinkedTransferQueue; |
| | | import org.glassfish.grizzly.utils.LinkedTransferQueue; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | return connFactory.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | private String getKDC() throws ArgumentException, CLIException |
| | | { |
| | | String value = null; |
| | |
| | | * operations with the exception of Bind requests. Attempts to perform a Bind |
| | | * will result in an {@code UnsupportedOperationException}. |
| | | * <p> |
| | | * In addition, the returned connections support retrieval of the {@code |
| | | * BindResult} returned from the initial Bind request, or last rebind. |
| | | * In addition, the returned connections support retrieval of the |
| | | * {@code BindResult} returned from the initial Bind request, or last rebind. |
| | | * <p> |
| | | * Support for connection re-authentication is provided through the |
| | | * {@link #setRebindAllowed} method which, if set to {@code true}, causes |
| | | * subsequent connections created using the factory to support the {@code |
| | | * rebind} method. |
| | | * subsequent connections created using the factory to support the |
| | | * {@code rebind} method. |
| | | * <p> |
| | | * If the Bind request fails for some reason (e.g. invalid credentials), then |
| | | * the connection attempt will fail and an {@code ErrorResultException} will be |
| | |
| | | * @throws UnsupportedOperationException |
| | | * If this connection does not support rebind operations. |
| | | * @throws IllegalStateException |
| | | * If this connection has already been closed, i.e. if {@code |
| | | * isClosed() == true}. |
| | | * If this connection has already been closed, i.e. if |
| | | * {@code isClosed() == true}. |
| | | */ |
| | | public FutureResult<BindResult> rebind( |
| | | final ResultHandler<? super BindResult> handler) |
| | |
| | | return connection.searchSingleEntry(request, resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("AuthenticatedConnection("); |
| | | builder.append(connection); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | * @throws UnsupportedOperationException |
| | | * If this connection does not support rebind operations. |
| | | * @throws IllegalStateException |
| | | * If this connection has already been closed, i.e. if {@code |
| | | * isClosed() == true}. |
| | | * If this connection has already been closed, i.e. if |
| | | * {@code isClosed() == true}. |
| | | */ |
| | | public BindResult rebind() throws ErrorResultException, |
| | | InterruptedException, UnsupportedOperationException, |
| | |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("AuthenticatedConnectionFactory("); |
| | | builder.append(String.valueOf(parentFactory)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.util; |
| | | |
| | | |
| | | |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.TimeoutException; |
| | | import java.util.concurrent.locks.AbstractQueuedSynchronizer; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.Result; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides a skeletal implementation of the {@code FutureResult} |
| | | * interface, to minimize the effort required to implement this interface. |
| | | * <p> |
| | | * This {@code FutureResult} implementation provides the following features: |
| | | * <ul> |
| | | * <li>The {@link #get} methods throw {@link ErrorResultException}s instead of |
| | | * the more generic {@code ExecutionException}s. |
| | | * <li>The {@link #get} methods never throw {@code CancellationException} since |
| | | * requests in this SDK can usually be cancelled via other external means (e.g. |
| | | * the {@code Cancel} extended operation) for which there are well defined error |
| | | * results. Therefore cancellation is always signalled by throwing a |
| | | * {@link CancelledResultException} in order to be consistent with other error |
| | | * results. |
| | | * <li>A {@link ResultHandler} can be provided to the constructor. The result |
| | | * handler will be invoked immediately after the result or error is received but |
| | | * before threads blocked on {@link #get} are released. More specifically, |
| | | * result handler invocation <i>happens-before</i> a call to {@link #get}. |
| | | * <b>NOTE:</b> a result handler which attempts to call {@link #get} will |
| | | * deadlock. |
| | | * <li>Sub-classes may choose to implement specific cancellation cleanup by |
| | | * implementing the {@link #handleCancelRequest} method. |
| | | * </ul> |
| | | * |
| | | * @param <M> |
| | | * The type of result returned by this completion future. |
| | | */ |
| | | public class AsynchronousFutureResult<M> implements FutureResult<M>, |
| | | ResultHandler<M> |
| | | { |
| | | @SuppressWarnings("serial") |
| | | private final class Sync extends AbstractQueuedSynchronizer |
| | | { |
| | | // State value representing the initial state before a result has |
| | | // been received. |
| | | private static final int WAITING = 0; |
| | | |
| | | // State value representing that a result has been received and is |
| | | // being processed. |
| | | private static final int PENDING = 1; |
| | | |
| | | // State value representing that the request was cancelled. |
| | | private static final int CANCELLED = 2; |
| | | |
| | | // State value representing that the request has failed. |
| | | private static final int FAIL = 3; |
| | | |
| | | // State value representing that the request has succeeded. |
| | | private static final int SUCCESS = 4; |
| | | |
| | | // These do not need to be volatile since their values are published |
| | | // by updating the state after they are set and reading the state |
| | | // immediately before they are read. |
| | | private ErrorResultException errorResult = null; |
| | | |
| | | private M result = null; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Allow all threads to acquire if future has completed. |
| | | */ |
| | | @Override |
| | | protected int tryAcquireShared(final int ignore) |
| | | { |
| | | return innerIsDone() ? 1 : -1; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Signal that the future has completed and threads waiting on get() can be |
| | | * released. |
| | | */ |
| | | @Override |
| | | protected boolean tryReleaseShared(final int finalState) |
| | | { |
| | | // Ensures that errorResult/result is published. |
| | | setState(finalState); |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | boolean innerCancel(final boolean mayInterruptIfRunning) |
| | | { |
| | | if (!isCancelable() || !setStatePending()) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // Perform implementation defined cancellation. |
| | | ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning); |
| | | if (errorResult == null) |
| | | { |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED); |
| | | errorResult = ErrorResultException.wrap(result); |
| | | } |
| | | this.errorResult = errorResult; |
| | | |
| | | try |
| | | { |
| | | // Invoke error result completion handler. |
| | | if (handler != null) |
| | | { |
| | | handler.handleErrorResult(errorResult); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | releaseShared(CANCELLED); // Publishes errorResult. |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | M innerGet() throws ErrorResultException, InterruptedException |
| | | { |
| | | acquireSharedInterruptibly(0); |
| | | return get0(); |
| | | } |
| | | |
| | | |
| | | |
| | | M innerGet(final long nanosTimeout) throws ErrorResultException, |
| | | TimeoutException, InterruptedException |
| | | { |
| | | if (!tryAcquireSharedNanos(0, nanosTimeout)) |
| | | { |
| | | throw new TimeoutException(); |
| | | } |
| | | else |
| | | { |
| | | return get0(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | boolean innerIsCancelled() |
| | | { |
| | | return getState() == CANCELLED; |
| | | } |
| | | |
| | | |
| | | |
| | | boolean innerIsDone() |
| | | { |
| | | return getState() > 1; |
| | | } |
| | | |
| | | |
| | | |
| | | void innerSetErrorResult(final ErrorResultException errorResult) |
| | | { |
| | | if (setStatePending()) |
| | | { |
| | | this.errorResult = errorResult; |
| | | |
| | | try |
| | | { |
| | | // Invoke error result completion handler. |
| | | if (handler != null) |
| | | { |
| | | handler.handleErrorResult(errorResult); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | releaseShared(FAIL); // Publishes errorResult. |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | void innerSetResult(final M result) |
| | | { |
| | | if (setStatePending()) |
| | | { |
| | | this.result = result; |
| | | |
| | | try |
| | | { |
| | | // Invoke result completion handler. |
| | | if (handler != null) |
| | | { |
| | | handler.handleResult(result); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | releaseShared(SUCCESS); // Publishes result. |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private M get0() throws ErrorResultException |
| | | { |
| | | if (errorResult != null) |
| | | { |
| | | // State must be FAILED or CANCELLED. |
| | | throw errorResult; |
| | | } |
| | | else |
| | | { |
| | | // State must be SUCCESS. |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean setStatePending() |
| | | { |
| | | for (;;) |
| | | { |
| | | final int s = getState(); |
| | | if (s != WAITING) |
| | | { |
| | | return false; |
| | | } |
| | | if (compareAndSetState(s, PENDING)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final Sync sync = new Sync(); |
| | | |
| | | private final ResultHandler<? super M> handler; |
| | | |
| | | private final int requestID; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new asynchronous future result with the provided result handler |
| | | * and a request ID of -1. |
| | | * |
| | | * @param handler |
| | | * A result handler which will be forwarded the result or error when |
| | | * it arrives, may be {@code null}. |
| | | */ |
| | | public AsynchronousFutureResult(final ResultHandler<? super M> handler) |
| | | { |
| | | this(handler, -1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new asynchronous future result with the provided result handler |
| | | * and request ID. |
| | | * |
| | | * @param handler |
| | | * A result handler which will be forwarded the result or error when |
| | | * it arrives, may be {@code null}. |
| | | * @param requestID |
| | | * The request ID which will be returned by the default |
| | | * implementation of {@link #getRequestID}. |
| | | */ |
| | | public AsynchronousFutureResult(final ResultHandler<? super M> handler, |
| | | final int requestID) |
| | | { |
| | | this.handler = handler; |
| | | this.requestID = requestID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean cancel(final boolean mayInterruptIfRunning) |
| | | { |
| | | return sync.innerCancel(mayInterruptIfRunning); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final M get() throws ErrorResultException, InterruptedException |
| | | { |
| | | return sync.innerGet(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final M get(final long timeout, final TimeUnit unit) |
| | | throws ErrorResultException, TimeoutException, InterruptedException |
| | | { |
| | | return sync.innerGet(unit.toNanos(timeout)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * <p> |
| | | * The default implementation returns the request ID passed in during |
| | | * construction, or -1 if none was provided. |
| | | */ |
| | | @Override |
| | | public int getRequestID() |
| | | { |
| | | return requestID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the error result associated with this future. If ({@code isDone() == |
| | | * true}) then the error result will be ignored, otherwise the result handler |
| | | * will be invoked if one was provided and, on return, any threads waiting on |
| | | * {@link #get} will be released and the provided error result will be thrown. |
| | | * |
| | | * @param errorResult |
| | | * The error result. |
| | | */ |
| | | @Override |
| | | public final void handleErrorResult(final ErrorResultException errorResult) |
| | | { |
| | | sync.innerSetErrorResult(errorResult); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the result associated with this future. If ({@code isDone() == true}) |
| | | * then the result will be ignored, otherwise the result handler will be |
| | | * invoked if one was provided and, on return, any threads waiting on |
| | | * {@link #get} will be released and the provided result will be returned. |
| | | * |
| | | * @param result |
| | | * The result. |
| | | */ |
| | | @Override |
| | | public final void handleResult(final M result) |
| | | { |
| | | sync.innerSetResult(result); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean isCancelled() |
| | | { |
| | | return sync.innerIsCancelled(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final boolean isDone() |
| | | { |
| | | return sync.innerIsDone(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Invoked when {@link #cancel} is called and {@code isDone() == false} and |
| | | * immediately before any threads waiting on {@link #get} are released. |
| | | * Implementations may choose to return a custom error result if needed or |
| | | * return {@code null} if the following default error result is acceptable: |
| | | * |
| | | * <pre> |
| | | * Result result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED); |
| | | * </pre> |
| | | * |
| | | * In addition, implementations may perform other cleanup, for example, by |
| | | * issuing an LDAP abandon request. The default implementation is to do |
| | | * nothing. |
| | | * |
| | | * @param mayInterruptIfRunning |
| | | * {@code true} if the thread executing executing the response |
| | | * handler should be interrupted; otherwise, in-progress response |
| | | * handlers are allowed to complete. |
| | | * @return The custom error result, or {@code null} if the default is |
| | | * acceptable. |
| | | */ |
| | | protected ErrorResultException handleCancelRequest( |
| | | final boolean mayInterruptIfRunning) |
| | | { |
| | | // Do nothing by default. |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this future result can be canceled. |
| | | * |
| | | * @return {@code true} if this future result is cancelable or {@code false} |
| | | * otherwise. |
| | | */ |
| | | protected boolean isCancelable() |
| | | { |
| | | // Return true by default. |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Appends a string representation of this future's state to the provided |
| | | * builder. |
| | | * |
| | | * @param sb |
| | | * The string builder. |
| | | */ |
| | | protected void toString(final StringBuilder sb) |
| | | { |
| | | sb.append(" state = "); |
| | | sb.append(sync); |
| | | } |
| | | |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.util; |
| | |
| | | public abstract class RecursiveFutureResult<M, N> implements FutureResult<N>, |
| | | ResultHandler<M> |
| | | { |
| | | private final class FutureResultImpl extends AbstractFutureResult<N> |
| | | private final class FutureResultImpl extends AsynchronousFutureResult<N> |
| | | { |
| | | private FutureResultImpl(final ResultHandler<? super N> handler) |
| | | { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package com.sun.opends.sdk.util; |
| | |
| | | import java.lang.reflect.InvocationTargetException; |
| | | import java.text.ParseException; |
| | | import java.util.*; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.ThreadFactory; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.logging.Level; |
| | | import java.util.logging.Logger; |
| | | import java.util.zip.DataFormatException; |
| | |
| | | private static final TimeZone TIME_ZONE_UTC_OBJ = TimeZone |
| | | .getTimeZone(TIME_ZONE_UTC); |
| | | |
| | | private static ScheduledExecutorService defaultScheduler = null; |
| | | |
| | | private static final Object DEFAULT_SCHEDULER_LOCK = new Object(); |
| | | |
| | | |
| | | |
| | | /** |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the default scheduler which should be used by the SDK. |
| | | * |
| | | * @return The default scheduler. |
| | | */ |
| | | public static ScheduledExecutorService getDefaultScheduler() |
| | | { |
| | | synchronized (DEFAULT_SCHEDULER_LOCK) |
| | | { |
| | | if (defaultScheduler == null) |
| | | { |
| | | final ThreadFactory factory = newThreadFactory(null, |
| | | "OpenDS SDK Default Scheduler", true); |
| | | defaultScheduler = Executors.newSingleThreadScheduledExecutor(factory); |
| | | } |
| | | } |
| | | return defaultScheduler; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the best human-readable message for the provided exception. For |
| | | * exceptions defined in the OpenDS project, it will attempt to use the |
| | | * message (combining it with the message ID if available). For some |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns a string whose content is the string representation of the objects |
| | | * contained in the provided collection concatenated together using the |
| | | * provided separator. |
| | | * |
| | | * @param c |
| | | * The collection whose elements are to be joined. |
| | | * @param separator |
| | | * The separator string. |
| | | * @return A string whose content is the string representation of the objects |
| | | * contained in the provided collection concatenated together using |
| | | * the provided separator. |
| | | * @throws NullPointerException |
| | | * If {@code c} or {@code separator} were {@code null}. |
| | | */ |
| | | public static String joinCollection(Collection<?> c, String separator) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(c, separator); |
| | | |
| | | switch (c.size()) |
| | | { |
| | | case 0: |
| | | return ""; |
| | | case 1: |
| | | return String.valueOf(c.iterator().next()); |
| | | default: |
| | | StringBuilder builder = new StringBuilder(); |
| | | Iterator<?> i = c.iterator(); |
| | | builder.append(i.next()); |
| | | while (i.hasNext()) |
| | | { |
| | | builder.append(separator); |
| | | builder.append(i.next()); |
| | | } |
| | | String s = builder.toString(); |
| | | return s; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new thread factory which will create threads using the specified |
| | | * thread group, naming template, and daemon status. |
| | | * |
| | | * @param group |
| | | * The thread group, which may be {@code null}. |
| | | * @param nameTemplate |
| | | * The thread name format string which may contain a "%d" format |
| | | * option which will be substituted with the thread count. |
| | | * @param isDaemon |
| | | * Indicates whether or not threads should be daemon threads. |
| | | * @return The new thread factory. |
| | | */ |
| | | public static ThreadFactory newThreadFactory(final ThreadGroup group, |
| | | final String nameTemplate, final boolean isDaemon) |
| | | { |
| | | return new ThreadFactory() |
| | | { |
| | | private final AtomicInteger count = new AtomicInteger(); |
| | | |
| | | |
| | | |
| | | public Thread newThread(Runnable r) |
| | | { |
| | | final String name = String |
| | | .format(nameTemplate, count.getAndIncrement()); |
| | | final Thread t = new Thread(group, r, name); |
| | | t.setDaemon(isDaemon); |
| | | return t; |
| | | } |
| | | }; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns a string representation of the contents of the provided byte |
| | | * sequence using hexadecimal characters and a space between each byte. |
| | | * |
| | |
| | | |
| | | |
| | | /** |
| | | * This class provides a skeletal implementation of the {@code |
| | | * AsynchronousConnection} interface, to minimize the effort required to |
| | | * This class provides a skeletal implementation of the |
| | | * {@code AsynchronousConnection} interface, to minimize the effort required to |
| | | * implement this interface. |
| | | */ |
| | | public abstract class AbstractAsynchronousConnection implements |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | public FutureResult<Result> search(final SearchRequest request, |
| | | final SearchResultHandler handler) |
| | | throws UnsupportedOperationException, IllegalStateException, |
| | | NullPointerException |
| | | final SearchResultHandler handler) throws UnsupportedOperationException, |
| | | IllegalStateException, NullPointerException |
| | | { |
| | | return search(request, handler, null); |
| | | } |
| | |
| | | innerFuture.setResultFuture(future); |
| | | return innerFuture; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * <p> |
| | | * Sub-classes should provide an implementation which returns an appropriate |
| | | * description of the connection which may be used for debugging purposes. |
| | | */ |
| | | public abstract String toString(); |
| | | |
| | | } |
| | |
| | | return searchSingleEntry(request); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * <p> |
| | | * Sub-classes should provide an implementation which returns an appropriate |
| | | * description of the connection which may be used for debugging purposes. |
| | | */ |
| | | public abstract String toString(); |
| | | |
| | | } |
| | |
| | | { |
| | | return getAsynchronousConnection(null).get().getSynchronousConnection(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public abstract String toString(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.ScheduledFuture; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.logging.Level; |
| | | |
| | | import org.opends.sdk.responses.Responses; |
| | | |
| | | import com.sun.opends.sdk.util.AsynchronousFutureResult; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An abstract load balancing algorithm providing monitoring and failover |
| | | * capabilities. |
| | | * <p> |
| | | * Implementations should override the method |
| | | * {@code getInitialConnectionFactoryIndex()} in order to provide the policy for |
| | | * selecting the first connection factory to use for each connection request. |
| | | */ |
| | | abstract class AbstractLoadBalancingAlgorithm implements LoadBalancingAlgorithm |
| | | { |
| | | private final class MonitoredConnectionFactory extends |
| | | AbstractConnectionFactory implements |
| | | ResultHandler<AsynchronousConnection> |
| | | { |
| | | |
| | | private final ConnectionFactory factory; |
| | | |
| | | private final AtomicBoolean isOperational = new AtomicBoolean(true); |
| | | |
| | | private volatile FutureResult<?> pendingConnectFuture = null; |
| | | |
| | | private final int index; |
| | | |
| | | |
| | | |
| | | private MonitoredConnectionFactory(final ConnectionFactory factory, |
| | | final int index) |
| | | { |
| | | this.factory = factory; |
| | | this.index = index; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<AsynchronousConnection> getAsynchronousConnection( |
| | | final ResultHandler<? super AsynchronousConnection> resultHandler) |
| | | { |
| | | final AsynchronousFutureResult<AsynchronousConnection> future = |
| | | new AsynchronousFutureResult<AsynchronousConnection>(resultHandler); |
| | | |
| | | final ResultHandler<AsynchronousConnection> failoverHandler = |
| | | new ResultHandler<AsynchronousConnection>() |
| | | { |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | // Attempt failed - try next factory. |
| | | notifyOffline(error); |
| | | |
| | | final int nextIndex = (index + 1) % monitoredFactories.size(); |
| | | try |
| | | { |
| | | final MonitoredConnectionFactory nextFactory = |
| | | getMonitoredConnectionFactory(nextIndex); |
| | | nextFactory.getAsynchronousConnection(future); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | future.handleErrorResult(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final AsynchronousConnection result) |
| | | { |
| | | notifyOnline(); |
| | | future.handleResult(result); |
| | | } |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(failoverHandler); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handle monitoring connection request failure. |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | notifyOffline(error); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Handle monitoring connection request success. |
| | | */ |
| | | @Override |
| | | public void handleResult(final AsynchronousConnection connection) |
| | | { |
| | | notifyOnline(); |
| | | |
| | | // The connection is not going to be used, so close it immediately. |
| | | connection.close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return factory.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Attempt to connect to the factory if it is offline and there is no |
| | | * pending monitoring request. |
| | | */ |
| | | private synchronized void checkIfAvailable() |
| | | { |
| | | if (!isOperational.get() |
| | | && (pendingConnectFuture == null || pendingConnectFuture.isDone())) |
| | | { |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String |
| | | .format("Attempting connect on factory " + this)); |
| | | } |
| | | pendingConnectFuture = factory.getAsynchronousConnection(this); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void notifyOffline(final ErrorResultException error) |
| | | { |
| | | if (isOperational.getAndSet(false)) |
| | | { |
| | | // Transition from online to offline. |
| | | synchronized (stateLock) |
| | | { |
| | | offlineFactoriesCount++; |
| | | if (offlineFactoriesCount == 1) |
| | | { |
| | | // Enable monitoring. |
| | | monitoringFuture = scheduler.scheduleWithFixedDelay( |
| | | new MonitorThread(), 0, monitoringInterval, |
| | | monitoringIntervalTimeUnit); |
| | | } |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.fine(String.format("Connection factory " |
| | | + factory + " is no longer operational: " + error.getMessage())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void notifyOnline() |
| | | { |
| | | if (!isOperational.getAndSet(true)) |
| | | { |
| | | // Transition from offline to online. |
| | | synchronized (stateLock) |
| | | { |
| | | offlineFactoriesCount--; |
| | | if (offlineFactoriesCount == 0) |
| | | { |
| | | monitoringFuture.cancel(false); |
| | | monitoringFuture = null; |
| | | } |
| | | } |
| | | |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINE)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.fine(String.format("Connection factory " |
| | | + factory + " is now operational")); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class MonitorThread implements Runnable |
| | | { |
| | | private MonitorThread() |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void run() |
| | | { |
| | | for (final MonitoredConnectionFactory factory : monitoredFactories) |
| | | { |
| | | factory.checkIfAvailable(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final List<MonitoredConnectionFactory> monitoredFactories; |
| | | |
| | | private final ScheduledExecutorService scheduler; |
| | | |
| | | private final Object stateLock = new Object(); |
| | | |
| | | // Guarded by stateLock. |
| | | private int offlineFactoriesCount = 0; |
| | | |
| | | private final long monitoringInterval; |
| | | |
| | | private final TimeUnit monitoringIntervalTimeUnit; |
| | | |
| | | // Guarded by stateLock. |
| | | private ScheduledFuture<?> monitoringFuture; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new abstract load balancing algorithm. |
| | | * |
| | | * @param factories |
| | | * The connection factories. |
| | | */ |
| | | AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories) |
| | | { |
| | | this(factories, StaticUtils.getDefaultScheduler()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new abstract load balancing algorithm. |
| | | * |
| | | * @param factories |
| | | * The connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring dead |
| | | * connection factories to see if they are usable again. |
| | | */ |
| | | AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler) |
| | | { |
| | | this(factories, StaticUtils.getDefaultScheduler(), 10, TimeUnit.SECONDS); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new abstract load balancing algorithm. |
| | | * |
| | | * @param factories |
| | | * The connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring dead |
| | | * connection factories to see if they are usable again. |
| | | * @param interval |
| | | * The interval between attempts to poll offline factories. |
| | | * @param unit |
| | | * The time unit for the interval between attempts to poll offline |
| | | * factories. |
| | | */ |
| | | AbstractLoadBalancingAlgorithm(final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler, final long interval, |
| | | final TimeUnit unit) |
| | | { |
| | | Validator.ensureNotNull(factories, scheduler, unit); |
| | | |
| | | this.monitoredFactories = new ArrayList<MonitoredConnectionFactory>( |
| | | factories.size()); |
| | | int i = 0; |
| | | for (final ConnectionFactory f : factories) |
| | | { |
| | | this.monitoredFactories.add(new MonitoredConnectionFactory(f, i++)); |
| | | } |
| | | this.scheduler = scheduler; |
| | | this.monitoringInterval = interval; |
| | | this.monitoringIntervalTimeUnit = unit; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public final ConnectionFactory getConnectionFactory() |
| | | throws ErrorResultException |
| | | { |
| | | final int index = getInitialConnectionFactoryIndex(); |
| | | return getMonitoredConnectionFactory(index); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append(getAlgorithmName()); |
| | | builder.append('('); |
| | | boolean isFirst = true; |
| | | for (final ConnectionFactory factory : monitoredFactories) |
| | | { |
| | | if (!isFirst) |
| | | { |
| | | builder.append(','); |
| | | } |
| | | else |
| | | { |
| | | isFirst = false; |
| | | } |
| | | builder.append(factory); |
| | | } |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the name of this load balancing algorithm. |
| | | * |
| | | * @return The name of this load balancing algorithm. |
| | | */ |
| | | abstract String getAlgorithmName(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the index of the first connection factory which should be used in |
| | | * order to satisfy the next connection request. |
| | | * |
| | | * @return The index of the first connection factory which should be used in |
| | | * order to satisfy the next connection request. |
| | | */ |
| | | abstract int getInitialConnectionFactoryIndex(); |
| | | |
| | | |
| | | |
| | | // Return the first factory after index which is operational. |
| | | private MonitoredConnectionFactory getMonitoredConnectionFactory( |
| | | final int initialIndex) throws ErrorResultException |
| | | { |
| | | int index = initialIndex; |
| | | final int maxIndex = monitoredFactories.size(); |
| | | do |
| | | { |
| | | final MonitoredConnectionFactory factory = monitoredFactories.get(index); |
| | | if (factory.isOperational.get()) |
| | | { |
| | | return factory; |
| | | } |
| | | index = (index + 1) % maxIndex; |
| | | } |
| | | while (index != initialIndex); |
| | | |
| | | // All factories are offline so give up. We could have a |
| | | // configurable policy here such as waiting indefinitely, or for a |
| | | // configurable timeout period. |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setDiagnosticMessage( |
| | | "No operational connection factories available")); |
| | | } |
| | | } |
| | |
| | | return connection.searchSingleEntry(request, resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("AuthenticatedConnection("); |
| | | builder.append(connection); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | return future.futureBindResult; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("AuthenticatedConnectionFactory("); |
| | | builder.append(String.valueOf(parentFactory)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.opends.sdk.responses.*; |
| | | import org.opends.sdk.schema.Schema; |
| | | |
| | | import com.sun.opends.sdk.util.AbstractFutureResult; |
| | | import com.sun.opends.sdk.util.AsynchronousFutureResult; |
| | | import com.sun.opends.sdk.util.CompletedFutureResult; |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | |
| | |
| | | { |
| | | // Future used for waiting for pooled connections to become available. |
| | | private static final class FuturePooledConnection extends |
| | | AbstractFutureResult<AsynchronousConnection> |
| | | AsynchronousFutureResult<AsynchronousConnection> |
| | | { |
| | | private FuturePooledConnection( |
| | | final ResultHandler<? super AsynchronousConnection> handler) |
| | | { |
| | | super(handler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getRequestID() |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | public void handleUnsolicitedNotification( |
| | | final ExtendedResult notification) |
| | | public void handleUnsolicitedNotification(final ExtendedResult notification) |
| | | { |
| | | // Ignore |
| | | } |
| | |
| | | } |
| | | return connection.searchSingleEntry(request, resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("PooledConnection("); |
| | | builder.append(connection); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | handler.handleResult(pooledConnection); |
| | | } |
| | | return new CompletedFutureResult<AsynchronousConnection>(pooledConnection); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("ConnectionPool("); |
| | | builder.append(String.valueOf(connectionFactory)); |
| | | builder.append(','); |
| | | builder.append(poolSize); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import org.opends.sdk.requests.BindRequest; |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new connection factory providing fault tolerance across multiple |
| | | * underlying connection factories. |
| | | * <p> |
| | | * The returned fail-over connection factory forwards connection requests to |
| | | * one of the provided connection factories. If the request fails for some |
| | | * reason (for example, due to network failure), then the fail-over connection |
| | | * factory switches to another connection faction, repeating the process until |
| | | * the connection request succeeds, or until all the connection factories are |
| | | * determined to be unavailable, in which case the connection request will |
| | | * fail. |
| | | * <p> |
| | | * The implementation periodically attempts to connect to failed connection |
| | | * factories in order to determine if they have become available again. |
| | | * |
| | | * @param factories |
| | | * The connection factories which will be used for fail-over. |
| | | * @return The new fail-over connection factory. |
| | | * @throws NullPointerException |
| | | * If {@code factories} was {@code null}. |
| | | */ |
| | | public static ConnectionFactory newFailoverConnectionFactory( |
| | | final Collection<ConnectionFactory> factories) |
| | | throws NullPointerException |
| | | { |
| | | final FailoverLoadBalancingAlgorithm algorithm = new FailoverLoadBalancingAlgorithm( |
| | | factories); |
| | | return new LoadBalancingConnectionFactory(algorithm); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new connection factory providing fault tolerance across multiple |
| | | * underlying connection factories. |
| | | * <p> |
| | | * The returned fail-over connection factory forwards connection requests to |
| | | * one of the provided connection factories. If the request fails for some |
| | | * reason (for example, due to network failure), then the fail-over connection |
| | | * factory switches to another connection faction, repeating the process until |
| | | * the connection request succeeds, or until all the connection factories are |
| | | * determined to be unavailable, in which case the connection request will |
| | | * fail. |
| | | * <p> |
| | | * The implementation periodically attempts to connect to failed connection |
| | | * factories in order to determine if they have become available again. |
| | | * |
| | | * @param factories |
| | | * The connection factories which will be used for fail-over. |
| | | * @return The new fail-over connection factory. |
| | | * @throws NullPointerException |
| | | * If {@code factories} was {@code null}. |
| | | */ |
| | | public static ConnectionFactory newFailoverConnectionFactory( |
| | | final ConnectionFactory... factories) throws NullPointerException |
| | | { |
| | | final FailoverLoadBalancingAlgorithm algorithm = new FailoverLoadBalancingAlgorithm( |
| | | factories); |
| | | return new LoadBalancingConnectionFactory(algorithm); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new connection factory which will create connections using the |
| | | * provided connection factory and periodically probe any created connections |
| | | * in order to detect that they are still alive. |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new connection factory which will create internal connections |
| | | * using the provided server connection factory. The server connection will be |
| | | * provided with request context whose value is unique integer associated with |
| | | * the request. |
| | | * Creates a new connection factory which binds internal client connections to |
| | | * {@link ServerConnection}s created using the provided |
| | | * {@link ServerConnectionFactory}. |
| | | * <p> |
| | | * When processing requests, {@code ServerConnection} implementations are |
| | | * passed an integer as the first parameter. This integer represents a pseudo |
| | | * {@code requestID} which is incremented for each successive internal request |
| | | * on a per client connection basis. The request ID may be useful for logging |
| | | * purposes. |
| | | * <p> |
| | | * An internal connection factory does not require {@code ServerConnection} |
| | | * implementations to return a result when processing requests. However, it is |
| | | * recommended that implementations do always return results even for |
| | | * abandoned requests. This is because application client threads may block |
| | | * indefinitely waiting for results. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new load balancer which will obtain connections using the |
| | | * provided load balancing algorithm. |
| | | * |
| | | * @param algorithm |
| | | * The load balancing algorithm which will be used to obtain the next |
| | | * @return The new load balancer. |
| | | * @throws NullPointerException |
| | | * If {@code algorithm} was {@code null}. |
| | | */ |
| | | public static ConnectionFactory newLoadBalancer( |
| | | final LoadBalancingAlgorithm algorithm) throws NullPointerException |
| | | { |
| | | return new LoadBalancer(algorithm); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new connection factory which forwards connection requests to the |
| | | * provided factory, but whose {@code toString} method will always return |
| | | * {@code name}. |
| | | * <p> |
| | | * This method may be useful for debugging purposes in order to more easily |
| | | * identity connection factories. |
| | | * |
| | | * @param factory |
| | | * The connection factory to be named. |
| | | * @param name |
| | | * The name of the connection factory. |
| | | * @return The named connection factory. |
| | | * @throws NullPointerException |
| | | * If {@code factory} or {@code name} was {@code null}. |
| | | */ |
| | | public static ConnectionFactory newNamedConnectionFactory( |
| | | final ConnectionFactory factory, final String name) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(factory, name); |
| | | |
| | | return new ConnectionFactory() |
| | | { |
| | | |
| | | @Override |
| | | public FutureResult<AsynchronousConnection> getAsynchronousConnection( |
| | | final ResultHandler<? super AsynchronousConnection> handler) |
| | | { |
| | | return factory.getAsynchronousConnection(handler); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Connection getConnection() throws ErrorResultException, |
| | | InterruptedException |
| | | { |
| | | return factory.getConnection(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return name; |
| | | } |
| | | |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | // Prevent instantiation. |
| | | private Connections() |
| | | { |
| | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Iterator; |
| | | |
| | | import org.opends.sdk.requests.ModifyRequest; |
| | | import org.opends.sdk.requests.Requests; |
| | | |
| | | import com.sun.opends.sdk.util.Function; |
| | | import com.sun.opends.sdk.util.Iterables; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class contains methods for creating and manipulating entries. |
| | | * |
| | | * @see Entry |
| | | */ |
| | | public final class Entries |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean addAttribute(final Attribute attribute) |
| | | throws UnsupportedOperationException, NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean addAttribute(final Attribute attribute, |
| | | final Collection<ByteString> duplicateValues) |
| | | throws UnsupportedOperationException, NullPointerException |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Entry addAttribute(final String attributeDescription, |
| | | final Object... values) throws LocalizedIllegalArgumentException, |
| | | UnsupportedOperationException, NullPointerException |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Entry clearAttributes() throws UnsupportedOperationException |
| | | { |
| | | throw new UnsupportedOperationException(); |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean containsAttribute(final Attribute attribute, |
| | | final Collection<ByteString> missingValues) throws NullPointerException |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean containsAttribute(final String attributeDescription, |
| | | final Object... values) throws LocalizedIllegalArgumentException, |
| | | NullPointerException |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Iterable<Attribute> getAllAttributes() |
| | | { |
| | | return Iterables.unmodifiable(Iterables.transform(entry |
| | | .getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION)); |
| | | return Iterables.unmodifiable(Iterables.transform( |
| | | entry.getAllAttributes(), UNMODIFIABLE_ATTRIBUTE_FUNCTION)); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Iterable<Attribute> getAllAttributes( |
| | | final AttributeDescription attributeDescription) |
| | | { |
| | | return Iterables.unmodifiable(Iterables.transform(entry |
| | | .getAllAttributes(attributeDescription), |
| | | return Iterables.unmodifiable(Iterables.transform( |
| | | entry.getAllAttributes(attributeDescription), |
| | | UNMODIFIABLE_ATTRIBUTE_FUNCTION)); |
| | | } |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Iterable<Attribute> getAllAttributes( |
| | | final String attributeDescription) |
| | | throws LocalizedIllegalArgumentException, NullPointerException |
| | | { |
| | | return Iterables.unmodifiable(Iterables.transform(entry |
| | | .getAllAttributes(attributeDescription), |
| | | return Iterables.unmodifiable(Iterables.transform( |
| | | entry.getAllAttributes(attributeDescription), |
| | | UNMODIFIABLE_ATTRIBUTE_FUNCTION)); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Attribute getAttribute( |
| | | final AttributeDescription attributeDescription) |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Attribute getAttribute(final String attributeDescription) |
| | | throws LocalizedIllegalArgumentException, NullPointerException |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public int getAttributeCount() |
| | | { |
| | | return entry.getAttributeCount(); |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DN getName() |
| | | { |
| | | return entry.getName(); |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean removeAttribute(final Attribute attribute, |
| | | final Collection<ByteString> missingValues) |
| | | throws UnsupportedOperationException, NullPointerException |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean removeAttribute( |
| | | final AttributeDescription attributeDescription) |
| | | throws UnsupportedOperationException, NullPointerException |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Entry removeAttribute(final String attributeDescription, |
| | | final Object... values) throws LocalizedIllegalArgumentException, |
| | | UnsupportedOperationException, NullPointerException |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean replaceAttribute(final Attribute attribute) |
| | | throws UnsupportedOperationException, NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Entry replaceAttribute(final String attributeDescription, |
| | | final Object... values) throws LocalizedIllegalArgumentException, |
| | | UnsupportedOperationException, NullPointerException |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Entry setName(final DN dn) throws UnsupportedOperationException, |
| | | NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Entry setName(final String dn) |
| | | throws LocalizedIllegalArgumentException, |
| | | UnsupportedOperationException, NullPointerException |
| | |
| | | |
| | | |
| | | |
| | | private static final Function<Attribute, Attribute, Void> |
| | | UNMODIFIABLE_ATTRIBUTE_FUNCTION = new Function<Attribute, Attribute, Void>() |
| | | private static final Function<Attribute, Attribute, Void> UNMODIFIABLE_ATTRIBUTE_FUNCTION = |
| | | new Function<Attribute, Attribute, Void>() |
| | | { |
| | | |
| | | @Override |
| | | public Attribute apply(final Attribute value, final Void p) |
| | | { |
| | | return Attributes.unmodifiableAttribute(value); |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new modify request containing a list of modifications which can |
| | | * be used to transform {@code fromEntry} into entry {@code toEntry}. |
| | | * <p> |
| | | * The modify request is reversible: it will contain only modifications of |
| | | * type {@link ModificationType#ADD ADD} and {@link ModificationType#DELETE |
| | | * DELETE}. |
| | | * <p> |
| | | * Finally, the modify request will use the distinguished name taken from |
| | | * {@code fromEntry}. Moreover, this method will not check to see if both |
| | | * {@code fromEntry} and {@code toEntry} have the same distinguished name. |
| | | * <p> |
| | | * This method is equivalent to: |
| | | * |
| | | * <pre> |
| | | * ModifyRequest request = Requests.newModifyRequest(fromEntry, toEntry); |
| | | * </pre> |
| | | * |
| | | * @param fromEntry |
| | | * The source entry. |
| | | * @param toEntry |
| | | * The destination entry. |
| | | * @return A modify request containing a list of modifications which can be |
| | | * used to transform {@code fromEntry} into entry {@code toEntry}. |
| | | * @throws NullPointerException |
| | | * If {@code fromEntry} or {@code toEntry} were {@code null}. |
| | | * @see Requests#newModifyRequest(Entry, Entry) |
| | | */ |
| | | public static final ModifyRequest diffEntries(final Entry fromEntry, |
| | | final Entry toEntry) throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(fromEntry, toEntry); |
| | | |
| | | final ModifyRequest request = Requests |
| | | .newModifyRequest(fromEntry.getName()); |
| | | |
| | | TreeMapEntry tfrom; |
| | | if (fromEntry instanceof TreeMapEntry) |
| | | { |
| | | tfrom = (TreeMapEntry) fromEntry; |
| | | } |
| | | else |
| | | { |
| | | tfrom = new TreeMapEntry(fromEntry); |
| | | } |
| | | |
| | | TreeMapEntry tto; |
| | | if (toEntry instanceof TreeMapEntry) |
| | | { |
| | | tto = (TreeMapEntry) toEntry; |
| | | } |
| | | else |
| | | { |
| | | tto = new TreeMapEntry(toEntry); |
| | | } |
| | | |
| | | final Iterator<Attribute> ifrom = tfrom.getAllAttributes().iterator(); |
| | | final Iterator<Attribute> ito = tto.getAllAttributes().iterator(); |
| | | |
| | | Attribute afrom = ifrom.hasNext() ? ifrom.next() : null; |
| | | Attribute ato = ito.hasNext() ? ito.next() : null; |
| | | |
| | | while (afrom != null && ato != null) |
| | | { |
| | | final AttributeDescription adfrom = afrom.getAttributeDescription(); |
| | | final AttributeDescription adto = ato.getAttributeDescription(); |
| | | |
| | | final int cmp = adfrom.compareTo(adto); |
| | | if (cmp == 0) |
| | | { |
| | | // Attribute is in both entries. Compute the set of values to be added |
| | | // and removed. We won't replace the attribute because this is not |
| | | // reversible. |
| | | final Attribute addedValues = new LinkedAttribute(ato); |
| | | addedValues.removeAll(afrom); |
| | | if (!addedValues.isEmpty()) |
| | | { |
| | | request.addModification(new Modification(ModificationType.ADD, |
| | | addedValues)); |
| | | } |
| | | |
| | | final Attribute deletedValues = new LinkedAttribute(afrom); |
| | | deletedValues.removeAll(ato); |
| | | if (!deletedValues.isEmpty()) |
| | | { |
| | | request.addModification(new Modification(ModificationType.DELETE, |
| | | deletedValues)); |
| | | } |
| | | |
| | | afrom = ifrom.hasNext() ? ifrom.next() : null; |
| | | ato = ito.hasNext() ? ito.next() : null; |
| | | } |
| | | else if (cmp < 0) |
| | | { |
| | | // afrom in source, but not destination. |
| | | request |
| | | .addModification(new Modification(ModificationType.DELETE, afrom)); |
| | | afrom = ifrom.hasNext() ? ifrom.next() : null; |
| | | } |
| | | else |
| | | { |
| | | // ato in destination, but not in source. |
| | | request.addModification(new Modification(ModificationType.ADD, ato)); |
| | | ato = ito.hasNext() ? ito.next() : null; |
| | | } |
| | | } |
| | | |
| | | // Additional attributes in source entry: these must be deleted. |
| | | if (afrom != null) |
| | | { |
| | | request.addModification(new Modification(ModificationType.DELETE, afrom)); |
| | | } |
| | | |
| | | while (ifrom.hasNext()) |
| | | { |
| | | final Attribute a = ifrom.next(); |
| | | request.addModification(new Modification(ModificationType.DELETE, a)); |
| | | } |
| | | |
| | | // Additional attributes in destination entry: these must be added. |
| | | if (ato != null) |
| | | { |
| | | request.addModification(new Modification(ModificationType.ADD, ato)); |
| | | } |
| | | |
| | | while (ito.hasNext()) |
| | | { |
| | | final Attribute a = ito.next(); |
| | | request.addModification(new Modification(ModificationType.ADD, a)); |
| | | } |
| | | |
| | | return request; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns a read-only view of {@code entry} and its attributes. Query |
| | | * operations on the returned entry and its attributes"read-through" to the |
| | | * operations on the returned entry and its attributes "read-through" to the |
| | | * underlying entry or attribute, and attempts to modify the returned entry |
| | | * and its attributes either directly or indirectly via an iterator result in |
| | | * an {@code UnsupportedOperationException}. |
| | |
| | | * {@link #replaceAttribute} and the conditions, if any, where a reference to |
| | | * the passed in attribute is maintained. |
| | | * </ul> |
| | | * |
| | | * @see Entries |
| | | */ |
| | | public interface Entry |
| | | { |
| | |
| | | |
| | | import java.util.concurrent.ExecutionException; |
| | | |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.Result; |
| | | |
| | | |
| | |
| | | @SuppressWarnings("serial") |
| | | public class ErrorResultException extends ExecutionException |
| | | { |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code and |
| | | * diagnostic message. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @param diagnosticMessage |
| | | * The diagnostic message, which may be empty or {@code null} |
| | | * indicating that none was provided. |
| | | * @return The new error result exception. |
| | | * @throws IllegalArgumentException |
| | | * If the provided result code does not represent a failure. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult(ResultCode resultCode, |
| | | String diagnosticMessage) throws IllegalArgumentException, |
| | | NullPointerException |
| | | { |
| | | return newErrorResult(resultCode, diagnosticMessage, null); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code, |
| | | * diagnostic message, and cause. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @param diagnosticMessage |
| | | * The diagnostic message, which may be empty or {@code null} |
| | | * indicating that none was provided. |
| | | * @param cause |
| | | * The throwable cause, which may be null indicating that none was |
| | | * provided. |
| | | * @return The new error result exception. |
| | | * @throws IllegalArgumentException |
| | | * If the provided result code does not represent a failure. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult(ResultCode resultCode, |
| | | String diagnosticMessage, Throwable cause) |
| | | throws IllegalArgumentException, NullPointerException |
| | | { |
| | | Result result = Responses.newResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | return wrap(result); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Wraps the provided result in an appropriate error result exception. The |
| | | * type of error result exception used depends on the underlying result code. |
| | |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.logging.Level; |
| | | |
| | | import org.opends.sdk.responses.Responses; |
| | | |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | |
| | | |
| | |
| | | * A fail-over load balancing algorithm provides fault tolerance across multiple |
| | | * underlying connection factories. |
| | | * <p> |
| | | * This algorithm is typically used for load-balancing <i>between</i> data |
| | | * centers, where there is preference to always always forward connection |
| | | * requests to the <i>closest available</i> data center. This algorithm |
| | | * contrasts with the {@link RoundRobinLoadBalancingAlgorithm} which is used for |
| | | * load-balancing <i>within</i> a data center. |
| | | * <p> |
| | | * This algorithm selects connection factories based on the order in which they |
| | | * were provided during construction. More specifically, an attempt to obtain a |
| | | * connection factory will always return the <i>first operational</i> connection |
| | | * factory in the list. Applications should, therefore, organize the connection |
| | | * factories such that the <i>preferred</i> (usually the closest) connection |
| | | * factories appear before those which are less preferred. |
| | | * <p> |
| | | * If a problem occurs that temporarily prevents connections from being obtained |
| | | * for one of the connection factories, then this algorithm "fails over" to |
| | | * another operational connection factory in the list. If none of the connection |
| | | * factories are operational then a {@code ConnectionException} is returned to |
| | | * the client. |
| | | * for one of the connection factories, then this algorithm automatically |
| | | * "fails over" to the next operational connection factory in the list. If none |
| | | * of the connection factories are operational then a |
| | | * {@code ConnectionException} is returned to the client. |
| | | * <p> |
| | | * The implementation periodically attempts to connect to failed connection |
| | | * factories in order to determine if they have become available again. |
| | | * |
| | | * @see RoundRobinLoadBalancingAlgorithm |
| | | * @see Connections#newLoadBalancer(LoadBalancingAlgorithm) |
| | | */ |
| | | class FailoverLoadBalancingAlgorithm implements LoadBalancingAlgorithm |
| | | public final class FailoverLoadBalancingAlgorithm extends |
| | | AbstractLoadBalancingAlgorithm |
| | | { |
| | | private static final class MonitoredConnectionFactory extends |
| | | AbstractConnectionFactory implements |
| | | ResultHandler<AsynchronousConnection> |
| | | { |
| | | private final ConnectionFactory factory; |
| | | |
| | | private volatile boolean isOperational; |
| | | |
| | | private volatile FutureResult<?> pendingConnectFuture; |
| | | |
| | | |
| | | |
| | | private MonitoredConnectionFactory(final ConnectionFactory factory) |
| | | { |
| | | this.factory = factory; |
| | | this.isOperational = true; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public FutureResult<AsynchronousConnection> getAsynchronousConnection( |
| | | final ResultHandler<? super AsynchronousConnection> resultHandler) |
| | | { |
| | | final ResultHandler<AsynchronousConnection> handler = |
| | | new ResultHandler<AsynchronousConnection>() |
| | | { |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | isOperational = false; |
| | | if (resultHandler != null) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) |
| | | { |
| | | StaticUtils.DEBUG_LOG |
| | | .warning(String.format("Connection factory " + factory |
| | | + " is no longer operational: " + error.getMessage())); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleResult(final AsynchronousConnection result) |
| | | { |
| | | isOperational = true; |
| | | if (resultHandler != null) |
| | | { |
| | | resultHandler.handleResult(result); |
| | | } |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.WARNING)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.warning(String.format("Connection factory " |
| | | + factory + " is now operational")); |
| | | } |
| | | } |
| | | }; |
| | | return factory.getAsynchronousConnection(handler); |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | isOperational = false; |
| | | } |
| | | |
| | | |
| | | |
| | | public void handleResult(final AsynchronousConnection result) |
| | | { |
| | | isOperational = true; |
| | | // TODO: Notify the server is back up |
| | | result.close(); |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean isOperational() |
| | | { |
| | | return isOperational; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class MonitorThread extends Thread |
| | | { |
| | | private MonitorThread() |
| | | { |
| | | super("Connection Factory Health Monitor"); |
| | | this.setDaemon(true); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void run() |
| | | { |
| | | while (true) |
| | | { |
| | | for (final MonitoredConnectionFactory f : monitoredFactories) |
| | | { |
| | | if (!f.isOperational |
| | | && (f.pendingConnectFuture == null || f.pendingConnectFuture |
| | | .isDone())) |
| | | { |
| | | if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINEST)) |
| | | { |
| | | StaticUtils.DEBUG_LOG.finest(String |
| | | .format("Attempting connect on factory " + f)); |
| | | } |
| | | f.pendingConnectFuture = f.factory.getAsynchronousConnection(f); |
| | | } |
| | | } |
| | | |
| | | try |
| | | { |
| | | sleep(10000); |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | // Termination requested - exit. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final List<MonitoredConnectionFactory> monitoredFactories; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new fail-over load balancing algorithm which will fail-over |
| | | * across the provided collection of connection factories. |
| | | * Creates a new fail-over load balancing algorithm which will use a default |
| | | * scheduler for monitoring offline connection factories every 10 seconds. |
| | | * |
| | | * @param factories |
| | | * The connection factories which will be used for fail-over. |
| | | * The ordered collection of connection factories. |
| | | */ |
| | | public FailoverLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories) |
| | | { |
| | | Validator.ensureNotNull(factories); |
| | | |
| | | monitoredFactories = new ArrayList<MonitoredConnectionFactory>(factories |
| | | .size()); |
| | | for (final ConnectionFactory f : factories) |
| | | { |
| | | monitoredFactories.add(new MonitoredConnectionFactory(f)); |
| | | } |
| | | |
| | | new MonitorThread().start(); |
| | | super(factories); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new fail-over load balancing algorithm which will fail-over |
| | | * across the provided list of connection factories. |
| | | * Creates a new fail-over load balancing algorithm which will use the |
| | | * provided scheduler for monitoring offline connection factories every 10 |
| | | * seconds. |
| | | * |
| | | * @param factories |
| | | * The connection factories which will be used for fail-over. |
| | | * The ordered collection of connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring offline |
| | | * connection factories to see if they are usable again. |
| | | */ |
| | | public FailoverLoadBalancingAlgorithm(final ConnectionFactory... factories) |
| | | public FailoverLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler) |
| | | { |
| | | Validator.ensureNotNull((Object[]) factories); |
| | | |
| | | monitoredFactories = new ArrayList<MonitoredConnectionFactory>( |
| | | factories.length); |
| | | for (final ConnectionFactory f : factories) |
| | | { |
| | | monitoredFactories.add(new MonitoredConnectionFactory(f)); |
| | | } |
| | | |
| | | new MonitorThread().start(); |
| | | super(factories, scheduler); |
| | | } |
| | | |
| | | |
| | | |
| | | public ConnectionFactory getNextConnectionFactory() |
| | | throws ErrorResultException |
| | | /** |
| | | * Creates a new fail-over load balancing algorithm which will use the |
| | | * provided scheduler for monitoring offline connection factories. |
| | | * |
| | | * @param factories |
| | | * The ordered collection of connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring offline |
| | | * connection factories to see if they are usable again. |
| | | * @param interval |
| | | * The interval between attempts to poll offline connection |
| | | * factories. |
| | | * @param unit |
| | | * The time unit for the interval between attempts to poll offline |
| | | * connection factories. |
| | | */ |
| | | public FailoverLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler, final long interval, |
| | | final TimeUnit unit) |
| | | { |
| | | for (final MonitoredConnectionFactory f : monitoredFactories) |
| | | { |
| | | if (f.isOperational()) |
| | | { |
| | | return f; |
| | | } |
| | | } |
| | | |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setDiagnosticMessage( |
| | | "No operational connection factories available")); |
| | | super(factories, scheduler, interval, unit); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | String getAlgorithmName() |
| | | { |
| | | return "Failover"; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | int getInitialConnectionFactoryIndex() |
| | | { |
| | | // Always start with the first connection factory. |
| | | return 0; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | public void handleUnsolicitedNotification( |
| | | final ExtendedResult notification) |
| | | public void handleUnsolicitedNotification(final ExtendedResult notification) |
| | | { |
| | | // Do nothing |
| | | } |
| | |
| | | { |
| | | return connection.searchSingleEntry(request, resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("HeartBeatConnection("); |
| | | builder.append(connection); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class FutureResultImpl extends |
| | | FutureResultTransformer<AsynchronousConnection, AsynchronousConnection> |
| | | implements FutureResult<AsynchronousConnection>, |
| | | ResultHandler<AsynchronousConnection> |
| | | implements ResultHandler<AsynchronousConnection> |
| | | { |
| | | |
| | | private FutureResultImpl( |
| | |
| | | future.setFutureResult(parentFactory.getAsynchronousConnection(future)); |
| | | return future; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("HeartBeatConnectionFactory("); |
| | | builder.append(String.valueOf(parentFactory)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * A special {@code ConnectionFactory} that can be used to perform internal |
| | | * operations against a {@code ServerConnectionFactory} implementation. |
| | | * A special {@code ConnectionFactory} which waits for internal connection |
| | | * requests and binds them to a {@link ServerConnection} created using the |
| | | * provided {@link ServerConnectionFactory}. |
| | | * <p> |
| | | * When processing requests, {@code ServerConnection} implementations are passed |
| | | * an integer as the first parameter. This integer represents a pseudo |
| | | * {@code requestID} which is incremented for each successive internal request |
| | | * on a per connection basis. The request ID may be useful for logging purposes. |
| | | * <p> |
| | | * An {@code InternalConnectionFactory} does not require |
| | | * {@code ServerConnection} implementations to return a result when processing |
| | | * requests. However, it is recommended that implementations do always return |
| | | * results even for abandoned requests. This is because application client |
| | | * threads may block indefinitely waiting for results. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | |
| | | final ServerConnection<Integer> serverConnection; |
| | | try |
| | | { |
| | | serverConnection = factory.accept(clientContext); |
| | | serverConnection = factory.handleAccept(clientContext); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | |
| | | } |
| | | return new CompletedFutureResult<AsynchronousConnection>(connection); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("InternalConnectionFactory("); |
| | | builder.append(String.valueOf(clientContext)); |
| | | builder.append(','); |
| | | builder.append(String.valueOf(factory)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * An LDAP client which has connected to a {@link ServerConnectionFactory}. The |
| | | * An LDAP client which has connected to a {@link ServerConnectionFactory}. An |
| | | * LDAP client context can be used to query information about the client's |
| | | * connection such as their network address, as well as managing the state of |
| | | * the connection. |
| | | */ |
| | | public interface LDAPClientContext |
| | | { |
| | | /** |
| | | * Registers the provided connection event listener so that it will be |
| | | * notified when the underlying connection is closed by the client, receives |
| | | * an unsolicited notification, or experiences a fatal error. |
| | | * <p> |
| | | * This method provides a event notification mechanism which can be used by |
| | | * asynchronous request handler implementations to detect connection |
| | | * termination. |
| | | * |
| | | * @param listener |
| | | * The listener which wants to be notified when events occur on the |
| | | * underlying connection. |
| | | * @throws NullPointerException |
| | | * If the {@code listener} was {@code null}. |
| | | * @see #isClosed |
| | | */ |
| | | void addConnectionEventListener(ConnectionEventListener listener) |
| | | throws NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Disconnects the client without sending a disconnect notification. |
| | | * <p> |
| | | * <b>Server connections:</b> invoking this method causes |
| | | * {@link ServerConnection#handleConnectionDisconnected |
| | | * handleConnectionDisconnected} to be called before this method returns. |
| | | */ |
| | | void disconnect(); |
| | | |
| | |
| | | /** |
| | | * Disconnects the client and sends a disconnect notification, if possible, |
| | | * containing the provided result code and diagnostic message. |
| | | * <p> |
| | | * <b>Server connections:</b> invoking this method causes |
| | | * {@link ServerConnection#handleConnectionDisconnected |
| | | * handleConnectionDisconnected} to be called before this method returns. |
| | | * |
| | | * @param resultCode |
| | | * The result code which should be included with the disconnect |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns {@code true} if the underlying connection is closed by the client, |
| | | * receives an unsolicited notification, or experiences a fatal error. |
| | | * Returns {@code true} if the underlying connection has been closed as a |
| | | * result of a client disconnect, a fatal connection error, or a server-side |
| | | * {@link #disconnect}. |
| | | * <p> |
| | | * This method provides a polling mechanism which can be used by synchronous |
| | | * request handler implementations to detect connection termination. |
| | | * <p> |
| | | * <b>Server connections:</b> this method will always return {@code true} when |
| | | * called from within {@link ServerConnection#handleConnectionClosed |
| | | * handleConnectionClosed}, |
| | | * {@link ServerConnection#handleConnectionDisconnected |
| | | * handleConnectionDisconnected}, or |
| | | * {@link ServerConnection#handleConnectionError handleConnectionError}. |
| | | * |
| | | * @return {@code true} if the underlying connection is closed by the client, |
| | | * receives an unsolicited notification, or experiences a fatal error, |
| | | * otherwise {@code false}. |
| | | * @see #addConnectionEventListener |
| | | * @return {@code true} if the underlying connection has been closed. |
| | | */ |
| | | boolean isClosed(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Removes the provided connection event listener from this client context so |
| | | * that it will no longer be notified when the underlying connection is closed |
| | | * by the application, receives an unsolicited notification, or experiences a |
| | | * fatal error. |
| | | * |
| | | * @param listener |
| | | * The listener which no longer wants to be notified when events |
| | | * occur on the underlying connection. |
| | | * @throws NullPointerException |
| | | * If the {@code listener} was {@code null}. |
| | | */ |
| | | void removeConnectionEventListener(ConnectionEventListener listener) |
| | | throws NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sends an unsolicited notification to the client. |
| | | * |
| | | * @param notification |
| | |
| | | |
| | | |
| | | |
| | | import java.net.InetAddress; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.SocketAddress; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the {@code InetAddress} that this LDAP listener is listening on. |
| | | * |
| | | * @return The {@code InetAddress} that this LDAP listener is listening on, or |
| | | * {@code null} if it is unknown. |
| | | */ |
| | | public InetAddress getAddress() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getAddress(); |
| | | } |
| | | else |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<AsynchronousConnection> getAsynchronousConnection( |
| | | final ResultHandler<? super AsynchronousConnection> handler) |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Connection getConnection() throws ErrorResultException, |
| | | InterruptedException |
| | | { |
| | | return impl.getConnection(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the host name that this LDAP listener is listening on. |
| | | * |
| | | * @return The host name that this LDAP listener is listening on, or |
| | | * {@code null} if it is unknown. |
| | | */ |
| | | public String getHostname() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getHostName(); |
| | | } |
| | | else |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the port that this LDAP listener is listening on. |
| | | * |
| | | * @return The port that this LDAP listener is listening on, or {@code -1} if |
| | | * it is unknown. |
| | | */ |
| | | public int getPort() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getPort(); |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the address that this LDAP listener is listening on. |
| | | * |
| | | * @return The address that this LDAP listener is listening on. |
| | | */ |
| | | public SocketAddress getSocketAddress() |
| | | { |
| | | return impl.getSocketAddress(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return impl.toString(); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | |
| | | |
| | | import java.io.Closeable; |
| | | import java.io.IOException; |
| | | import java.net.InetAddress; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.SocketAddress; |
| | | |
| | |
| | | |
| | | /** |
| | | * An LDAP server connection listener which waits for LDAP connection requests |
| | | * to come in over the network and binds them to a {@link ServerConnection}. |
| | | * to come in over the network and binds them to a {@link ServerConnection} |
| | | * created using the provided {@link ServerConnectionFactory}. |
| | | * <p> |
| | | * When processing requests, {@code ServerConnection} implementations are passed |
| | | * an integer as the first parameter. This integer represents the |
| | | * {@code requestID} associated with the client request and corresponds to the |
| | | * {@code requestID} passed as a parameter to abandon and cancel extended |
| | | * requests. The request ID may also be useful for logging purposes. |
| | | * <p> |
| | | * An {@code LDAPListener} does not require {@code ServerConnection} |
| | | * implementations to return a result when processing requests. More |
| | | * specifically, an {@code LDAPListener} does not maintain any internal state |
| | | * information associated with each request which must be released. This is |
| | | * useful when implementing LDAP abandon operations which may prevent results |
| | | * being sent for abandoned operations. |
| | | * <p> |
| | | * The following code illustrates how to create a simple LDAP server: |
| | | * |
| | |
| | | * |
| | | * |
| | | * |
| | | * public void add(Integer context, AddRequest request, |
| | | * public void add(Integer requestID, AddRequest request, |
| | | * ResultHandler<Result> handler, |
| | | * IntermediateResponseHandler intermediateResponseHandler) |
| | | * throws UnsupportedOperationException |
| | |
| | | * |
| | | * |
| | | * |
| | | * class MyServer implements ServerConnectionFactory<LDAPClientContext, Integer> |
| | | * class MyServer implements |
| | | * ServerConnectionFactory<LDAPClientContext, RequestContext> |
| | | * { |
| | | * public ServerConnection<Integer> accept(LDAPClientContext context) |
| | | * public ServerConnection<RequestContext> accept(LDAPClientContext context) |
| | | * { |
| | | * System.out.println("Connection from: " + context.getPeerAddress()); |
| | | * return new MyClientConnection(context); |
| | |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections at the provided address. |
| | | * |
| | | * @param port |
| | | * The port to listen on. |
| | | * @param host |
| | | * The address to listen on. |
| | | * @param factory |
| | | * The server connection factory which will be used to create server |
| | | * connections. |
| | | * @throws IOException |
| | | * If an error occurred while trying to listen on the provided |
| | | * address. |
| | | * @throws NullPointerException |
| | | * If {@code host} or {code factory} was {@code null}. |
| | | */ |
| | | public LDAPListener(final int port, final String host, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory) |
| | | throws IOException, NullPointerException |
| | | { |
| | | this(port, host, factory, new LDAPListenerOptions()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections at the provided address. |
| | | * |
| | | * @param port |
| | | * The port to listen on. |
| | | * @param host |
| | | * 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. |
| | | * @throws NullPointerException |
| | | * If {@code host}, {code factory}, or {@code options} was {@code |
| | | * null}. |
| | | */ |
| | | public LDAPListener(final int port, final String host, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory, |
| | | final LDAPListenerOptions options) throws IOException, |
| | | NullPointerException |
| | | { |
| | | Validator.ensureNotNull(host, factory, options); |
| | | final SocketAddress address = new InetSocketAddress(host, port); |
| | | this.impl = new LDAPListenerImpl(address, factory, options); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections at the provided address. |
| | | * |
| | | * @param address |
| | | * The address to listen on. |
| | | * @param factory |
| | |
| | | |
| | | |
| | | /** |
| | | * Closes this LDAP connection listener. |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections at the provided address. |
| | | * |
| | | * @param host |
| | | * The address to listen on. |
| | | * @param port |
| | | * The port to listen on. |
| | | * @param factory |
| | | * The server connection factory which will be used to create server |
| | | * connections. |
| | | * @throws IOException |
| | | * If an IO error occurred while closing this listener. |
| | | * If an error occurred while trying to listen on the provided |
| | | * address. |
| | | * @throws NullPointerException |
| | | * If {@code host} or {code factory} was {@code null}. |
| | | */ |
| | | public void close() throws IOException |
| | | public LDAPListener(final String host, final int port, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory) |
| | | throws IOException, NullPointerException |
| | | { |
| | | this(host, port, factory, new LDAPListenerOptions()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new LDAP listener implementation which will listen for LDAP |
| | | * client connections at the provided address. |
| | | * |
| | | * @param host |
| | | * The address to listen on. |
| | | * @param port |
| | | * The port 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. |
| | | * @throws NullPointerException |
| | | * If {@code host}, {code factory}, or {@code options} was |
| | | * {@code null}. |
| | | */ |
| | | public LDAPListener(final String host, final int port, |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> factory, |
| | | final LDAPListenerOptions options) throws IOException, |
| | | NullPointerException |
| | | { |
| | | Validator.ensureNotNull(host, factory, options); |
| | | final SocketAddress address = new InetSocketAddress(host, port); |
| | | this.impl = new LDAPListenerImpl(address, factory, options); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Closes this LDAP connection listener. |
| | | */ |
| | | @Override |
| | | public void close() |
| | | { |
| | | impl.close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the {@code InetAddress} that this LDAP listener is listening on. |
| | | * |
| | | * @return The {@code InetAddress} that this LDAP listener is listening on, or |
| | | * {@code null} if it is unknown. |
| | | */ |
| | | public InetAddress getAddress() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getAddress(); |
| | | } |
| | | else |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the host name that this LDAP listener is listening on. |
| | | * |
| | | * @return The host name that this LDAP listener is listening on, or |
| | | * {@code null} if it is unknown. |
| | | */ |
| | | public String getHostname() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getHostName(); |
| | | } |
| | | else |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the port that this LDAP listener is listening on. |
| | | * |
| | | * @return The port that this LDAP listener is listening on, or {@code -1} if |
| | | * it is unknown. |
| | | */ |
| | | public int getPort() |
| | | { |
| | | final SocketAddress socketAddress = getSocketAddress(); |
| | | if (socketAddress instanceof InetSocketAddress) |
| | | { |
| | | final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; |
| | | return inetSocketAddress.getPort(); |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the address that this LDAP listener is listening on. |
| | | * |
| | | * @return The address that this LDAP listener is listening on. |
| | | */ |
| | | public SocketAddress getSocketAddress() |
| | | { |
| | | return impl.getSocketAddress(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | return impl.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | |
| | | |
| | | |
| | | |
| | | boolean addAll(final LinkedAttribute attribute, |
| | | final Collection<? extends ByteString> values, |
| | | final Collection<? super ByteString> duplicateValues) |
| | | throws NullPointerException |
| | | { |
| | | // TODO: could optimize if values is a BasicAttribute. |
| | | ensureCapacity(attribute, values.size()); |
| | | boolean modified = false; |
| | | for (final ByteString value : values) |
| | | { |
| | | if (add(attribute, value)) |
| | | { |
| | | modified = true; |
| | | } |
| | | else if (duplicateValues != null) |
| | | { |
| | | duplicateValues.add(value); |
| | | } |
| | | } |
| | | resize(attribute); |
| | | return modified; |
| | | } |
| | | |
| | | |
| | | |
| | | abstract void clear(LinkedAttribute attribute); |
| | | |
| | | |
| | |
| | | boolean containsAll(final LinkedAttribute attribute, |
| | | final Collection<?> values) |
| | | { |
| | | // TODO: could optimize if objects is a BasicAttribute. |
| | | // TODO: could optimize if objects is a LinkedAttribute having the same |
| | | // equality matching rule. |
| | | for (final Object value : values) |
| | | { |
| | | if (!contains(attribute, ByteString.valueOf(value))) |
| | |
| | | |
| | | |
| | | |
| | | abstract void ensureCapacity(LinkedAttribute attribute, int size); |
| | | |
| | | |
| | | |
| | | abstract ByteString firstValue(LinkedAttribute attribute) |
| | | throws NoSuchElementException; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | <T> boolean removeAll(final LinkedAttribute attribute, |
| | | final Collection<T> values, final Collection<? super T> missingValues) |
| | | { |
| | | // TODO: could optimize if objects is a BasicAttribute. |
| | | boolean modified = false; |
| | | for (final T value : values) |
| | | { |
| | | if (remove(attribute, ByteString.valueOf(value))) |
| | | { |
| | | modified = true; |
| | | } |
| | | else if (missingValues != null) |
| | | { |
| | | missingValues.add(value); |
| | | } |
| | | } |
| | | return modified; |
| | | } |
| | | |
| | | |
| | | |
| | | abstract void resize(LinkedAttribute attribute); |
| | | |
| | | |
| | | |
| | | abstract <T> boolean retainAll(LinkedAttribute attribute, |
| | | Collection<T> values, Collection<? super T> missingValues); |
| | | |
| | |
| | | |
| | | |
| | | @Override |
| | | void ensureCapacity(final LinkedAttribute attribute, final int size) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | ByteString firstValue(final LinkedAttribute attribute) |
| | | throws NoSuchElementException |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean hasNext() |
| | | { |
| | | return iterator.hasNext(); |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public ByteString next() |
| | | { |
| | | if (attribute.pimpl != expectedImpl) |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void remove() |
| | | { |
| | | if (attribute.pimpl != expectedImpl) |
| | |
| | | |
| | | |
| | | @Override |
| | | void resize(final LinkedAttribute attribute) |
| | | { |
| | | // May need to resize if initial size estimate was wrong (e.g. all |
| | | // values in added collection were the same). |
| | | switch (attribute.multipleValues.size()) |
| | | { |
| | | case 0: |
| | | attribute.multipleValues = null; |
| | | attribute.pimpl = ZERO_VALUE_IMPL; |
| | | break; |
| | | case 1: |
| | | final Map.Entry<ByteString, ByteString> e = attribute.multipleValues |
| | | .entrySet().iterator().next(); |
| | | attribute.singleValue = e.getValue(); |
| | | attribute.normalizedSingleValue = e.getKey(); |
| | | attribute.multipleValues = null; |
| | | attribute.pimpl = SINGLE_VALUE_IMPL; |
| | | break; |
| | | default: |
| | | // Nothing to do. |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | <T> boolean retainAll(final LinkedAttribute attribute, |
| | | final Collection<T> values, final Collection<? super T> missingValues) |
| | | { |
| | | // TODO: could optimize if objects is a BasicAttribute. |
| | | // TODO: could optimize if objects is a LinkedAttribute having the same |
| | | // equality matching rule. |
| | | if (values.isEmpty()) |
| | | { |
| | | clear(attribute); |
| | |
| | | { |
| | | return attribute.multipleValues.size(); |
| | | } |
| | | |
| | | |
| | | |
| | | private void resize(final LinkedAttribute attribute) |
| | | { |
| | | // May need to resize if initial size estimate was wrong (e.g. all |
| | | // values in added collection were the same). |
| | | switch (attribute.multipleValues.size()) |
| | | { |
| | | case 0: |
| | | attribute.multipleValues = null; |
| | | attribute.pimpl = ZERO_VALUE_IMPL; |
| | | break; |
| | | case 1: |
| | | final Map.Entry<ByteString, ByteString> e = attribute.multipleValues |
| | | .entrySet().iterator().next(); |
| | | attribute.singleValue = e.getValue(); |
| | | attribute.normalizedSingleValue = e.getKey(); |
| | | attribute.multipleValues = null; |
| | | attribute.pimpl = SINGLE_VALUE_IMPL; |
| | | break; |
| | | default: |
| | | // Nothing to do. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | @Override |
| | | void ensureCapacity(final LinkedAttribute attribute, final int size) |
| | | { |
| | | if (size == 0) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>( |
| | | 1 + size); |
| | | attribute.multipleValues.put(attribute.normalizedSingleValue, |
| | | attribute.singleValue); |
| | | attribute.singleValue = null; |
| | | attribute.normalizedSingleValue = null; |
| | | attribute.pimpl = MULTI_VALUE_IMPL; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | ByteString firstValue(final LinkedAttribute attribute) |
| | | throws NoSuchElementException |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public boolean hasNext() |
| | | { |
| | | return hasNext; |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public ByteString next() |
| | | { |
| | | if (attribute.pimpl != expectedImpl) |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void remove() |
| | | { |
| | | if (attribute.pimpl != expectedImpl) |
| | |
| | | |
| | | |
| | | @Override |
| | | void resize(final LinkedAttribute attribute) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | <T> boolean retainAll(final LinkedAttribute attribute, |
| | | final Collection<T> values, final Collection<? super T> missingValues) |
| | | { |
| | | // TODO: could optimize if objects is a BasicAttribute. |
| | | // TODO: could optimize if objects is a LinkedAttribute having the same |
| | | // equality matching rule. |
| | | if (values.isEmpty()) |
| | | { |
| | | clear(attribute); |
| | |
| | | boolean retained = false; |
| | | for (final T value : values) |
| | | { |
| | | final ByteString normalizedValue = normalizeValue(attribute, ByteString |
| | | .valueOf(value)); |
| | | final ByteString normalizedValue = normalizeValue(attribute, |
| | | ByteString.valueOf(value)); |
| | | if (normalizedSingleValue.equals(normalizedValue)) |
| | | { |
| | | if (missingValues == null) |
| | |
| | | |
| | | |
| | | @Override |
| | | void ensureCapacity(final LinkedAttribute attribute, final int size) |
| | | { |
| | | if (size < 2) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | attribute.multipleValues = new LinkedHashMap<ByteString, ByteString>(size); |
| | | attribute.pimpl = MULTI_VALUE_IMPL; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | ByteString firstValue(final LinkedAttribute attribute) |
| | | throws NoSuchElementException |
| | | { |
| | |
| | | { |
| | | return new Iterator<ByteString>() |
| | | { |
| | | @Override |
| | | public boolean hasNext() |
| | | { |
| | | return false; |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public ByteString next() |
| | | { |
| | | if (attribute.pimpl != ZERO_VALUE_IMPL) |
| | |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void remove() |
| | | { |
| | | if (attribute.pimpl != ZERO_VALUE_IMPL) |
| | |
| | | |
| | | |
| | | @Override |
| | | void resize(final LinkedAttribute attribute) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | <T> boolean retainAll(final LinkedAttribute attribute, |
| | | final Collection<T> values, final Collection<? super T> missingValues) |
| | | { |
| | |
| | | */ |
| | | public static final AttributeFactory FACTORY = new AttributeFactory() |
| | | { |
| | | @Override |
| | | public Attribute newAttribute( |
| | | final AttributeDescription attributeDescription) |
| | | throws NullPointerException |
| | |
| | | * @param values |
| | | * The attribute values. |
| | | * @throws NullPointerException |
| | | * If {@code attributeDescription} or {@code values} was {@code |
| | | * null}. |
| | | * If {@code attributeDescription} or {@code values} was |
| | | * {@code null}. |
| | | */ |
| | | public LinkedAttribute(final AttributeDescription attributeDescription, |
| | | final ByteString... values) throws NullPointerException |
| | |
| | | * @param values |
| | | * The attribute values. |
| | | * @throws NullPointerException |
| | | * If {@code attributeDescription} or {@code values} was {@code |
| | | * null}. |
| | | * If {@code attributeDescription} or {@code values} was |
| | | * {@code null}. |
| | | */ |
| | | public LinkedAttribute(final AttributeDescription attributeDescription, |
| | | final Collection<ByteString> values) throws NullPointerException |
| | |
| | | * If {@code attributeDescription} could not be decoded using the |
| | | * default schema. |
| | | * @throws NullPointerException |
| | | * If {@code attributeDescription} or {@code values} was {@code |
| | | * null}. |
| | | * If {@code attributeDescription} or {@code values} was |
| | | * {@code null}. |
| | | */ |
| | | public LinkedAttribute(final String attributeDescription, |
| | | final Object... values) throws LocalizedIllegalArgumentException, |
| | |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(values); |
| | | return pimpl.addAll(this, values, duplicateValues); |
| | | |
| | | // TODO: could optimize if objects is a LinkedAttribute having the same |
| | | // equality matching rule. |
| | | boolean modified = false; |
| | | for (final ByteString value : values) |
| | | { |
| | | if (add(value)) |
| | | { |
| | | modified = true; |
| | | } |
| | | else if (duplicateValues != null) |
| | | { |
| | | duplicateValues.add(value); |
| | | } |
| | | } |
| | | return modified; |
| | | } |
| | | |
| | | |
| | |
| | | final Collection<? super T> missingValues) throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(values); |
| | | return pimpl.removeAll(this, values, missingValues); |
| | | |
| | | // TODO: could optimize if objects is a LinkedAttribute having the same |
| | | // equality matching rule. |
| | | boolean modified = false; |
| | | for (final T value : values) |
| | | { |
| | | if (remove(ByteString.valueOf(value))) |
| | | { |
| | | modified = true; |
| | | } |
| | | else if (missingValues != null) |
| | | { |
| | | missingValues.add(value); |
| | | } |
| | | } |
| | | return modified; |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import com.sun.opends.sdk.util.CompletedFutureResult; |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A load balancing connection factory allocates connections using the provided |
| | | * algorithm. |
| | | */ |
| | | final class LoadBalancer extends AbstractConnectionFactory |
| | | { |
| | | private final LoadBalancingAlgorithm algorithm; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new load balancer using the provided algorithm. |
| | | * |
| | | * @param algorithm |
| | | * The load balancing algorithm which will be used to obtain the next |
| | | * connection factory. |
| | | */ |
| | | public LoadBalancer(final LoadBalancingAlgorithm algorithm) |
| | | { |
| | | Validator.ensureNotNull(algorithm); |
| | | this.algorithm = algorithm; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public FutureResult<AsynchronousConnection> getAsynchronousConnection( |
| | | final ResultHandler<? super AsynchronousConnection> resultHandler) |
| | | { |
| | | final ConnectionFactory factory; |
| | | |
| | | try |
| | | { |
| | | factory = algorithm.getConnectionFactory(); |
| | | } |
| | | catch (final ErrorResultException e) |
| | | { |
| | | if (resultHandler != null) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | return new CompletedFutureResult<AsynchronousConnection>(e); |
| | | } |
| | | |
| | | return factory.getAsynchronousConnection(resultHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("LoadBalancer("); |
| | | builder.append(String.valueOf(algorithm)); |
| | | builder.append(')'); |
| | | return builder.toString(); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * A load balancing algorithm distributes connection requests across one or more |
| | | * underlying connection factories in an implementation defined manner. |
| | | * |
| | | * @see Connections#newLoadBalancer(LoadBalancingAlgorithm) newLoadBalancer |
| | | */ |
| | | interface LoadBalancingAlgorithm |
| | | public interface LoadBalancingAlgorithm |
| | | { |
| | | /** |
| | | * Returns the next connection factory which should be used in order to obtain |
| | | * a connection. |
| | | * Returns a connection factory which should be used in order to satisfy the |
| | | * next connection request. |
| | | * |
| | | * @return The next connection factory. |
| | | * @return The connection factory. |
| | | * @throws ErrorResultException |
| | | * If no connection factories are available for use. |
| | | */ |
| | | ConnectionFactory getNextConnectionFactory() throws ErrorResultException; |
| | | ConnectionFactory getConnectionFactory() throws ErrorResultException; |
| | | } |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A round robin load balancing algorithm distributes connection requests across |
| | | * a list of connection factories one at a time. When the end of the list is |
| | | * reached, the algorithm starts again from the beginning. |
| | | * <p> |
| | | * This algorithm is typically used for load-balancing <i>within</i> data |
| | | * centers, where load must be distributed equally across multiple data sources. |
| | | * This algorithm contrasts with the {@link FailoverLoadBalancingAlgorithm} |
| | | * which is used for load-balancing <i>between</i> data centers. |
| | | * <p> |
| | | * If a problem occurs that temporarily prevents connections from being obtained |
| | | * for one of the connection factories, then this algorithm automatically |
| | | * "fails over" to the next operational connection factory in the list. If none |
| | | * of the connection factories are operational then a |
| | | * {@code ConnectionException} is returned to the client. |
| | | * <p> |
| | | * The implementation periodically attempts to connect to failed connection |
| | | * factories in order to determine if they have become available again. |
| | | * |
| | | * @see FailoverLoadBalancingAlgorithm |
| | | * @see Connections#newLoadBalancer(LoadBalancingAlgorithm) |
| | | */ |
| | | public final class RoundRobinLoadBalancingAlgorithm extends |
| | | AbstractLoadBalancingAlgorithm |
| | | { |
| | | private final int maxIndex; |
| | | |
| | | private final AtomicInteger nextIndex = new AtomicInteger(-1); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new round robin load balancing algorithm which will use a default |
| | | * scheduler for monitoring offline connection factories every 10 seconds. |
| | | * |
| | | * @param factories |
| | | * The unordered collection of connection factories. |
| | | */ |
| | | public RoundRobinLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories) |
| | | { |
| | | super(factories); |
| | | this.maxIndex = factories.size(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new round robin load balancing algorithm which will use the |
| | | * provided scheduler for monitoring offline connection factories every 10 |
| | | * seconds. |
| | | * |
| | | * @param factories |
| | | * The unordered collection of connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring offline |
| | | * connection factories to see if they are usable again. |
| | | */ |
| | | public RoundRobinLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler) |
| | | { |
| | | super(factories, scheduler); |
| | | this.maxIndex = factories.size(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new round robin load balancing algorithm which will use the |
| | | * provided scheduler for monitoring offline connection factories. |
| | | * |
| | | * @param factories |
| | | * The unordered collection of connection factories. |
| | | * @param scheduler |
| | | * The scheduler which should for periodically monitoring offline |
| | | * connection factories to see if they are usable again. |
| | | * @param interval |
| | | * The interval between attempts to poll offline connection |
| | | * factories. |
| | | * @param unit |
| | | * The time unit for the interval between attempts to poll offline |
| | | * connection factories. |
| | | */ |
| | | public RoundRobinLoadBalancingAlgorithm( |
| | | final Collection<ConnectionFactory> factories, |
| | | final ScheduledExecutorService scheduler, final long interval, |
| | | final TimeUnit unit) |
| | | { |
| | | super(factories, scheduler, interval, unit); |
| | | this.maxIndex = factories.size(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | String getAlgorithmName() |
| | | { |
| | | return "RoundRobin"; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | int getInitialConnectionFactoryIndex() |
| | | { |
| | | // A round robin pool of one connection factories is unlikely in practice |
| | | // and requires special treatment. |
| | | if (maxIndex == 1) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | // Determine the next factory to use: avoid blocking algorithm. |
| | | int oldNextIndex; |
| | | int newNextIndex; |
| | | do |
| | | { |
| | | oldNextIndex = nextIndex.get(); |
| | | newNextIndex = oldNextIndex + 1; |
| | | if (newNextIndex == maxIndex) |
| | | { |
| | | newNextIndex = 0; |
| | | } |
| | | } |
| | | while (!nextIndex.compareAndSet(oldNextIndex, newNextIndex)); |
| | | |
| | | // There's a potential, but benign, race condition here: other threads could |
| | | // jump in and rotate through the list before we return the connection |
| | | // factory. |
| | | return newNextIndex; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | /** |
| | | * A handler interface for processing requests from clients. |
| | | * <p> |
| | | * Implementations should always return results via the provided |
| | | * {@code RequestHandler} when processing requests unless otherwise indicated by |
| | | * the component passing requests to the {@code ServerConnection}. For example, |
| | | * an {@link LDAPListener} does not require {@code ServerConnection} |
| | | * implementations to return results, which may be useful when implementing |
| | | * abandon operation functionality. |
| | | * <p> |
| | | * Note that {@code ServerConnection}s may be stacked, and that a lower |
| | | * {@code ServerConnection} implementation, such as a logger, may require upper |
| | | * {@code ServerConnection} implementations to always return results. |
| | | * |
| | | * @param <C> |
| | | * The type of request context. |
| | | * @see ServerConnectionFactory |
| | | */ |
| | | public interface ServerConnection<C> |
| | | { |
| | |
| | | * request. |
| | | * |
| | | * @param requestContext |
| | | * The request context. |
| | | * The request context which should be ignored if there was no |
| | | * associated unbind request. |
| | | * @param request |
| | | * The unbind request, which may be {@code null} if one was not sent |
| | | * before the connection was closed. |
| | |
| | | |
| | | |
| | | /** |
| | | * Invoked when the server disconnects the client connection, possibly using a |
| | | * disconnect notification. |
| | | * |
| | | * @param resultCode |
| | | * The result code which was included with the disconnect |
| | | * notification, or {@code null} if no disconnect notification was |
| | | * sent. |
| | | * @param message |
| | | * The diagnostic message, which may be empty or {@code null} |
| | | * indicating that none was provided. |
| | | */ |
| | | void handleConnectionDisconnected(ResultCode resultCode, String message); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Invoked when an error occurs on the connection and it is no longer usable. |
| | | * |
| | | * @param error |
| | | * The exception describing the problem that occurred. |
| | | */ |
| | | void handleConnectionException(Throwable error); |
| | | void handleConnectionError(Throwable error); |
| | | |
| | | |
| | | |
| | |
| | | * @param request |
| | | * The search request. |
| | | * @param resultHandler |
| | | * The handler which should be used to send back the result to the |
| | | * client. |
| | | * @param searchResulthandler |
| | | * The handler which should be used to send back the search result |
| | | * entries and references to the client. |
| | | * The handler which should be used to send back the search results |
| | | * to the client. |
| | | * @param intermediateResponseHandler |
| | | * The handler which should be used to send back any intermediate |
| | | * responses to the client. |
| | |
| | | * If this server connection does not handle search requests. |
| | | */ |
| | | void handleSearch(C requestContext, SearchRequest request, |
| | | ResultHandler<? super Result> resultHandler, |
| | | SearchResultHandler searchResulthandler, |
| | | SearchResultHandler resultHandler, |
| | | IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException; |
| | | } |
| | |
| | | |
| | | /** |
| | | * A handler interface for accepting new connections from clients. |
| | | * <p> |
| | | * A connection listener implementation, such as {@link LDAPListener} or |
| | | * {@link Connections#newInternalConnectionFactory newInternalConnectionFactory} |
| | | * , invoke the method {@link #handleAccept(Object) handleAccept} whenever a new |
| | | * client connection is accepted. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | | * @param <R> |
| | | * The type of request context. |
| | | * @see LDAPListener |
| | | * @see Connections#newInternalConnectionFactory(ServerConnectionFactory, |
| | | * Object) newInternalConnectionFactory |
| | | */ |
| | | public interface ServerConnectionFactory<C, R> |
| | | { |
| | | /** |
| | | * Returns a {@code ServerConnection} which will be used to handle requests |
| | | * from a client connection. |
| | | * Invoked when a new client connection is accepted by the associated |
| | | * listener. Implementations should return a {@code ServerConnection} which |
| | | * will be used to handle requests from the client connection. |
| | | * |
| | | * @param clientContext |
| | | * The protocol dependent context information associated with the |
| | |
| | | * information about the client such as their address and level |
| | | * connection security. It may also be used to manage the state of |
| | | * the client's connection. |
| | | * @return a {@code ServerConnection} which will be used to handle requests |
| | | * @return A {@code ServerConnection} which will be used to handle requests |
| | | * from a client connection. |
| | | * @throws ErrorResultException |
| | | * If this server connection factory cannot accept the client |
| | | * connection. |
| | | */ |
| | | ServerConnection<R> accept(C clientContext) throws ErrorResultException; |
| | | ServerConnection<R> handleAccept(C clientContext) throws ErrorResultException; |
| | | } |
| | |
| | | import java.util.concurrent.BlockingQueue; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A {@code SynchronousConnection} adapts an {@code AsynchronousConnection} into |
| | | * a synchronous {@code Connection}. |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConnectionEntryReader search(final SearchRequest request, |
| | | BlockingQueue<Response> entries) |
| | | throws UnsupportedOperationException, IllegalStateException, |
| | | NullPointerException |
| | | BlockingQueue<Response> entries) throws UnsupportedOperationException, |
| | | IllegalStateException, NullPointerException |
| | | { |
| | | return new ConnectionEntryReader(getAsynchronousConnection(), |
| | | request, entries); |
| | | return new ConnectionEntryReader(getAsynchronousConnection(), request, |
| | | entries); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String toString() |
| | | { |
| | | return connection.toString(); |
| | | } |
| | | |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * Classes implementing common LDAP controls. |
| | | * Classes and interfaces for common LDAP controls. |
| | | */ |
| | | package org.opends.sdk.controls; |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | /** |
| | | * Core OpenDS SDK API including connections, entries, and attributes. |
| | | * Classes and interfaces for core types including connections, entries, and |
| | | * attributes. |
| | | */ |
| | | package org.opends.sdk; |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the message ID of the request to be abandoned. |
| | | * Returns the request ID of the request to be abandoned. |
| | | * |
| | | * @return The message ID of the request to be abandoned. |
| | | * @return The request ID of the request to be abandoned. |
| | | */ |
| | | int getMessageID(); |
| | | int getRequestID(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the message ID of the request to be abandoned. |
| | | * Sets the request ID of the request to be abandoned. |
| | | * |
| | | * @param id |
| | | * The message ID of the request to be abandoned. |
| | | * The request ID of the request to be abandoned. |
| | | * @return This abandon request. |
| | | * @throws UnsupportedOperationException |
| | | * If this abandon request does not permit the message ID to be set. |
| | | * If this abandon request does not permit the request ID to be set. |
| | | */ |
| | | AbandonRequest setMessageID(int id) throws UnsupportedOperationException; |
| | | AbandonRequest setRequestID(int id) throws UnsupportedOperationException; |
| | | |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | implements AbandonRequest |
| | | { |
| | | |
| | | private int messageID; |
| | | private int requestID; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new abandon request using the provided message ID. |
| | | * |
| | | * @param messageID |
| | | * @param requestID |
| | | * The message ID of the request to be abandoned. |
| | | */ |
| | | AbandonRequestImpl(final int messageID) |
| | | AbandonRequestImpl(final int requestID) |
| | | { |
| | | this.messageID = messageID; |
| | | this.requestID = requestID; |
| | | } |
| | | |
| | | |
| | | |
| | | public int getMessageID() |
| | | public int getRequestID() |
| | | { |
| | | return messageID; |
| | | return requestID; |
| | | } |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public AbandonRequest setMessageID(final int id) |
| | | public AbandonRequest setRequestID(final int id) |
| | | throws UnsupportedOperationException |
| | | { |
| | | this.messageID = id; |
| | | this.requestID = id; |
| | | return this; |
| | | } |
| | | |
| | |
| | | public String toString() |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("AbandonRequest(messageID="); |
| | | builder.append(getMessageID()); |
| | | builder.append("AbandonRequest(requestID="); |
| | | builder.append(getRequestID()); |
| | | builder.append(", controls="); |
| | | builder.append(getControls()); |
| | | builder.append(")"); |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the message ID of the request to be abandoned. |
| | | * |
| | | * @return The message ID of the request to be abandoned. |
| | | * {@inheritDoc} |
| | | */ |
| | | int getMessageID(); |
| | | String getOID(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | * Returns the request ID of the request to be abandoned. |
| | | * |
| | | * @return The request ID of the request to be abandoned. |
| | | */ |
| | | String getOID(); |
| | | int getRequestID(); |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the message ID of the request to be abandoned. |
| | | * Sets the request ID of the request to be abandoned. |
| | | * |
| | | * @param id |
| | | * The message ID of the request to be abandoned. |
| | | * The request ID of the request to be abandoned. |
| | | * @return This abandon request. |
| | | * @throws UnsupportedOperationException |
| | | * If this abandon request does not permit the message ID to be set. |
| | | * If this abandon request does not permit the request ID to be set. |
| | | */ |
| | | CancelExtendedRequest setMessageID(int id) |
| | | CancelExtendedRequest setRequestID(int id) |
| | | throws UnsupportedOperationException; |
| | | } |
| | |
| | | import org.opends.sdk.asn1.ASN1Reader; |
| | | import org.opends.sdk.asn1.ASN1Writer; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.responses.AbstractExtendedResultDecoder; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.Responses; |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<ExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<ExtendedResult> |
| | | { |
| | | public ExtendedResult adaptExtendedErrorResult(final ResultCode resultCode, |
| | | public ExtendedResult newExtendedErrorResult(final ResultCode resultCode, |
| | | final String matchedDN, final String diagnosticMessage) |
| | | { |
| | | return Responses.newGenericExtendedResult(resultCode).setMatchedDN( |
| | |
| | | |
| | | |
| | | |
| | | private int messageID; |
| | | private int requestID; |
| | | |
| | | // No need to expose this. |
| | | private static final ExtendedResultDecoder<ExtendedResult> RESULT_DECODER = new ResultDecoder(); |
| | |
| | | |
| | | |
| | | // Instantiation via factory. |
| | | CancelExtendedRequestImpl(final int messageID) |
| | | CancelExtendedRequestImpl(final int requestID) |
| | | { |
| | | this.messageID = messageID; |
| | | this.requestID = requestID; |
| | | } |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getMessageID() |
| | | public int getRequestID() |
| | | { |
| | | return messageID; |
| | | return requestID; |
| | | } |
| | | |
| | | |
| | |
| | | try |
| | | { |
| | | writer.writeStartSequence(); |
| | | writer.writeInteger(messageID); |
| | | writer.writeInteger(requestID); |
| | | writer.writeEndSequence(); |
| | | } |
| | | catch (final IOException ioe) |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public CancelExtendedRequest setMessageID(final int id) |
| | | public CancelExtendedRequest setRequestID(final int id) |
| | | { |
| | | this.messageID = id; |
| | | this.requestID = id; |
| | | return this; |
| | | } |
| | | |
| | |
| | | final StringBuilder builder = new StringBuilder(); |
| | | builder.append("CancelExtendedRequest(requestName="); |
| | | builder.append(getOID()); |
| | | builder.append(", messageID="); |
| | | builder.append(messageID); |
| | | builder.append(", requestID="); |
| | | builder.append(requestID); |
| | | builder.append(", controls="); |
| | | builder.append(getControls()); |
| | | builder.append(")"); |
| | |
| | | |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.controls.Control; |
| | |
| | | */ |
| | | public static final String SASL_MECHANISM_NAME = "DIGEST-MD5"; |
| | | |
| | | |
| | | /** |
| | | * Indicates that the client will accept authentication only. More |
| | | * specifically, the underlying connection will not be protected using |
| | | * integrity protection or encryption, unless previously established using |
| | | * SSL/TLS. This is the default if no QOP option is present in the bind |
| | | * request. |
| | | */ |
| | | public static final String QOP_AUTH = "auth"; |
| | | |
| | | /** |
| | | * Supported quality-of-protection options. |
| | | * Indicates that the client will accept authentication with connection |
| | | * integrity protection. More specifically, the underlying connection will not |
| | | * be encrypted, unless previously established using SSL/TLS. |
| | | */ |
| | | public static enum QOPOption |
| | | { |
| | | /** |
| | | * Authentication only. |
| | | */ |
| | | AUTH, |
| | | public static final String QOP_AUTH_INT = "auth-int"; |
| | | |
| | | /** |
| | | * Authentication plus integrity protection. |
| | | */ |
| | | AUTH_INT, |
| | | /** |
| | | * Indicates that the client will accept authentication with connection |
| | | * integrity protection and encryption. |
| | | */ |
| | | public static final String QOP_AUTH_CONF = "auth-conf"; |
| | | |
| | | /** |
| | | * Authentication plus integrity and confidentiality protection. |
| | | */ |
| | | AUTH_CONF |
| | | } |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the high |
| | | * strength triple-DES cipher. |
| | | */ |
| | | public static final String CIPHER_3DES = "3des"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the high |
| | | * strength 128-bit RC4 cipher. |
| | | */ |
| | | public static final String CIPHER_RC4_128 = "rc4"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the |
| | | * medium strength DES cipher. |
| | | */ |
| | | public static final String CIPHER_DES = "des"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the |
| | | * medium strength 56-bit RC4 cipher. |
| | | */ |
| | | public static final String CIPHER_RC4_56 = "rc4-56"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the low |
| | | * strength 40-bit RC4 cipher. |
| | | */ |
| | | public static final String CIPHER_RC4_40 = "rc4-40"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the |
| | | * strongest supported cipher, as long as the cipher is considered to be high |
| | | * strength. |
| | | */ |
| | | public static final String CIPHER_HIGH = "high"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the |
| | | * strongest supported cipher, as long as the cipher is considered to be high |
| | | * or medium strength. |
| | | */ |
| | | public static final String CIPHER_MEDIUM = "medium"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept connection encryption using the |
| | | * strongest supported cipher, even if the strongest cipher is considered to |
| | | * be medium or low strength. |
| | | */ |
| | | public static final String CIPHER_LOW = "low"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Cipher options for use with the security layer. |
| | | * Adds the provided additional authentication parameter to the list of |
| | | * parameters to be passed to the underlying mechanism implementation. This |
| | | * method is provided in order to allow for future extensions. |
| | | * |
| | | * @param name |
| | | * The name of the additional authentication parameter. |
| | | * @param value |
| | | * The value of the additional authentication parameter. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit additional authentication |
| | | * parameters to be added. |
| | | * @throws NullPointerException |
| | | * If {@code name} or {@code value} was {@code null}. |
| | | */ |
| | | public static enum CipherOption |
| | | { |
| | | /** |
| | | * Triple DES |
| | | * The "triple DES" cipher in CBC mode with EDE with the |
| | | * same key for each E stage (aka "two keys mode") for a |
| | | * total key length of 112 bits. |
| | | * <p> |
| | | * RC4 128 bits |
| | | * The RC4 cipher with a 128 bit key. |
| | | */ |
| | | TRIPLE_DES_RC4, |
| | | |
| | | /** |
| | | * DES |
| | | * The Data Encryption Standard (DES) cipher [FIPS] in |
| | | * cipher block chaining (CBC) mode with a 56 bit key. |
| | | * <p> |
| | | * RC4 56 bits |
| | | * The RC4 cipher with a 56 bit key. |
| | | */ |
| | | DES_RC4_56, |
| | | |
| | | /** |
| | | * RC4 40 bits |
| | | * The RC4 cipher with a 40 bit key. |
| | | */ |
| | | RC4_40 |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | DigestMD5SASLBindRequest addControl(Control control) |
| | | DigestMD5SASLBindRequest addAdditionalAuthParam(String name, String value) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | DigestMD5SASLBindRequest addControl(Control control) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the provided quality of protection (QOP) values to the ordered list of |
| | | * QOP values that the client is willing to accept. The order of the list |
| | | * specifies the preference order, high to low. Authentication will fail if no |
| | | * QOP values are recognized or accepted by the server. |
| | | * <p> |
| | | * By default the client will accept {@link #QOP_AUTH AUTH}. |
| | | * |
| | | * @param qopValues |
| | | * The quality of protection values that the client is willing to |
| | | * accept. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit QOP values to be added. |
| | | * @throws NullPointerException |
| | | * If {@code qopValues} was {@code null}. |
| | | * @see #QOP_AUTH |
| | | * @see #QOP_AUTH_INT |
| | | * @see #QOP_AUTH_CONF |
| | | */ |
| | | DigestMD5SASLBindRequest addQOP(String... qopValues) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindClient createBindClient(String serverName) throws ErrorResultException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns a map containing the provided additional authentication parameters |
| | | * to be passed to the underlying mechanism implementation. This method is |
| | | * provided in order to allow for future extensions. |
| | | * |
| | | * @return A map containing the provided additional authentication parameters |
| | | * to be passed to the underlying mechanism implementation. |
| | | */ |
| | | Map<String, String> getAdditionalAuthParams(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the authentication ID of the user. The authentication ID usually |
| | | * has the form "dn:" immediately followed by the distinguished name of the |
| | | * user, or "u:" followed by a user ID string, but other forms are permitted. |
| | |
| | | * |
| | | * @return The authentication mechanism identifier. |
| | | */ |
| | | @Override |
| | | byte getAuthenticationType(); |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the cipher name or strength that the client is willing to use when |
| | | * connection encryption quality of protection, {@link #QOP_AUTH_CONF |
| | | * AUTH-CONF}, is requested. |
| | | * <p> |
| | | * By default the client will accept connection encryption using the strongest |
| | | * supported cipher, even if the strongest cipher is considered to be medium |
| | | * or low strength. This is equivalent to {@link #CIPHER_LOW}. |
| | | * |
| | | * @return The cipher that the client is willing to use if connection |
| | | * encryption QOP is negotiated. May be {@code null}, indicating that |
| | | * the default cipher should be used. |
| | | */ |
| | | String getCipher(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | <C extends Control> C getControl(ControlDecoder<C> decoder, |
| | | DecodeOptions options) throws NullPointerException, DecodeException; |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | List<Control> getControls(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the receive buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * send buffer size. The default size is 65536. |
| | | * |
| | | * @return The maximum size of the receive buffer in bytes. |
| | | */ |
| | | int getMaxReceiveBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the send buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * receive buffer size. The default size is 65536. |
| | | * |
| | | * @return The maximum size of the send buffer in bytes. |
| | | */ |
| | | int getMaxSendBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the name of the Directory object that the client wishes to bind as, |
| | | * which is always the empty string for SASL authentication. |
| | | * |
| | | * @return The name of the Directory object that the client wishes to bind as. |
| | | */ |
| | | @Override |
| | | String getName(); |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the ordered list of quality of protection (QOP) values that the |
| | | * client is willing to accept. The order of the list specifies the preference |
| | | * order, high to low. Authentication will fail if no QOP values are |
| | | * recognized or accepted by the server. |
| | | * <p> |
| | | * By default the client will accept {@link #QOP_AUTH AUTH}. |
| | | * |
| | | * @return The list of quality of protection values that the client is willing |
| | | * to accept. The returned list may be empty indicating that the |
| | | * default QOP will be accepted. |
| | | */ |
| | | List<String> getQOPs(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the optional realm containing the user's account. |
| | | * |
| | | * @return The name of the realm containing the user's account, which may be |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | String getSASLMechanism(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the quality-of-protection options to use. |
| | | * The order of the list specifies the preference order. |
| | | * Returns {@code true} if the server must authenticate to the client. The |
| | | * default is {@code false}. |
| | | * |
| | | * @return The list of quality-of-protection options to use. |
| | | * @return {@code true} if the server must authenticate to the client. |
| | | */ |
| | | QOPOption[] getQOP(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the ciphers to use with the optional security layer |
| | | * offered by the {@code AUTH_CONF} quality-of-protection. The order |
| | | * of the list specifies the preference order. When there is |
| | | * more than one choice for a particular option, the cipher |
| | | * selected depends on the availability of the ciphers in the |
| | | * underlying platform. |
| | | * |
| | | * @return The list of cipher options to use. |
| | | */ |
| | | CipherOption[] getCipher(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns whether the server must authenticate to the client. |
| | | * |
| | | * @return {@code true} if the server must authenticate |
| | | * to the client or {@code false} otherwise. |
| | | */ |
| | | boolean getServerAuth(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the receive buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum send |
| | | * buffer size. |
| | | * |
| | | * @return The maximum size of the receive buffer in bytes. |
| | | */ |
| | | int getMaxReceiveBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the send buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum receive |
| | | * buffer size. |
| | | * |
| | | * @return The maximum size of the send buffer in bytes. |
| | | */ |
| | | int getMaxSendBufferSize(); |
| | | boolean isServerAuth(); |
| | | |
| | | |
| | | |
| | |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If {@code authenticationID} was non-empty and did not contain a |
| | | * valid authorization ID type. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the authentication ID to be |
| | | * set. |
| | | * @throws NullPointerException |
| | | * If {@code authenticationID} was {@code null}. |
| | | */ |
| | | DigestMD5SASLBindRequest setAuthenticationID(String authenticationID) |
| | | throws LocalizedIllegalArgumentException, NullPointerException; |
| | | throws LocalizedIllegalArgumentException, UnsupportedOperationException, |
| | | NullPointerException; |
| | | |
| | | |
| | | |
| | |
| | | * @throws LocalizedIllegalArgumentException |
| | | * If {@code authorizationID} was non-empty and did not contain a |
| | | * valid authorization ID type. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the authorization ID to be |
| | | * set. |
| | | */ |
| | | DigestMD5SASLBindRequest setAuthorizationID(String authorizationID) |
| | | throws LocalizedIllegalArgumentException; |
| | | throws LocalizedIllegalArgumentException, UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the cipher name or strength that the client is willing to use when |
| | | * connection encryption quality of protection, {@link #QOP_AUTH_CONF |
| | | * AUTH-CONF}, is requested. |
| | | * <p> |
| | | * By default the client will accept connection encryption using the strongest |
| | | * supported cipher, even if the strongest cipher is considered to be medium |
| | | * or low strength. This is equivalent to {@link #CIPHER_LOW}. |
| | | * |
| | | * @param cipher |
| | | * The cipher that the client is willing to use if connection |
| | | * encryption QOP is negotiated. May be {@code null}, indicating that |
| | | * the default cipher should be used. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the cipher name or strength |
| | | * to be set. |
| | | * @see #QOP_AUTH_CONF |
| | | * @see #CIPHER_3DES |
| | | * @see #CIPHER_RC4_128 |
| | | * @see #CIPHER_DES |
| | | * @see #CIPHER_RC4_56 |
| | | * @see #CIPHER_RC4_40 |
| | | * @see #CIPHER_HIGH |
| | | * @see #CIPHER_MEDIUM |
| | | * @see #CIPHER_LOW |
| | | */ |
| | | DigestMD5SASLBindRequest setCipher(String cipher) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the maximum size of the receive buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * send buffer size. The default size is 65536. |
| | | * |
| | | * @param size |
| | | * The maximum size of the receive buffer in bytes. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the buffer size to be set. |
| | | */ |
| | | DigestMD5SASLBindRequest setMaxReceiveBufferSize(int size) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the maximum size of the send buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * receive buffer size. The default size is 65536. |
| | | * |
| | | * @param size |
| | | * The maximum size of the send buffer in bytes. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the buffer size to be set. |
| | | */ |
| | | DigestMD5SASLBindRequest setMaxSendBufferSize(int size) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Specifies the quality-of-protection options to use. |
| | | * The order of the list specifies the preference order. |
| | | * Specifies whether or not the server must authenticate to the client. The |
| | | * default is {@code false}. |
| | | * |
| | | * @param qopOptions The list of quality-of-protection options to |
| | | * use. |
| | | * @param serverAuth |
| | | * {@code true} if the server must authenticate to the client or |
| | | * {@code false} otherwise. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit server auth to be set. |
| | | */ |
| | | DigestMD5SASLBindRequest setQOP(QOPOption... qopOptions); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the ciphers to use with the optional security layer |
| | | * offered by the {@code AUTH_CONF} quality-of-protection. The order |
| | | * of the list specifies the preference order. When there is |
| | | * more than one choice for a particular option, the cipher |
| | | * selected depends on the availability of the ciphers in the |
| | | * underlying platform. |
| | | * |
| | | * @param cipherOptions The list of cipher options to use. |
| | | * @return his bind request. |
| | | */ |
| | | DigestMD5SASLBindRequest setCipher(CipherOption... cipherOptions); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether the server must authenticate to the client. |
| | | * |
| | | * @param serverAuth {@code true} if the server must authenticate |
| | | * to the client or {@code false} otherwise. |
| | | * @return This bind request. |
| | | */ |
| | | DigestMD5SASLBindRequest setServerAuth(boolean serverAuth); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the maximum size of the receive buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum send |
| | | * buffer size. |
| | | * |
| | | * @param maxBuffer The maximum size of the receive buffer in bytes. |
| | | * @return This bind request. |
| | | */ |
| | | DigestMD5SASLBindRequest setMaxReceiveBufferSize(int maxBuffer); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the maximum size of the send buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum receive |
| | | * buffer size. |
| | | * |
| | | * @param maxBuffer The maximum size of the send buffer in bytes. |
| | | * @return This bind request. |
| | | */ |
| | | DigestMD5SASLBindRequest setMaxSendBufferSize(int maxBuffer); |
| | | DigestMD5SASLBindRequest setServerAuth(boolean serverAuth) |
| | | throws UnsupportedOperationException; |
| | | } |
| | |
| | | |
| | | import static com.sun.opends.sdk.messages.Messages.ERR_SASL_PROTOCOL_ERROR; |
| | | import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage; |
| | | import static com.sun.opends.sdk.util.StaticUtils.joinCollection; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.*; |
| | | |
| | | import javax.security.auth.callback.NameCallback; |
| | | import javax.security.auth.callback.PasswordCallback; |
| | |
| | | this.password = initialBindRequest.getPassword(); |
| | | this.realm = initialBindRequest.getRealm(); |
| | | |
| | | // Create property map containing all the parameters. |
| | | final Map<String, String> props = new HashMap<String, String>(); |
| | | props.put(Sasl.QOP, "auth-conf,auth-int,auth"); |
| | | |
| | | final List<String> qopValues = initialBindRequest.getQOPs(); |
| | | if (!qopValues.isEmpty()) |
| | | { |
| | | props.put(Sasl.QOP, joinCollection(qopValues, ",")); |
| | | } |
| | | |
| | | final String cipher = initialBindRequest.getCipher(); |
| | | if (cipher != null) |
| | | { |
| | | if (cipher.equalsIgnoreCase(CIPHER_LOW)) |
| | | { |
| | | props.put(Sasl.STRENGTH, "high,medium,low"); |
| | | } |
| | | else if (cipher.equalsIgnoreCase(CIPHER_MEDIUM)) |
| | | { |
| | | props.put(Sasl.STRENGTH, "high,medium"); |
| | | } |
| | | else if (cipher.equalsIgnoreCase(CIPHER_HIGH)) |
| | | { |
| | | props.put(Sasl.STRENGTH, "high"); |
| | | } |
| | | else |
| | | { |
| | | // Default strength allows all ciphers, so specifying a single cipher |
| | | // cannot be incompatible with the strength. |
| | | props.put("com.sun.security.sasl.digest.cipher", cipher); |
| | | } |
| | | } |
| | | |
| | | final Boolean serverAuth = initialBindRequest.isServerAuth(); |
| | | if (serverAuth != null) |
| | | { |
| | | props.put(Sasl.SERVER_AUTH, String.valueOf(serverAuth)); |
| | | } |
| | | |
| | | Integer size = initialBindRequest.getMaxReceiveBufferSize(); |
| | | if (size != null) |
| | | { |
| | | props.put(Sasl.MAX_BUFFER, String.valueOf(size)); |
| | | } |
| | | |
| | | size = initialBindRequest.getMaxSendBufferSize(); |
| | | if (size != null) |
| | | { |
| | | props.put("javax.security.sasl.sendmaxbuffer", String.valueOf(size)); |
| | | } |
| | | |
| | | for (final Map.Entry<String, String> e : initialBindRequest |
| | | .getAdditionalAuthParams().entrySet()) |
| | | { |
| | | props.put(e.getKey(), e.getValue()); |
| | | } |
| | | |
| | | // Now create the client. |
| | | try |
| | | { |
| | | saslClient = Sasl.createSaslClient( |
| | | new String[] { SASL_MECHANISM_NAME }, initialBindRequest |
| | | .getAuthorizationID(), SASL_DEFAULT_PROTOCOL, serverName, |
| | | props, this); |
| | | new String[] { SASL_MECHANISM_NAME }, |
| | | initialBindRequest.getAuthorizationID(), SASL_DEFAULT_PROTOCOL, |
| | | serverName, props, this); |
| | | if (saslClient.hasInitialResponse()) |
| | | { |
| | | setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0])); |
| | |
| | | try |
| | | { |
| | | setNextSASLCredentials(saslClient.evaluateChallenge(result |
| | | .getServerSASLCredentials() == null ? new byte[0] : |
| | | result.getServerSASLCredentials().toByteArray())); |
| | | .getServerSASLCredentials() == null ? new byte[0] : result |
| | | .getServerSASLCredentials().toByteArray())); |
| | | return saslClient.isComplete(); |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e)); |
| | | } |
| | | } |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private final Map<String, String> additionalAuthParams = new LinkedHashMap<String, String>(); |
| | | private final List<String> qopValues = new LinkedList<String>(); |
| | | private String cipher = null; |
| | | |
| | | // Don't use primitives for these so that we can distinguish between default |
| | | // settings (null) and values set by the caller. |
| | | private Boolean serverAuth = null; |
| | | private Integer maxReceiveBufferSize = null; |
| | | private Integer maxSendBufferSize = null; |
| | | |
| | | private String authenticationID; |
| | | private String authorizationID = null; |
| | | private ByteString password; |
| | | |
| | | private String realm = null; |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest addAdditionalAuthParam(final String name, |
| | | final String value) throws UnsupportedOperationException, |
| | | NullPointerException |
| | | { |
| | | Validator.ensureNotNull(name, value); |
| | | additionalAuthParams.put(name, value); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest addQOP(final String... qopValues) |
| | | throws UnsupportedOperationException, NullPointerException |
| | | { |
| | | for (final String qopValue : qopValues) |
| | | { |
| | | this.qopValues.add(Validator.ensureNotNull(qopValue)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public BindClient createBindClient(final String serverName) |
| | | throws ErrorResultException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Map<String, String> getAdditionalAuthParams() |
| | | { |
| | | return additionalAuthParams; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getAuthenticationID() |
| | | { |
| | | return authenticationID; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getAuthorizationID() |
| | | { |
| | | return authorizationID; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getCipher() |
| | | { |
| | | return cipher; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int getMaxReceiveBufferSize() |
| | | { |
| | | return maxReceiveBufferSize == null ? 65536 : maxReceiveBufferSize; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int getMaxSendBufferSize() |
| | | { |
| | | return maxSendBufferSize == null ? 65536 : maxSendBufferSize; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ByteString getPassword() |
| | | { |
| | | return password; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public List<String> getQOPs() |
| | | { |
| | | return qopValues; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getRealm() |
| | | { |
| | | return realm; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getSASLMechanism() |
| | | { |
| | | return SASL_MECHANISM_NAME; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isServerAuth() |
| | | { |
| | | return serverAuth == null ? false : serverAuth; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setAuthenticationID( |
| | | final String authenticationID) throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setAuthorizationID( |
| | | final String authorizationID) |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setCipher(final String cipher) |
| | | throws UnsupportedOperationException |
| | | { |
| | | this.cipher = cipher; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setMaxReceiveBufferSize(final int size) |
| | | throws UnsupportedOperationException |
| | | { |
| | | maxReceiveBufferSize = size; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setMaxSendBufferSize(final int size) |
| | | throws UnsupportedOperationException |
| | | { |
| | | maxSendBufferSize = size; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setPassword(final ByteString password) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setPassword(final String password) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public DigestMD5SASLBindRequest setRealm(final String realm) |
| | | { |
| | | this.realm = realm; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public QOPOption[] getQOP() { |
| | | String value = System.getProperty(Sasl.QOP); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return new QOPOption[]{QOPOption.AUTH}; |
| | | } |
| | | String[] values = value.split(","); |
| | | QOPOption[] options = new QOPOption[values.length]; |
| | | |
| | | for(int i = 0; i < values.length; i++) |
| | | { |
| | | String v = values[i].trim(); |
| | | if(v.equalsIgnoreCase("auth")) |
| | | { |
| | | options[i] = QOPOption.AUTH; |
| | | } |
| | | else if(v.equalsIgnoreCase("auth-int")) |
| | | { |
| | | options[i] = QOPOption.AUTH_INT; |
| | | } |
| | | else if(v.equalsIgnoreCase("auth-conf")) |
| | | { |
| | | options[i] = QOPOption.AUTH_CONF; |
| | | } |
| | | } |
| | | return options; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public CipherOption[] getCipher() { |
| | | String value = System.getProperty(Sasl.STRENGTH); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return new CipherOption[]{CipherOption.TRIPLE_DES_RC4, |
| | | CipherOption.DES_RC4_56, CipherOption.RC4_40}; |
| | | } |
| | | String[] values = value.split(","); |
| | | CipherOption[] options = new CipherOption[values.length]; |
| | | |
| | | for(int i = 0; i < values.length; i++) |
| | | { |
| | | String v = values[i].trim(); |
| | | if(v.equalsIgnoreCase("high")) |
| | | { |
| | | options[i] = CipherOption.TRIPLE_DES_RC4; |
| | | } |
| | | else if(v.equalsIgnoreCase("medium")) |
| | | { |
| | | options[i] = CipherOption.DES_RC4_56; |
| | | } |
| | | else if(v.equalsIgnoreCase("low")) |
| | | { |
| | | options[i] = CipherOption.RC4_40; |
| | | } |
| | | } |
| | | return options; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean getServerAuth() { |
| | | String value = System.getProperty(Sasl.SERVER_AUTH); |
| | | return !(value == null || value.length() == 0) && |
| | | value.equalsIgnoreCase("true"); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getMaxReceiveBufferSize() { |
| | | String value = System.getProperty(Sasl.MAX_BUFFER); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return 65536; |
| | | } |
| | | return Integer.parseInt(value); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getMaxSendBufferSize() { |
| | | String value = System.getProperty("javax.security.sasl.sendmaxbuffer"); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return 65536; |
| | | } |
| | | return Integer.parseInt(value); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DigestMD5SASLBindRequest setQOP(QOPOption... qopOptions) { |
| | | String values = null; |
| | | for(QOPOption option : qopOptions) |
| | | { |
| | | String value = null; |
| | | if(option == QOPOption.AUTH) |
| | | { |
| | | value = "auth"; |
| | | } |
| | | else if(option == QOPOption.AUTH_INT) |
| | | { |
| | | value = "auth-int"; |
| | | } |
| | | else if(option == QOPOption.AUTH_CONF) |
| | | { |
| | | value = "auth-conf"; |
| | | } |
| | | |
| | | if(value != null) |
| | | { |
| | | if(values == null) |
| | | { |
| | | values = value; |
| | | } |
| | | else |
| | | { |
| | | values += (", " + value); |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.setProperty(Sasl.QOP, values); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DigestMD5SASLBindRequest setCipher(CipherOption... cipherOptions) { |
| | | String values = null; |
| | | for(CipherOption option : cipherOptions) |
| | | { |
| | | String value = null; |
| | | if(option == CipherOption.TRIPLE_DES_RC4) |
| | | { |
| | | value = "high"; |
| | | } |
| | | else if(option == CipherOption.DES_RC4_56) |
| | | { |
| | | value = "medium"; |
| | | } |
| | | else if(option == CipherOption.RC4_40) |
| | | { |
| | | value = "low"; |
| | | } |
| | | |
| | | if(value != null) |
| | | { |
| | | if(values == null) |
| | | { |
| | | values = value; |
| | | } |
| | | else |
| | | { |
| | | values += (", " + value); |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.setProperty(Sasl.STRENGTH, values); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DigestMD5SASLBindRequest setServerAuth(boolean serverAuth) { |
| | | System.setProperty(Sasl.SERVER_AUTH, String.valueOf(serverAuth)); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DigestMD5SASLBindRequest setMaxReceiveBufferSize(int maxBuffer) { |
| | | System.setProperty(Sasl.MAX_BUFFER, String.valueOf(maxBuffer)); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DigestMD5SASLBindRequest setMaxSendBufferSize(int maxBuffer) { |
| | | System.setProperty("javax.security.sasl.sendmaxbuffer", |
| | | String.valueOf(maxBuffer)); |
| | | @Override |
| | | public DigestMD5SASLBindRequest setServerAuth(final boolean serverAuth) |
| | | throws UnsupportedOperationException |
| | | { |
| | | this.serverAuth = serverAuth; |
| | | return this; |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import javax.security.auth.Subject; |
| | | |
| | |
| | | */ |
| | | public static final String SASL_MECHANISM_NAME = "GSSAPI"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept authentication only. More |
| | | * specifically, the underlying connection will not be protected using |
| | | * integrity protection or encryption, unless previously established using |
| | | * SSL/TLS. This is the default if no QOP option is present in the bind |
| | | * request. |
| | | */ |
| | | public static final String QOP_AUTH = "auth"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept authentication with connection |
| | | * integrity protection. More specifically, the underlying connection will not |
| | | * be encrypted, unless previously established using SSL/TLS. |
| | | */ |
| | | public static final String QOP_AUTH_INT = "auth-int"; |
| | | |
| | | /** |
| | | * Indicates that the client will accept authentication with connection |
| | | * integrity protection and encryption. |
| | | */ |
| | | public static final String QOP_AUTH_CONF = "auth-conf"; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Supported quality-of-protection options. |
| | | * Adds the provided additional authentication parameter to the list of |
| | | * parameters to be passed to the underlying mechanism implementation. This |
| | | * method is provided in order to allow for future extensions. |
| | | * |
| | | * @param name |
| | | * The name of the additional authentication parameter. |
| | | * @param value |
| | | * The value of the additional authentication parameter. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit additional authentication |
| | | * parameters to be added. |
| | | * @throws NullPointerException |
| | | * If {@code name} or {@code value} was {@code null}. |
| | | */ |
| | | public static enum QOPOption |
| | | { |
| | | /** |
| | | * Authentication only. |
| | | */ |
| | | AUTH, |
| | | GSSAPISASLBindRequest addAdditionalAuthParam(String name, String value) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | /** |
| | | * Authentication plus integrity protection. |
| | | */ |
| | | AUTH_INT, |
| | | |
| | | /** |
| | | * Authentication plus integrity and confidentiality protection. |
| | | */ |
| | | AUTH_CONF |
| | | } |
| | | |
| | | /** |
| | | * Returns a map containing the provided additional authentication parameters |
| | | * to be passed to the underlying mechanism implementation. This method is |
| | | * provided in order to allow for future extensions. |
| | | * |
| | | * @return A map containing the provided additional authentication parameters |
| | | * to be passed to the underlying mechanism implementation. |
| | | */ |
| | | Map<String, String> getAdditionalAuthParams(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | GSSAPISASLBindRequest addControl(Control control) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the provided quality of protection (QOP) values to the ordered list of |
| | | * QOP values that the client is willing to accept. The order of the list |
| | | * specifies the preference order, high to low. Authentication will fail if no |
| | | * QOP values are recognized or accepted by the server. |
| | | * <p> |
| | | * By default the client will accept {@link #QOP_AUTH AUTH}. |
| | | * |
| | | * @param qopValues |
| | | * The quality of protection values that the client is willing to |
| | | * accept. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit QOP values to be added. |
| | | * @throws NullPointerException |
| | | * If {@code qopValues} was {@code null}. |
| | | * @see #QOP_AUTH |
| | | * @see #QOP_AUTH_INT |
| | | * @see #QOP_AUTH_CONF |
| | | */ |
| | | GSSAPISASLBindRequest addQOP(String... qopValues) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | BindClient createBindClient(String serverName) throws ErrorResultException; |
| | | |
| | | |
| | |
| | | * |
| | | * @return The authentication mechanism identifier. |
| | | */ |
| | | @Override |
| | | byte getAuthenticationType(); |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | <C extends Control> C getControl(ControlDecoder<C> decoder, |
| | | DecodeOptions options) throws NullPointerException, DecodeException; |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | List<Control> getControls(); |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the receive buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * send buffer size. The default size is 65536. |
| | | * |
| | | * @return The maximum size of the receive buffer in bytes. |
| | | */ |
| | | int getMaxReceiveBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the send buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * receive buffer size. The default size is 65536. |
| | | * |
| | | * @return The maximum size of the send buffer in bytes. |
| | | */ |
| | | int getMaxSendBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the name of the Directory object that the client wishes to bind as, |
| | | * which is always the empty string for SASL authentication. |
| | | * |
| | | * @return The name of the Directory object that the client wishes to bind as. |
| | | */ |
| | | @Override |
| | | String getName(); |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the ordered list of quality of protection (QOP) values that the |
| | | * client is willing to accept. The order of the list specifies the preference |
| | | * order, high to low. Authentication will fail if no QOP values are |
| | | * recognized or accepted by the server. |
| | | * <p> |
| | | * By default the client will accept {@link #QOP_AUTH AUTH}. |
| | | * |
| | | * @return The list of quality of protection values that the client is willing |
| | | * to accept. The returned list may be empty indicating that the |
| | | * default QOP will be accepted. |
| | | */ |
| | | List<String> getQOPs(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the optional realm containing the user's account. |
| | | * <p> |
| | | * <b>NOTE</b>: this will not be used if a {@code Subject} is specified. |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | String getSASLMechanism(); |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the quality-of-protection options to use. |
| | | * The order of the list specifies the preference order. |
| | | * Returns {@code true} if the server must authenticate to the client. The |
| | | * default is {@code false}. |
| | | * |
| | | * @return The list of quality-of-protection options to use. |
| | | * @return {@code true} if the server must authenticate to the client. |
| | | */ |
| | | QOPOption[] getQOP(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns whether the server must authenticate to the client. |
| | | * The default is {@code false}. |
| | | * |
| | | * @return {@code true} if the server must authenticate |
| | | * to the client or {@code false} otherwise. |
| | | */ |
| | | boolean getServerAuth(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the receive buffer in bytes. The |
| | | * default is 65536. The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum send |
| | | * buffer size. |
| | | * |
| | | * @return The maximum size of the receive buffer in bytes. |
| | | */ |
| | | int getMaxReceiveBufferSize(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the maximum size of the send buffer in bytes. The |
| | | * default is 65536. The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum receive |
| | | * buffer size. |
| | | * |
| | | * @return The maximum size of the send buffer in bytes. |
| | | */ |
| | | int getMaxSendBufferSize(); |
| | | |
| | | boolean isServerAuth(); |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the maximum size of the receive buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * send buffer size. The default size is 65536. |
| | | * |
| | | * @param size |
| | | * The maximum size of the receive buffer in bytes. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the buffer size to be set. |
| | | */ |
| | | GSSAPISASLBindRequest setMaxReceiveBufferSize(int size) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the maximum size of the send buffer in bytes. The actual maximum |
| | | * number of bytes will be the minimum of this number and the peer's maximum |
| | | * receive buffer size. The default size is 65536. |
| | | * |
| | | * @param size |
| | | * The maximum size of the send buffer in bytes. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit the buffer size to be set. |
| | | */ |
| | | GSSAPISASLBindRequest setMaxSendBufferSize(int size) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the password of the user that the client wishes to bind as. |
| | | * <p> |
| | | * <b>NOTE</b>: this will not be used if a {@code Subject} is specified. |
| | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether or not the server must authenticate to the client. The |
| | | * default is {@code false}. |
| | | * |
| | | * @param serverAuth |
| | | * {@code true} if the server must authenticate to the client or |
| | | * {@code false} otherwise. |
| | | * @return This bind request. |
| | | * @throws UnsupportedOperationException |
| | | * If this bind request does not permit server auth to be set. |
| | | */ |
| | | GSSAPISASLBindRequest setServerAuth(boolean serverAuth) |
| | | throws UnsupportedOperationException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the Kerberos subject of the user to be authenticated. |
| | | * <p> |
| | | * <b>NOTE</b>: if a {@code Subject} is specified then the authentication ID, |
| | |
| | | * If {@code subject} was {@code null}. |
| | | */ |
| | | GSSAPISASLBindRequest setSubject(Subject subject) throws NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the quality-of-protection options to use. |
| | | * The order of the list specifies the preference order. |
| | | * |
| | | * @param qopOptions The list of quality-of-protection options to |
| | | * use. |
| | | * @return This bind request. |
| | | */ |
| | | GSSAPISASLBindRequest setQOP(QOPOption... qopOptions); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies whether the server must authenticate to the client. |
| | | * |
| | | * @param serverAuth {@code true} if the server must authenticate |
| | | * to the client or {@code false} otherwise. |
| | | * @return This bind request. |
| | | */ |
| | | GSSAPISASLBindRequest setServerAuth(boolean serverAuth); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the maximum size of the receive buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum send |
| | | * buffer size. |
| | | * |
| | | * @param maxBuffer The maximum size of the receive buffer in bytes. |
| | | * @return This bind request. |
| | | */ |
| | | GSSAPISASLBindRequest setMaxReceiveBufferSize(int maxBuffer); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Specifies the maximum size of the send buffer in bytes. |
| | | * The actual maximum number of bytes will |
| | | * be the minimum of this number and the peer's maximum receive |
| | | * buffer size. |
| | | * |
| | | * @param maxBuffer The maximum size of the send buffer in bytes. |
| | | * @return This bind request. |
| | | */ |
| | | GSSAPISASLBindRequest setMaxSendBufferSize(int maxBuffer); |
| | | |
| | | } |
| | |
| | | import static com.sun.opends.sdk.messages.Messages.ERR_SASL_CONTEXT_CREATE_ERROR; |
| | | import static com.sun.opends.sdk.messages.Messages.ERR_SASL_PROTOCOL_ERROR; |
| | | import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage; |
| | | import static com.sun.opends.sdk.util.StaticUtils.joinCollection; |
| | | |
| | | import java.security.PrivilegedActionException; |
| | | import java.security.PrivilegedExceptionAction; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.*; |
| | | |
| | | import javax.security.auth.Subject; |
| | | import javax.security.auth.login.LoginException; |
| | |
| | | // FIXME: Is this the best result code? |
| | | final LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_LOCAL_AUTHENTICATION_FAILED |
| | | .get(StaticUtils.getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | message.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(message.toString()).setCause(e)); |
| | | } |
| | | return subject; |
| | | } |
| | |
| | | |
| | | |
| | | private final SaslClient saslClient; |
| | | private final String serverName; |
| | | private final String authorizationID; |
| | | private final Subject subject; |
| | | |
| | |
| | | private final PrivilegedExceptionAction<Boolean> evaluateAction = |
| | | new PrivilegedExceptionAction<Boolean>() |
| | | { |
| | | @Override |
| | | public Boolean run() throws ErrorResultException |
| | | { |
| | | if (lastResult.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e)); |
| | | } |
| | | } |
| | |
| | | } |
| | | }; |
| | | |
| | | private final PrivilegedExceptionAction<SaslClient> invokeAction = |
| | | new PrivilegedExceptionAction<SaslClient>() |
| | | { |
| | | public SaslClient run() throws ErrorResultException |
| | | { |
| | | final Map<String, String> props = new HashMap<String, String>(); |
| | | props.put(Sasl.QOP, "auth-conf,auth-int,auth"); |
| | | |
| | | try |
| | | { |
| | | final SaslClient saslClient = Sasl.createSaslClient( |
| | | new String[] { SASL_MECHANISM_NAME }, authorizationID, |
| | | SASL_DEFAULT_PROTOCOL, serverName, props, Client.this); |
| | | if (saslClient.hasInitialResponse()) |
| | | { |
| | | setNextSASLCredentials(saslClient.evaluateChallenge(new byte[0])); |
| | | } |
| | | else |
| | | { |
| | | setNextSASLCredentials((ByteString) null); |
| | | } |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | } |
| | | return saslClient; |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | private Client(final GSSAPISASLBindRequestImpl initialBindRequest, |
| | |
| | | initialBindRequest.getPassword(), initialBindRequest.getRealm(), |
| | | initialBindRequest.getKDCAddress()); |
| | | } |
| | | this.serverName = serverName; |
| | | |
| | | try |
| | | { |
| | | this.saslClient = Subject.doAs(subject, invokeAction); |
| | | this.saslClient = Subject.doAs(subject, |
| | | new PrivilegedExceptionAction<SaslClient>() |
| | | { |
| | | @Override |
| | | public SaslClient run() throws ErrorResultException |
| | | { |
| | | // Create property map containing all the parameters. |
| | | final Map<String, String> props = new HashMap<String, String>(); |
| | | |
| | | final List<String> qopValues = initialBindRequest.getQOPs(); |
| | | if (!qopValues.isEmpty()) |
| | | { |
| | | props.put(Sasl.QOP, joinCollection(qopValues, ",")); |
| | | } |
| | | |
| | | final Boolean serverAuth = initialBindRequest.isServerAuth(); |
| | | if (serverAuth != null) |
| | | { |
| | | props.put(Sasl.SERVER_AUTH, String.valueOf(serverAuth)); |
| | | } |
| | | |
| | | Integer size = initialBindRequest.getMaxReceiveBufferSize(); |
| | | if (size != null) |
| | | { |
| | | props.put(Sasl.MAX_BUFFER, String.valueOf(size)); |
| | | } |
| | | |
| | | size = initialBindRequest.getMaxSendBufferSize(); |
| | | if (size != null) |
| | | { |
| | | props.put("javax.security.sasl.sendmaxbuffer", |
| | | String.valueOf(size)); |
| | | } |
| | | |
| | | for (final Map.Entry<String, String> e : initialBindRequest |
| | | .getAdditionalAuthParams().entrySet()) |
| | | { |
| | | props.put(e.getKey(), e.getValue()); |
| | | } |
| | | |
| | | try |
| | | { |
| | | final SaslClient saslClient = Sasl.createSaslClient( |
| | | new String[] { SASL_MECHANISM_NAME }, authorizationID, |
| | | SASL_DEFAULT_PROTOCOL, serverName, props, Client.this); |
| | | if (saslClient.hasInitialResponse()) |
| | | { |
| | | setNextSASLCredentials(saslClient |
| | | .evaluateChallenge(new byte[0])); |
| | | } |
| | | else |
| | | { |
| | | setNextSASLCredentials((ByteString) null); |
| | | } |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | } |
| | | return saslClient; |
| | | } |
| | | }); |
| | | } |
| | | catch (final PrivilegedActionException e) |
| | | { |
| | |
| | | // This should not happen. Must be a bug. |
| | | final LocalizableMessage msg = ERR_SASL_CONTEXT_CREATE_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | } |
| | |
| | | // This should not happen. Must be a bug. |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_DECODING_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setDiagnosticMessage( |
| | | msg.toString()).setCause(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | // If null then authenticationID and password must be present. |
| | | private Subject subject = null; |
| | | |
| | | // Ignored if subject is non-null. |
| | | private String authenticationID = null; |
| | | private ByteString password = null; |
| | |
| | | // Optional authorization ID. |
| | | private String authorizationID = null; |
| | | |
| | | private final Map<String, String> additionalAuthParams = new LinkedHashMap<String, String>(); |
| | | private final List<String> qopValues = new LinkedList<String>(); |
| | | |
| | | // Don't use primitives for these so that we can distinguish between default |
| | | // settings (null) and values set by the caller. |
| | | private Boolean serverAuth = null; |
| | | private Integer maxReceiveBufferSize = null; |
| | | private Integer maxSendBufferSize = null; |
| | | |
| | | |
| | | |
| | | GSSAPISASLBindRequestImpl(final String authenticationID, |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest addAdditionalAuthParam(final String name, |
| | | final String value) throws UnsupportedOperationException, |
| | | NullPointerException |
| | | { |
| | | Validator.ensureNotNull(name, value); |
| | | additionalAuthParams.put(name, value); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest addQOP(final String... qopValues) |
| | | throws UnsupportedOperationException, NullPointerException |
| | | { |
| | | for (final String qopValue : qopValues) |
| | | { |
| | | this.qopValues.add(Validator.ensureNotNull(qopValue)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public BindClient createBindClient(final String serverName) |
| | | throws ErrorResultException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Map<String, String> getAdditionalAuthParams() |
| | | { |
| | | return additionalAuthParams; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getAuthenticationID() |
| | | { |
| | | return authenticationID; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getAuthorizationID() |
| | | { |
| | | return authorizationID; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getKDCAddress() |
| | | { |
| | | return kdcAddress; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int getMaxReceiveBufferSize() |
| | | { |
| | | return maxReceiveBufferSize == null ? 65536 : maxReceiveBufferSize; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int getMaxSendBufferSize() |
| | | { |
| | | return maxSendBufferSize == null ? 65536 : maxSendBufferSize; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ByteString getPassword() |
| | | { |
| | | return password; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public List<String> getQOPs() |
| | | { |
| | | return qopValues; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getRealm() |
| | | { |
| | | return realm; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getSASLMechanism() |
| | | { |
| | | return SASL_MECHANISM_NAME; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Subject getSubject() |
| | | { |
| | | return subject; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isServerAuth() |
| | | { |
| | | return serverAuth == null ? false : serverAuth; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setAuthenticationID(final String authenticationID) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setAuthorizationID(final String authorizationID) |
| | | { |
| | | this.authorizationID = authorizationID; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setKDCAddress(final String address) |
| | | { |
| | | this.kdcAddress = address; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setMaxReceiveBufferSize(final int size) |
| | | throws UnsupportedOperationException |
| | | { |
| | | maxReceiveBufferSize = size; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setMaxSendBufferSize(final int size) |
| | | throws UnsupportedOperationException |
| | | { |
| | | maxSendBufferSize = size; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setPassword(final ByteString password) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setPassword(final String password) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setRealm(final String realm) |
| | | { |
| | | this.realm = realm; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setServerAuth(final boolean serverAuth) |
| | | throws UnsupportedOperationException |
| | | { |
| | | this.serverAuth = serverAuth; |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public GSSAPISASLBindRequest setSubject(final Subject subject) |
| | | throws NullPointerException |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public QOPOption[] getQOP() { |
| | | String value = System.getProperty(Sasl.QOP); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return new QOPOption[]{QOPOption.AUTH}; |
| | | } |
| | | String[] values = value.split(","); |
| | | QOPOption[] options = new QOPOption[values.length]; |
| | | |
| | | for(int i = 0; i < values.length; i++) |
| | | { |
| | | String v = values[i].trim(); |
| | | if(v.equalsIgnoreCase("auth")) |
| | | { |
| | | options[i] = QOPOption.AUTH; |
| | | } |
| | | else if(v.equalsIgnoreCase("auth-int")) |
| | | { |
| | | options[i] = QOPOption.AUTH_INT; |
| | | } |
| | | else if(v.equalsIgnoreCase("auth-conf")) |
| | | { |
| | | options[i] = QOPOption.AUTH_CONF; |
| | | } |
| | | } |
| | | return options; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean getServerAuth() { |
| | | String value = System.getProperty(Sasl.SERVER_AUTH); |
| | | return !(value == null || value.length() == 0) && |
| | | value.equalsIgnoreCase("true"); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getMaxReceiveBufferSize() { |
| | | String value = System.getProperty(Sasl.MAX_BUFFER); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return 65536; |
| | | } |
| | | return Integer.parseInt(value); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getMaxSendBufferSize() { |
| | | String value = System.getProperty("javax.security.sasl.sendmaxbuffer"); |
| | | if(value == null || value.length() == 0) |
| | | { |
| | | return 65536; |
| | | } |
| | | return Integer.parseInt(value); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GSSAPISASLBindRequest setQOP(QOPOption... qopOptions) { |
| | | String values = null; |
| | | for(QOPOption option : qopOptions) |
| | | { |
| | | String value = null; |
| | | if(option == QOPOption.AUTH) |
| | | { |
| | | value = "auth"; |
| | | } |
| | | else if(option == QOPOption.AUTH_INT) |
| | | { |
| | | value = "auth-int"; |
| | | } |
| | | else if(option == QOPOption.AUTH_CONF) |
| | | { |
| | | value = "auth-conf"; |
| | | } |
| | | |
| | | if(value != null) |
| | | { |
| | | if(values == null) |
| | | { |
| | | values = value; |
| | | } |
| | | else |
| | | { |
| | | values += (", " + value); |
| | | } |
| | | } |
| | | } |
| | | |
| | | System.setProperty(Sasl.QOP, values); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GSSAPISASLBindRequest setServerAuth(boolean serverAuth) { |
| | | System.setProperty(Sasl.SERVER_AUTH, String.valueOf(serverAuth)); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GSSAPISASLBindRequest setMaxReceiveBufferSize(int maxBuffer) { |
| | | System.setProperty(Sasl.MAX_BUFFER, String.valueOf(maxBuffer)); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public GSSAPISASLBindRequest setMaxSendBufferSize(int maxBuffer) { |
| | | System.setProperty("javax.security.sasl.sendmaxbuffer", |
| | | String.valueOf(maxBuffer)); |
| | | return this; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | | |
| | | |
| | | |
| | | import org.opends.sdk.ByteString; |
| | | import org.opends.sdk.DecodeException; |
| | | import org.opends.sdk.DecodeOptions; |
| | | import org.opends.sdk.ResultCode; |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.GenericExtendedResult; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.opends.sdk.util.StaticUtils; |
| | | import com.sun.opends.sdk.util.Validator; |
| | |
| | | |
| | | |
| | | |
| | | private static final class GenericExtendedResultDecoder implements |
| | | ExtendedResultDecoder<GenericExtendedResult> |
| | | private static final class GenericExtendedResultDecoder extends |
| | | AbstractExtendedResultDecoder<GenericExtendedResult> |
| | | { |
| | | |
| | | public GenericExtendedResult adaptExtendedErrorResult( |
| | | public GenericExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| | |
| | | import org.opends.sdk.asn1.ASN1Reader; |
| | | import org.opends.sdk.asn1.ASN1Writer; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.PasswordModifyExtendedResult; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<PasswordModifyExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<PasswordModifyExtendedResult> |
| | | { |
| | | public PasswordModifyExtendedResult adaptExtendedErrorResult( |
| | | public PasswordModifyExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | /** |
| | | * The base class of all Requests provides methods for querying and manipulating |
| | | * the set of Controls included with a Request. |
| | | * <p> |
| | | * TODO: added complete description including sub-types. |
| | | */ |
| | | public interface Request |
| | | { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | /** |
| | | * Creates a new abandon request using the provided message ID. |
| | | * |
| | | * @param messageID |
| | | * The message ID of the request to be abandoned. |
| | | * @param requestID |
| | | * The request ID of the request to be abandoned. |
| | | * @return The new abandon request. |
| | | */ |
| | | public static AbandonRequest newAbandonRequest(final int messageID) |
| | | public static AbandonRequest newAbandonRequest(final int requestID) |
| | | { |
| | | return new AbandonRequestImpl(messageID); |
| | | return new AbandonRequestImpl(requestID); |
| | | } |
| | | |
| | | |
| | |
| | | /** |
| | | * Creates a new cancel extended request using the provided message ID. |
| | | * |
| | | * @param messageID |
| | | * The message ID of the request to be abandoned. |
| | | * @param requestID |
| | | * The request ID of the request to be abandoned. |
| | | * @return The new cancel extended request. |
| | | */ |
| | | public static CancelExtendedRequest newCancelExtendedRequest( |
| | | final int messageID) |
| | | final int requestID) |
| | | { |
| | | return new CancelExtendedRequestImpl(messageID); |
| | | return new CancelExtendedRequestImpl(requestID); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new modify request containing a list of modifications which can |
| | | * be used to transform {@code fromEntry} into entry {@code toEntry}. |
| | | * <p> |
| | | * The modify request is reversible: it will contain only modifications of |
| | | * type {@link ModificationType#ADD ADD} and {@link ModificationType#DELETE |
| | | * DELETE}. |
| | | * <p> |
| | | * Finally, the modify request will use the distinguished name taken from |
| | | * {@code fromEntry}. Moreover, this method will not check to see if both |
| | | * {@code fromEntry} and {@code toEntry} have the same distinguished name. |
| | | * <p> |
| | | * This method is equivalent to: |
| | | * |
| | | * <pre> |
| | | * ModifyRequest request = Entries.diffEntries(fromEntry, toEntry); |
| | | * </pre> |
| | | * |
| | | * @param fromEntry |
| | | * The source entry. |
| | | * @param toEntry |
| | | * The destination entry. |
| | | * @return A modify request containing a list of modifications which can be |
| | | * used to transform {@code fromEntry} into entry {@code toEntry}. |
| | | * @throws NullPointerException |
| | | * If {@code fromEntry} or {@code toEntry} were {@code null}. |
| | | * @see Entries#diffEntries(Entry, Entry) |
| | | */ |
| | | public static final ModifyRequest newModifyRequest(Entry fromEntry, |
| | | Entry toEntry) throws NullPointerException |
| | | { |
| | | return Entries.diffEntries(fromEntry, toEntry); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new modify request using the provided distinguished name decoded |
| | | * using the default schema. |
| | | * |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | public interface SearchRequest extends Request |
| | | { |
| | | /** |
| | | * Adds the provided attribute name to the list of attributes to be included |
| | | * with each entry that matches the search criteria. Attributes that are |
| | | * sub-types of listed attributes are implicitly included. |
| | | * Adds the provided attribute name(s) to the list of attributes to be |
| | | * included with each entry that matches the search criteria. Attributes that |
| | | * are sub-types of listed attributes are implicitly included. |
| | | * |
| | | * @param attributeDescription |
| | | * The name of the attribute to be included with each entry. |
| | | * @param attributeDescriptions |
| | | * The name(s) of the attribute to be included with each entry. |
| | | * @return This search request. |
| | | * @throws UnsupportedOperationException |
| | | * If this search request does not permit attribute names to be |
| | | * added. |
| | | * @throws NullPointerException |
| | | * If {@code attributeDescription} was {@code null}. |
| | | * If {@code attributeDescriptions} was {@code null}. |
| | | */ |
| | | SearchRequest addAttribute(String attributeDescription) |
| | | SearchRequest addAttribute(String... attributeDescriptions) |
| | | throws UnsupportedOperationException, NullPointerException; |
| | | |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.requests; |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public SearchRequest addAttribute(final String attributeDescription) |
| | | public SearchRequest addAttribute(final String... attributeDescriptions) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(attributeDescription); |
| | | attributes.add(attributeDescription); |
| | | for (String attributeDescription : attributeDescriptions) |
| | | { |
| | | attributes.add(Validator.ensureNotNull(attributeDescription)); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | |
| | | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | import org.opends.sdk.ByteString; |
| | | import org.opends.sdk.DecodeException; |
| | | import org.opends.sdk.DecodeOptions; |
| | | import org.opends.sdk.ResultCode; |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.GenericExtendedResult; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.opends.sdk.util.Validator; |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<ExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<ExtendedResult> |
| | | { |
| | | public GenericExtendedResult adaptExtendedErrorResult( |
| | | public GenericExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| | |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.controls.Control; |
| | | import org.opends.sdk.responses.ExtendedResult; |
| | | import org.opends.sdk.responses.ExtendedResultDecoder; |
| | | import org.opends.sdk.responses.Responses; |
| | | import org.opends.sdk.responses.WhoAmIExtendedResult; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | |
| | | |
| | | private static final class ResultDecoder implements |
| | | ExtendedResultDecoder<WhoAmIExtendedResult> |
| | | private static final class ResultDecoder extends |
| | | AbstractExtendedResultDecoder<WhoAmIExtendedResult> |
| | | { |
| | | public WhoAmIExtendedResult adaptExtendedErrorResult( |
| | | public WhoAmIExtendedResult newExtendedErrorResult( |
| | | final ResultCode resultCode, final String matchedDN, |
| | | final String diagnosticMessage) |
| | | { |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.responses; |
| | | |
| | | |
| | | |
| | | import org.opends.sdk.*; |
| | | import org.opends.sdk.requests.ExtendedRequest; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class provides a skeletal implementation of the |
| | | * {@code ExtendedResultDecoder} interface, to minimize the effort required to |
| | | * implement this interface. |
| | | * |
| | | * @param <S> |
| | | * The type of result. |
| | | */ |
| | | public abstract class AbstractExtendedResultDecoder<S extends ExtendedResult> |
| | | implements ExtendedResultDecoder<S> |
| | | { |
| | | /** |
| | | * Creates a new abstract extended result decoder. |
| | | */ |
| | | protected AbstractExtendedResultDecoder() |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public S adaptDecodeException(final DecodeException exception) |
| | | throws NullPointerException |
| | | { |
| | | final S adaptedResult = newExtendedErrorResult(ResultCode.PROTOCOL_ERROR, |
| | | "", exception.getMessage()); |
| | | adaptedResult.setCause(exception.getCause()); |
| | | return adaptedResult; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> ResultHandler<S> adaptExtendedResultHandler( |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, final DecodeOptions options) |
| | | { |
| | | return new ResultHandler<S>() |
| | | { |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | final Result result = error.getResult(); |
| | | final R adaptedResult = request.getResultDecoder() |
| | | .newExtendedErrorResult(result.getResultCode(), |
| | | result.getMatchedDN(), result.getDiagnosticMessage()); |
| | | adaptedResult.setCause(result.getCause()); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .wrap(adaptedResult)); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public void handleResult(final S result) |
| | | { |
| | | try |
| | | { |
| | | final R adaptedResult = request.getResultDecoder() |
| | | .decodeExtendedResult(result, options); |
| | | resultHandler.handleResult(adaptedResult); |
| | | } |
| | | catch (final DecodeException e) |
| | | { |
| | | final R adaptedResult = request.getResultDecoder() |
| | | .adaptDecodeException(e); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .wrap(adaptedResult)); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public abstract S decodeExtendedResult(ExtendedResult result, |
| | | DecodeOptions options) throws DecodeException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public abstract S newExtendedErrorResult(ResultCode resultCode, |
| | | String matchedDN, String diagnosticMessage) throws NullPointerException; |
| | | |
| | | } |
| | |
| | | import org.opends.sdk.DecodeException; |
| | | import org.opends.sdk.DecodeOptions; |
| | | import org.opends.sdk.ResultCode; |
| | | import org.opends.sdk.ResultHandler; |
| | | import org.opends.sdk.requests.ExtendedRequest; |
| | | |
| | | |
| | | |
| | |
| | | */ |
| | | public interface ExtendedResultDecoder<S extends ExtendedResult> |
| | | { |
| | | |
| | | /** |
| | | * Adapts the provided error result parameters to an extended operation |
| | | * result. This method is called when a generic failure occurs, such as a |
| | | * connection failure, and the error result needs to be converted to a {@code |
| | | * Result} of type {@code S}. |
| | | * Creates a new extended operation error result using the provided decoding |
| | | * exception. This method should be used to adapt {@code DecodeException} |
| | | * encountered while decoding an extended request or result. The returned |
| | | * error result will have the result code {@link ResultCode#PROTOCOL_ERROR}. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @param matchedDN |
| | | * The matched DN, which may be empty if none was provided. |
| | | * @param diagnosticMessage |
| | | * The diagnostic message, which may be empty if none was provided. |
| | | * @return The decoded extended operation error result. |
| | | * @param exception |
| | | * The decoding exception to be adapted. |
| | | * @return An extended operation error result representing the decoding |
| | | * exception. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode}, {@code matchedDN}, or {@code |
| | | * diagnosticMessage} were {@code null}. |
| | | * If {@code exception} was {@code null}. |
| | | */ |
| | | S adaptExtendedErrorResult(ResultCode resultCode, String matchedDN, |
| | | String diagnosticMessage) throws NullPointerException; |
| | | S adaptDecodeException(DecodeException exception) throws NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adapts the provided extended result handler into a result handler which is |
| | | * compatible with this extended result decoder. Extended results handled by |
| | | * the returned handler will be automatically converted and passed to the |
| | | * provided result handler. Decoding errors encountered while decoding the |
| | | * extended result will be converted into protocol errors. |
| | | * |
| | | * @param <R> |
| | | * The type of result handler to be adapted. |
| | | * @param request |
| | | * The extended request whose result handler is to be adapted. |
| | | * @param resultHandler |
| | | * The extended result handler which is to be adapted. |
| | | * @param options |
| | | * The set of decode options which should be used when decoding the |
| | | * extended operation result. |
| | | * @return A result handler which is compatible with this extended result |
| | | * decoder. |
| | | */ |
| | | <R extends ExtendedResult> ResultHandler<S> adaptExtendedResultHandler( |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, DecodeOptions options); |
| | | |
| | | |
| | | |
| | |
| | | S decodeExtendedResult(ExtendedResult result, DecodeOptions options) |
| | | throws DecodeException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new extended error result using the provided result code, matched |
| | | * DN, and diagnostic message. This method is called when a generic failure |
| | | * occurs, such as a connection failure, and the error result needs to be |
| | | * converted to a {@code Result} of type {@code S}. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @param matchedDN |
| | | * The matched DN, which may be empty if none was provided. |
| | | * @param diagnosticMessage |
| | | * The diagnostic message, which may be empty if none was provided. |
| | | * @return The decoded extended operation error result. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode}, {@code matchedDN}, or |
| | | * {@code diagnosticMessage} were {@code null}. |
| | | */ |
| | | S newExtendedErrorResult(ResultCode resultCode, String matchedDN, |
| | | String diagnosticMessage) throws NullPointerException; |
| | | |
| | | } |
| New file |
| | |
| | | <html> |
| | | <body> |
| | | The OpenDS SDK for Java provides a high performance easy to use |
| | | library of classes and interfaces for accessing and implementing |
| | | LDAP Directory Services as defined in <a |
| | | href="http://tools.ietf.org/html/rfc4510">RFC 4510</a>. |
| | | <br> |
| | | <h1>Getting started</h1> |
| | | The following example shows how the OpenDS SDK may be used to |
| | | connect to a Directory Server, authenticate, and then perform a |
| | | search. The search results are output as LDIF to the standard |
| | | output: |
| | | <br> |
| | | <table bgcolor="#cccccc" border="0" cellpadding="2" cellspacing="2" |
| | | width="100%"> |
| | | <tbody> |
| | | <tr> |
| | | <pre> // Create an LDIF writer which will write the search results to stdout. |
| | | final LDIFEntryWriter writer = new LDIFEntryWriter(System.out); |
| | | Connection connection = null; |
| | | try |
| | | { |
| | | // Connect and bind to the server. |
| | | final LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 1389); |
| | | |
| | | connection = factory.getConnection(); |
| | | connection.bind(userName, password); |
| | | |
| | | // Read the entries and output them as LDIF. |
| | | final ConnectionEntryReader reader = connection.search(baseDN, scope, filter, attributes); |
| | | while (reader.hasNext()) |
| | | { |
| | | if (!reader.isReference()) |
| | | { |
| | | // Got an entry. |
| | | final SearchResultEntry entry = reader.readEntry(); |
| | | writer.writeComment("Search result entry: " + entry.getName().toString()); |
| | | writer.writeEntry(entry); |
| | | } |
| | | else |
| | | { |
| | | // Got a continuation reference. |
| | | final SearchResultReference ref = reader.readReference(); |
| | | writer.writeComment("Search result reference: " + ref.getURIs().toString()); |
| | | } |
| | | } |
| | | writer.flush(); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Handle exceptions... |
| | | System.err.println(e.getMessage()); |
| | | } |
| | | finally |
| | | { |
| | | if (connection != null) |
| | | { |
| | | connection.close(); |
| | | } |
| | | }</pre> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | <br> |
| | | Additional examples can be found in the file examples.zip which is |
| | | included with this SDK. |
| | | <br> |
| | | <h1>Creating connections</h1> |
| | | The following classes can be used to create and manage connections to |
| | | LDAP Directory Servers: |
| | | <ul> |
| | | <li>{@link org.opends.sdk.LDAPConnectionFactory}</li> |
| | | <li>{@link org.opends.sdk.Connection}</li> |
| | | <li>{@link org.opends.sdk.Connections}</li> |
| | | </ul> |
| | | <br> |
| | | <h1>Creating requests</h1> |
| | | The following classes can be used to create LDAP requests: |
| | | <ul> |
| | | <li>{@link org.opends.sdk.requests.Requests}</li> |
| | | <li>{@link org.opends.sdk.requests.Request}</li> |
| | | </ul> |
| | | <br> |
| | | <h1>Using controls</h1> |
| | | Common LDAP control implementations can be found in |
| | | {@link org.opends.sdk.controls}. |
| | | <br> |
| | | <br> |
| | | <h1>Core types</h1> |
| | | The following classes and interfaces represent core types: |
| | | <ul> |
| | | <li>{@link org.opends.sdk.AttributeDescription}</li> |
| | | <li>{@link org.opends.sdk.Attribute}</li> |
| | | <li>{@link org.opends.sdk.DN}</li> |
| | | <li>{@link org.opends.sdk.Entry}</li> |
| | | <li>{@link org.opends.sdk.Filter}</li> |
| | | </ul> |
| | | <br> |
| | | @see <a href="http://tools.ietf.org/html/rfc4511">RFC 4511 - Lightweight |
| | | Directory Access Protocol (LDAP): The Protocol </a> |
| | | @see org.opends.sdk |
| | | </body> |
| | | </html> |
| | |
| | | import org.opends.sdk.asn1.ASN1Reader; |
| | | import org.opends.sdk.asn1.ASN1ReaderTestCase; |
| | | |
| | | import com.sun.grizzly.memory.ByteBufferWrapper; |
| | | import com.sun.grizzly.memory.DefaultMemoryManager; |
| | | import org.glassfish.grizzly.memory.ByteBufferWrapper; |
| | | import org.glassfish.grizzly.memory.DefaultMemoryManager; |
| | | |
| | | |
| | | |
| | |
| | | import org.opends.sdk.asn1.ASN1Writer; |
| | | import org.opends.sdk.asn1.ASN1WriterTestCase; |
| | | |
| | | import com.sun.grizzly.Buffer; |
| | | import com.sun.grizzly.memory.ByteBufferWrapper; |
| | | import org.glassfish.grizzly.Buffer; |
| | | import org.glassfish.grizzly.memory.ByteBufferWrapper; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | import org.testng.annotations.Test; |
| | | |
| | | import com.sun.grizzly.TransportFactory; |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.TransportFactory; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | |
| | | |
| | | |
| | |
| | | import static org.testng.Assert.assertNotNull; |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | import java.net.InetSocketAddress; |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.CountDownLatch; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import org.opends.sdk.requests.DigestMD5SASLBindRequest; |
| | | import org.opends.sdk.requests.Requests; |
| | | import org.opends.sdk.requests.SearchRequest; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.Test; |
| | | import org.testng.annotations.DataProvider; |
| | |
| | | import javax.net.ssl.SSLContext; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the connectionfactory classes. |
| | | */ |
| | |
| | | // latch. |
| | | private final CountDownLatch latch; |
| | | // invalid flag. |
| | | private volatile boolean invalid; |
| | | private volatile ErrorResultException error; |
| | | |
| | | |
| | | |
| | |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | // came here. |
| | | invalid = true; |
| | | this.error = error; |
| | | latch.countDown(); |
| | | } |
| | | |
| | |
| | | TestCaseUtils.startServer(); |
| | | } |
| | | |
| | | |
| | | |
| | | @DataProvider(name = "connectionFactories") |
| | | public Object[][] getModifyDNRequests() throws Exception |
| | | public Object[][] getConnectyionFactories() throws Exception |
| | | { |
| | | Object[][] factories = new Object[7][1]; |
| | | Object[][] factories = new Object[21][1]; |
| | | |
| | | // HeartBeatConnectionFactory |
| | | // Use custom search request. |
| | | SearchRequest request = Requests.newSearchRequest( |
| | | "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT, "objectclass=*", |
| | | "cn"); |
| | | "uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT, |
| | | "objectclass=*", "cn"); |
| | | |
| | | factories[0][0] = new HeartBeatConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | 1000, TimeUnit.MILLISECONDS, request); |
| | | factories[0][0] = new HeartBeatConnectionFactory(new LDAPConnectionFactory( |
| | | "localhost", TestCaseUtils.getLdapPort()), 1000, TimeUnit.MILLISECONDS, |
| | | request); |
| | | |
| | | // InternalConnectionFactory |
| | | factories[1][0] = Connections |
| | | .newInternalConnectionFactory(LDAPServer.getInstance(), null); |
| | | factories[1][0] = Connections.newInternalConnectionFactory( |
| | | LDAPServer.getInstance(), null); |
| | | |
| | | // AuthenticatedConnectionFactory |
| | | factories[2][0] = new AuthenticatedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | Requests.newSimpleBindRequest("", "")); |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | Requests.newSimpleBindRequest("", "")); |
| | | |
| | | // AuthenticatedConnectionFactory with multi-stage SASL |
| | | factories[3][0] = new AuthenticatedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | Requests.newCRAMMD5SASLBindRequest("id:user", |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | Requests.newCRAMMD5SASLBindRequest("id:user", |
| | | ByteString.valueOf("password"))); |
| | | |
| | | // LDAPConnectionFactory with default options |
| | | factories[4][0] = new LDAPConnectionFactory( |
| | | "localhost", TestCaseUtils.getLdapPort()); |
| | | factories[4][0] = new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.getLdapPort()); |
| | | |
| | | // LDAPConnectionFactory with startTLS |
| | | SSLContext sslContext = new SSLContextBuilder(). |
| | | setTrustManager(TrustManagers.trustAll()).getSSLContext(); |
| | | LDAPOptions options = new LDAPOptions().setSSLContext(sslContext). |
| | | setUseStartTLS(true).setEnabledCipherSuites( |
| | | new String[]{"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", |
| | | "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", |
| | | "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", |
| | | "SSL_DH_anon_WITH_DES_CBC_SHA", |
| | | "SSL_DH_anon_WITH_RC4_128_MD5", |
| | | "TLS_DH_anon_WITH_AES_128_CBC_SHA", |
| | | "TLS_DH_anon_WITH_AES_256_CBC_SHA"}); |
| | | factories[5][0] = new LDAPConnectionFactory( |
| | | "localhost", TestCaseUtils.getLdapPort(), options); |
| | | SSLContext sslContext = new SSLContextBuilder().setTrustManager( |
| | | TrustManagers.trustAll()).getSSLContext(); |
| | | LDAPOptions options = new LDAPOptions() |
| | | .setSSLContext(sslContext) |
| | | .setUseStartTLS(true) |
| | | .setEnabledCipherSuites( |
| | | new String[] { "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", |
| | | "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", |
| | | "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", |
| | | "SSL_DH_anon_WITH_DES_CBC_SHA", "SSL_DH_anon_WITH_RC4_128_MD5", |
| | | "TLS_DH_anon_WITH_AES_128_CBC_SHA", |
| | | "TLS_DH_anon_WITH_AES_256_CBC_SHA" }); |
| | | factories[5][0] = new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.getLdapPort(), options); |
| | | |
| | | // startTLS + SASL confidentiality |
| | | // Use IP address here so that DIGEST-MD5 host verification works if local |
| | | // host name is not localhost (e.g. on some machines it might be |
| | | // localhost.localdomain). |
| | | factories[6][0] = new AuthenticatedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort(), |
| | | options), Requests.newDigestMD5SASLBindRequest("id:user", |
| | | ByteString.valueOf("password")).setQOP( |
| | | DigestMD5SASLBindRequest.QOPOption.AUTH_CONF).setCipher( |
| | | DigestMD5SASLBindRequest.CipherOption.TRIPLE_DES_RC4)); |
| | | new LDAPConnectionFactory(new InetSocketAddress("127.0.0.1", |
| | | TestCaseUtils.getLdapPort()), options), Requests |
| | | .newDigestMD5SASLBindRequest("id:user", |
| | | ByteString.valueOf("password")) |
| | | .addQOP(DigestMD5SASLBindRequest.QOP_AUTH_CONF) |
| | | .setCipher(DigestMD5SASLBindRequest.CIPHER_LOW)); |
| | | |
| | | // Connection pool and load balancing tests. |
| | | ConnectionFactory offlineServer1 = Connections.newNamedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.findFreePort()), |
| | | "offline1"); |
| | | ConnectionFactory offlineServer2 = Connections.newNamedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.findFreePort()), |
| | | "offline2"); |
| | | ConnectionFactory onlineServer = Connections.newNamedConnectionFactory( |
| | | new LDAPConnectionFactory("localhost", TestCaseUtils.getLdapPort()), |
| | | "online"); |
| | | |
| | | // Connection pools. |
| | | factories[7][0] = Connections.newConnectionPool(onlineServer, 10); |
| | | |
| | | // Round robin. |
| | | factories[8][0] = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | onlineServer, offlineServer1))); |
| | | factories[9][0] = factories[8][0]; |
| | | factories[10][0] = factories[8][0]; |
| | | factories[11][0] = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | offlineServer1, onlineServer))); |
| | | factories[12][0] = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | offlineServer1, offlineServer2, onlineServer))); |
| | | factories[13][0] = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | Connections.newConnectionPool(offlineServer1, 10), |
| | | Connections.newConnectionPool(onlineServer, 10)))); |
| | | |
| | | // Fail-over. |
| | | factories[14][0] = Connections |
| | | .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList( |
| | | onlineServer, offlineServer1))); |
| | | factories[15][0] = factories[14][0]; |
| | | factories[16][0] = factories[14][0]; |
| | | factories[17][0] = Connections |
| | | .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList( |
| | | offlineServer1, onlineServer))); |
| | | factories[18][0] = Connections |
| | | .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList( |
| | | offlineServer1, offlineServer2, onlineServer))); |
| | | factories[19][0] = Connections |
| | | .newLoadBalancer(new FailoverLoadBalancingAlgorithm(Arrays.asList( |
| | | Connections.newConnectionPool(offlineServer1, 10), |
| | | Connections.newConnectionPool(onlineServer, 10)))); |
| | | |
| | | factories[20][0] = Connections.newConnectionPool(onlineServer, 10); |
| | | |
| | | return factories; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the async connection in the blocking mode. This is not fully async as |
| | | * it blocks on the future. |
| | |
| | | public void testBlockingFutureNoHandler(ConnectionFactory factory) |
| | | throws Exception |
| | | { |
| | | final FutureResult<AsynchronousConnection> future = |
| | | factory.getAsynchronousConnection(null); |
| | | final FutureResult<AsynchronousConnection> future = factory |
| | | .getAsynchronousConnection(null); |
| | | final AsynchronousConnection con = future.get(); |
| | | // quickly check if iit is a valid connection. |
| | | // quickly check if it is a valid connection. |
| | | // Don't use a result handler. |
| | | assertNotNull(con.readRootDSE(null).get()); |
| | | con.close(); |
| | |
| | | // Use the handler to get the result asynchronously. |
| | | final CountDownLatch latch = new CountDownLatch(1); |
| | | final MyResultHandler handler = new MyResultHandler(latch); |
| | | final FutureResult<AsynchronousConnection> future = |
| | | factory.getAsynchronousConnection(handler); |
| | | final FutureResult<AsynchronousConnection> future = factory |
| | | .getAsynchronousConnection(handler); |
| | | // Since we don't have anything to do, we would rather |
| | | // be notified by the latch when the other thread calls our handler. |
| | | latch.await(); // should do a timed wait rather? |
| | | if (handler.invalid) |
| | | if (handler.error != null) |
| | | { |
| | | // There was an error. |
| | | throw new Exception(); |
| | | throw handler.error; |
| | | } |
| | | } |
| | | |
| | |
| | | { "cn=aaaa,dc=com", "cn=AAA,dc=com", 1 }, |
| | | { "cn=aaab,dc=com", "cn=aaaa,dc=com", 1 }, |
| | | { "cn=aaaa,dc=com", "cn=aaab,dc=com", -1 }, |
| | | { "dc=aaa,dc=aaa", "dc=bbb", -1 }, { "dc=bbb,dc=aaa", "dc=bbb", -1 }, |
| | | { "dc=ccc,dc=aaa", "dc=bbb", -1 }, { "dc=aaa,dc=bbb", "dc=bbb", 1 }, |
| | | { "dc=bbb,dc=bbb", "dc=bbb", 1 }, { "dc=ccc,dc=bbb", "dc=bbb", 1 }, |
| | | { "dc=aaa,dc=ccc", "dc=bbb", 1 }, { "dc=bbb,dc=ccc", "dc=bbb", 1 }, |
| | | { "dc=ccc,dc=ccc", "dc=bbb", 1 }, { "", "dc=bbb", -1 }, |
| | | { "dc=aaa,dc=aaa", "dc=bbb", -1 }, |
| | | { "dc=bbb,dc=aaa", "dc=bbb", -1 }, |
| | | { "dc=ccc,dc=aaa", "dc=bbb", -1 }, |
| | | { "dc=aaa,dc=bbb", "dc=bbb", 1 }, |
| | | { "dc=bbb,dc=bbb", "dc=bbb", 1 }, |
| | | { "dc=ccc,dc=bbb", "dc=bbb", 1 }, |
| | | { "dc=aaa,dc=ccc", "dc=bbb", 1 }, |
| | | { "dc=bbb,dc=ccc", "dc=bbb", 1 }, |
| | | { "dc=ccc,dc=ccc", "dc=bbb", 1 }, |
| | | { "", "dc=bbb", -1 }, |
| | | { "dc=bbb", "", 1 } }; |
| | | } |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import java.util.Iterator; |
| | | |
| | | import org.opends.sdk.requests.ModifyRequest; |
| | | import org.opends.sdk.requests.Requests; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Test {@code Entries}. |
| | | */ |
| | | public final class EntriesTestCase extends SdkTestCase |
| | | { |
| | | /** |
| | | * Creates test data for {@link #testDiffEntries}. |
| | | * |
| | | * @return The test data. |
| | | */ |
| | | @DataProvider(name = "createTestDiffEntriesData") |
| | | public Object[][] createTestDiffEntriesData() |
| | | { |
| | | // @formatter:off |
| | | Entry empty = new LinkedHashMapEntry( |
| | | "dn: cn=test", |
| | | "objectClass: top", |
| | | "objectClass: test" |
| | | ); |
| | | |
| | | Entry from = new LinkedHashMapEntry( |
| | | "dn: cn=test", |
| | | "objectClass: top", |
| | | "objectClass: test", |
| | | "fromOnly: fromOnlyValue", |
| | | "bothSame: one", |
| | | "bothSame: two", |
| | | "bothSame: three", |
| | | "bothDifferentDeletes: common", |
| | | "bothDifferentDeletes: fromOnly1", |
| | | "bothDifferentDeletes: fromOnly2", |
| | | "bothDifferentAdds: common", |
| | | "bothDifferentAddsAndDeletes: common", |
| | | "bothDifferentAddsAndDeletes: fromOnly", |
| | | "bothDifferentReplace: fromOnly1", |
| | | "bothDifferentReplace: fromOnly2" |
| | | ); |
| | | |
| | | Entry to = new LinkedHashMapEntry( |
| | | "dn: cn=test", |
| | | "objectClass: top", |
| | | "objectClass: test", |
| | | "toOnly: toOnlyValue", |
| | | "bothSame: one", |
| | | "bothSame: two", |
| | | "bothSame: three", |
| | | "bothDifferentDeletes: common", |
| | | "bothDifferentAdds: common", |
| | | "bothDifferentAdds: toOnly1", |
| | | "bothDifferentAdds: toOnly2", |
| | | "bothDifferentAddsAndDeletes: common", |
| | | "bothDifferentAddsAndDeletes: toOnly", |
| | | "bothDifferentReplace: toOnly1", |
| | | "bothDifferentReplace: toOnly2" |
| | | ); |
| | | |
| | | ModifyRequest diffFromEmpty = Requests.newModifyRequest( |
| | | "dn: cn=test", |
| | | "changetype: modify", |
| | | "delete: bothDifferentAdds", |
| | | "bothDifferentAdds: common", |
| | | "-", |
| | | "delete: bothDifferentAddsAndDeletes", |
| | | "bothDifferentAddsAndDeletes: common", |
| | | "bothDifferentAddsAndDeletes: fromOnly", |
| | | "-", |
| | | "delete: bothDifferentDeletes", |
| | | "bothDifferentDeletes: common", |
| | | "bothDifferentDeletes: fromOnly1", |
| | | "bothDifferentDeletes: fromOnly2", |
| | | "-", |
| | | "delete: bothDifferentReplace", |
| | | "bothDifferentReplace: fromOnly1", |
| | | "bothDifferentReplace: fromOnly2", |
| | | "-", |
| | | "delete: bothSame", |
| | | "bothSame: one", |
| | | "bothSame: two", |
| | | "bothSame: three", |
| | | "-", |
| | | "delete: fromOnly", |
| | | "fromOnly: fromOnlyValue" |
| | | ); |
| | | |
| | | ModifyRequest diffEmptyTo = Requests.newModifyRequest( |
| | | "dn: cn=test", |
| | | "changetype: modify", |
| | | "add: bothDifferentAdds", |
| | | "bothDifferentAdds: common", |
| | | "bothDifferentAdds: toOnly1", |
| | | "bothDifferentAdds: toOnly2", |
| | | "-", |
| | | "add: bothDifferentAddsAndDeletes", |
| | | "bothDifferentAddsAndDeletes: common", |
| | | "bothDifferentAddsAndDeletes: toOnly", |
| | | "-", |
| | | "add: bothDifferentDeletes", |
| | | "bothDifferentDeletes: common", |
| | | "-", |
| | | "add: bothDifferentReplace", |
| | | "bothDifferentReplace: toOnly1", |
| | | "bothDifferentReplace: toOnly2", |
| | | "-", |
| | | "add: bothSame", |
| | | "bothSame: one", |
| | | "bothSame: two", |
| | | "bothSame: three", |
| | | "-", |
| | | "add: toOnly", |
| | | "toOnly: toOnlyValue" |
| | | ); |
| | | |
| | | ModifyRequest diffFromTo = Requests.newModifyRequest( |
| | | "dn: cn=test", |
| | | "changetype: modify", |
| | | "add: bothDifferentAdds", |
| | | "bothDifferentAdds: toOnly1", |
| | | "bothDifferentAdds: toOnly2", |
| | | "-", |
| | | "add: bothDifferentAddsAndDeletes", |
| | | "bothDifferentAddsAndDeletes: toOnly", |
| | | "-", |
| | | "delete: bothDifferentAddsAndDeletes", |
| | | "bothDifferentAddsAndDeletes: fromOnly", |
| | | "-", |
| | | "delete: bothDifferentDeletes", |
| | | "bothDifferentDeletes: fromOnly1", |
| | | "bothDifferentDeletes: fromOnly2", |
| | | "-", |
| | | "add: bothDifferentReplace", |
| | | "bothDifferentReplace: toOnly1", |
| | | "bothDifferentReplace: toOnly2", |
| | | "-", |
| | | "delete: bothDifferentReplace", |
| | | "bothDifferentReplace: fromOnly1", |
| | | "bothDifferentReplace: fromOnly2", |
| | | "-", |
| | | "delete: fromOnly", |
| | | "fromOnly: fromOnlyValue", |
| | | "-", |
| | | "add: toOnly", |
| | | "toOnly: toOnlyValue" |
| | | ); |
| | | |
| | | // From, to, diff. |
| | | return new Object[][] |
| | | { |
| | | { from, empty, diffFromEmpty }, |
| | | { empty, to, diffEmptyTo }, |
| | | { from, to, diffFromTo } |
| | | }; |
| | | |
| | | // @formatter:on |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests {@link Entries#diffEntries(Entry, Entry)}. |
| | | * |
| | | * @param from |
| | | * Source entry. |
| | | * @param to |
| | | * Destination entry. |
| | | * @param expected |
| | | * Expected modifications. |
| | | */ |
| | | @Test(dataProvider = "createTestDiffEntriesData") |
| | | public void testDiffEntries(final Entry from, final Entry to, |
| | | final ModifyRequest expected) |
| | | { |
| | | ModifyRequest actual = Entries.diffEntries(from, to); |
| | | |
| | | Assert.assertEquals(from.getName(), actual.getName()); |
| | | Assert.assertEquals(actual.getModifications().size(), expected |
| | | .getModifications().size()); |
| | | Iterator<Modification> i1 = actual.getModifications().iterator(); |
| | | Iterator<Modification> i2 = expected.getModifications().iterator(); |
| | | while (i1.hasNext()) |
| | | { |
| | | Modification m1 = i1.next(); |
| | | Modification m2 = i2.next(); |
| | | |
| | | Assert.assertEquals(m1.getModificationType(), m2.getModificationType()); |
| | | Assert.assertEquals(m1.getAttribute(), m2.getAttribute()); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Test {@code BasicAttribute}. |
| | | * Test {@code Entry}. |
| | | */ |
| | | public final class EntryTestCase extends SdkTestCase |
| | | { |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * 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/opends/resource/legal-notices/OpenDS.LICENSE. 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 |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | | |
| | | |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.CountDownLatch; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.Test; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the LDAPListener class. |
| | | */ |
| | | public class LDAPListenerTestCase extends SdkTestCase |
| | | { |
| | | |
| | | private static class MockServerConnection implements |
| | | ServerConnection<Integer> |
| | | { |
| | | volatile LDAPClientContext context = null; |
| | | volatile boolean isConnected = false; |
| | | final CountDownLatch isClosed = new CountDownLatch(1); |
| | | |
| | | |
| | | |
| | | MockServerConnection() |
| | | { |
| | | // Do nothing. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer requestContext, |
| | | final AbandonRequest request) throws UnsupportedOperationException |
| | | { |
| | | // Do nothing. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final Integer requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final Integer requestContext, final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final Integer requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler |
| | | .handleResult(Responses.newCompareResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed(final Integer requestContext, |
| | | final UnbindRequest request) |
| | | { |
| | | isClosed.countDown(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected(final ResultCode resultCode, |
| | | final String message) |
| | | { |
| | | // Do nothing. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | // Do nothing. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final Integer requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final Integer requestContext, final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException.wrap(request |
| | | .getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, "", |
| | | "Extended operation " + request.getOID() + " not supported"))); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final Integer requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final Integer requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final Integer requestContext, |
| | | final SearchRequest request, final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS)); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private static class MockServerConnectionFactory implements |
| | | ServerConnectionFactory<LDAPClientContext, Integer> |
| | | { |
| | | |
| | | private final MockServerConnection serverConnection; |
| | | |
| | | |
| | | |
| | | private MockServerConnectionFactory( |
| | | final MockServerConnection serverConnection) |
| | | { |
| | | this.serverConnection = serverConnection; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | serverConnection.context = clientContext; |
| | | serverConnection.isConnected = true; |
| | | return serverConnection; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests basic LDAP listener functionality. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @Test |
| | | public void testLDAPListenerBasic() throws Exception |
| | | { |
| | | final MockServerConnection serverConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory serverConnectionFactory = new MockServerConnectionFactory( |
| | | serverConnection); |
| | | final LDAPListener listener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), serverConnectionFactory); |
| | | try |
| | | { |
| | | // Connect and close. |
| | | new LDAPConnectionFactory(listener.getSocketAddress()).getConnection() |
| | | .close(); |
| | | |
| | | Assert.assertTrue(serverConnection.isConnected); |
| | | Assert.assertTrue(serverConnection.isClosed.await(10, TimeUnit.SECONDS)); |
| | | } |
| | | finally |
| | | { |
| | | listener.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests LDAP listener which attempts to open a connection to a remote offline |
| | | * server at the point when the listener accepts the client connection. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @Test(enabled = false) |
| | | public void testLDAPListenerLoadBalanceDuringHandleAccept() throws Exception |
| | | { |
| | | // Online server listener. |
| | | final int onlineServerPort = TestCaseUtils.findFreePort(); |
| | | final MockServerConnection onlineServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory( |
| | | onlineServerConnection); |
| | | final LDAPListener onlineServerListener = new LDAPListener("localhost", |
| | | onlineServerPort, onlineServerConnectionFactory); |
| | | |
| | | try |
| | | { |
| | | // Connection pool and load balancing tests. |
| | | final ConnectionFactory offlineServer1 = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.findFreePort()), "offline1"); |
| | | final ConnectionFactory offlineServer2 = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.findFreePort()), "offline2"); |
| | | final ConnectionFactory onlineServer = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | onlineServerPort), "online"); |
| | | |
| | | // Round robin. |
| | | final ConnectionFactory loadBalancer = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | Connections.newConnectionPool(offlineServer1, 10), |
| | | Connections.newConnectionPool(offlineServer2, 10), |
| | | Connections.newConnectionPool(onlineServer, 10)))); |
| | | |
| | | final MockServerConnection proxyServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory( |
| | | proxyServerConnection) |
| | | { |
| | | |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | // Get connection from load balancer, this should fail over twice |
| | | // before getting connection to online server. |
| | | try |
| | | { |
| | | loadBalancer.getConnection().close(); |
| | | } |
| | | catch (final InterruptedException e) |
| | | { |
| | | // Unexpected. |
| | | throw ErrorResultException.newErrorResult(ResultCode.OTHER, |
| | | "Unexpected exception when connecting to online server", e); |
| | | } |
| | | return super.handleAccept(clientContext); |
| | | } |
| | | |
| | | }; |
| | | |
| | | final LDAPListener proxyListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), proxyServerConnectionFactory); |
| | | try |
| | | { |
| | | // Connect and close. |
| | | new LDAPConnectionFactory(proxyListener.getSocketAddress()) |
| | | .getConnection().close(); |
| | | |
| | | // Wait for connect/close to complete. |
| | | proxyServerConnection.isClosed.await(); |
| | | |
| | | Assert.assertTrue(proxyServerConnection.isConnected); |
| | | Assert.assertTrue(onlineServerConnection.isConnected); |
| | | } |
| | | finally |
| | | { |
| | | proxyListener.close(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | onlineServerListener.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests LDAP listener which attempts to open a connection to a load balancing |
| | | * pool at the point when the listener handles a bind request. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @Test |
| | | public void testLDAPListenerLoadBalanceDuringHandleBind() throws Exception |
| | | { |
| | | // Online server listener. |
| | | final int onlineServerPort = TestCaseUtils.findFreePort(); |
| | | final MockServerConnection onlineServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory( |
| | | onlineServerConnection); |
| | | final LDAPListener onlineServerListener = new LDAPListener("localhost", |
| | | onlineServerPort, onlineServerConnectionFactory); |
| | | |
| | | try |
| | | { |
| | | // Connection pool and load balancing tests. |
| | | final ConnectionFactory offlineServer1 = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.findFreePort()), "offline1"); |
| | | final ConnectionFactory offlineServer2 = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | TestCaseUtils.findFreePort()), "offline2"); |
| | | final ConnectionFactory onlineServer = Connections |
| | | .newNamedConnectionFactory(new LDAPConnectionFactory("localhost", |
| | | onlineServerPort), "online"); |
| | | |
| | | // Round robin. |
| | | final ConnectionFactory loadBalancer = Connections |
| | | .newLoadBalancer(new RoundRobinLoadBalancingAlgorithm(Arrays.asList( |
| | | Connections.newConnectionPool(offlineServer1, 10), |
| | | Connections.newConnectionPool(offlineServer2, 10), |
| | | Connections.newConnectionPool(onlineServer, 10)))); |
| | | |
| | | final MockServerConnection proxyServerConnection = new MockServerConnection() |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final Integer requestContext, final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // Get connection from load balancer, this should fail over twice |
| | | // before getting connection to online server. |
| | | try |
| | | { |
| | | loadBalancer.getConnection().close(); |
| | | resultHandler.handleResult(Responses |
| | | .newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Unexpected. |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException.newErrorResult( |
| | | ResultCode.OTHER, |
| | | "Unexpected exception when connecting to load balancer", e)); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory( |
| | | proxyServerConnection); |
| | | |
| | | final LDAPListener proxyListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), proxyServerConnectionFactory); |
| | | try |
| | | { |
| | | // Connect, bind, and close. |
| | | final Connection connection = new LDAPConnectionFactory( |
| | | proxyListener.getSocketAddress()).getConnection(); |
| | | try |
| | | { |
| | | connection.bind("cn=test", "password"); |
| | | } |
| | | finally |
| | | { |
| | | connection.close(); |
| | | } |
| | | |
| | | // Wait for connect/close to complete. |
| | | proxyServerConnection.isClosed.await(); |
| | | |
| | | Assert.assertTrue(proxyServerConnection.isConnected); |
| | | Assert.assertTrue(onlineServerConnection.isConnected); |
| | | } |
| | | finally |
| | | { |
| | | proxyListener.close(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | onlineServerListener.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests LDAP listener which attempts to open a connection to a remote offline |
| | | * server at the point when the listener accepts the client connection. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @Test(enabled = false) |
| | | public void testLDAPListenerProxyDuringHandleAccept() throws Exception |
| | | { |
| | | final MockServerConnection onlineServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory( |
| | | onlineServerConnection); |
| | | final LDAPListener onlineServerListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), onlineServerConnectionFactory); |
| | | |
| | | try |
| | | { |
| | | final int offlineServerPort = TestCaseUtils.findFreePort(); |
| | | |
| | | final MockServerConnection proxyServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory( |
| | | proxyServerConnection) |
| | | { |
| | | |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) throws ErrorResultException |
| | | { |
| | | // First attempt offline server. |
| | | LDAPConnectionFactory lcf = new LDAPConnectionFactory("localhost", |
| | | offlineServerPort); |
| | | try |
| | | { |
| | | // This is expected to fail. |
| | | lcf.getConnection().close(); |
| | | throw ErrorResultException.newErrorResult(ResultCode.OTHER, |
| | | "Connection to offline server succeeded unexpectedly"); |
| | | } |
| | | catch (final ConnectionException ce) |
| | | { |
| | | // This is expected - so go to online server. |
| | | try |
| | | { |
| | | lcf = new LDAPConnectionFactory( |
| | | onlineServerListener.getSocketAddress()); |
| | | lcf.getConnection().close(); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Unexpected. |
| | | throw ErrorResultException.newErrorResult(ResultCode.OTHER, |
| | | "Unexpected exception when connecting to online server", e); |
| | | } |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Unexpected. |
| | | throw ErrorResultException.newErrorResult(ResultCode.OTHER, |
| | | "Unexpected exception when connecting to offline server", e); |
| | | } |
| | | |
| | | return super.handleAccept(clientContext); |
| | | } |
| | | |
| | | }; |
| | | final LDAPListener proxyListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), proxyServerConnectionFactory); |
| | | try |
| | | { |
| | | // Connect and close. |
| | | new LDAPConnectionFactory(proxyListener.getSocketAddress()) |
| | | .getConnection().close(); |
| | | |
| | | // Wait for connect/close to complete. |
| | | proxyServerConnection.isClosed.await(); |
| | | |
| | | Assert.assertTrue(proxyServerConnection.isConnected); |
| | | Assert.assertTrue(onlineServerConnection.isConnected); |
| | | } |
| | | finally |
| | | { |
| | | proxyListener.close(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | onlineServerListener.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests LDAP listener which attempts to open a connection to a remote offline |
| | | * server at the point when the listener handles a bind request. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @Test |
| | | public void testLDAPListenerProxyDuringHandleBind() throws Exception |
| | | { |
| | | final MockServerConnection onlineServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory( |
| | | onlineServerConnection); |
| | | final LDAPListener onlineServerListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), onlineServerConnectionFactory); |
| | | |
| | | try |
| | | { |
| | | final int offlineServerPort = TestCaseUtils.findFreePort(); |
| | | |
| | | final MockServerConnection proxyServerConnection = new MockServerConnection() |
| | | { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final Integer requestContext, final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // First attempt offline server. |
| | | LDAPConnectionFactory lcf = new LDAPConnectionFactory("localhost", |
| | | offlineServerPort); |
| | | try |
| | | { |
| | | // This is expected to fail. |
| | | lcf.getConnection().close(); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.OTHER, |
| | | "Connection to offline server succeeded unexpectedly")); |
| | | } |
| | | catch (final ConnectionException ce) |
| | | { |
| | | // This is expected - so go to online server. |
| | | try |
| | | { |
| | | lcf = new LDAPConnectionFactory( |
| | | onlineServerListener.getSocketAddress()); |
| | | lcf.getConnection().close(); |
| | | resultHandler.handleResult(Responses |
| | | .newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Unexpected. |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.OTHER, |
| | | "Unexpected exception when connecting to online server", |
| | | e)); |
| | | } |
| | | } |
| | | catch (final Exception e) |
| | | { |
| | | // Unexpected. |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException |
| | | .newErrorResult( |
| | | ResultCode.OTHER, |
| | | "Unexpected exception when connecting to offline server", |
| | | e)); |
| | | } |
| | | } |
| | | |
| | | }; |
| | | final MockServerConnectionFactory proxyServerConnectionFactory = new MockServerConnectionFactory( |
| | | proxyServerConnection); |
| | | final LDAPListener proxyListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), proxyServerConnectionFactory); |
| | | try |
| | | { |
| | | // Connect, bind, and close. |
| | | final Connection connection = new LDAPConnectionFactory( |
| | | proxyListener.getSocketAddress()).getConnection(); |
| | | try |
| | | { |
| | | connection.bind("cn=test", "password"); |
| | | } |
| | | finally |
| | | { |
| | | connection.close(); |
| | | } |
| | | |
| | | // Wait for connect/close to complete. |
| | | proxyServerConnection.isClosed.await(); |
| | | |
| | | Assert.assertTrue(proxyServerConnection.isConnected); |
| | | Assert.assertTrue(onlineServerConnection.isConnected); |
| | | } |
| | | finally |
| | | { |
| | | proxyListener.close(); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | onlineServerListener.close(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests server-side disconnection. |
| | | * |
| | | * @throws Exception |
| | | * If an unexpected error occurred. |
| | | */ |
| | | @Test |
| | | public void testServerDisconnect() throws Exception |
| | | { |
| | | final MockServerConnection onlineServerConnection = new MockServerConnection(); |
| | | final MockServerConnectionFactory onlineServerConnectionFactory = new MockServerConnectionFactory( |
| | | onlineServerConnection); |
| | | final LDAPListener onlineServerListener = new LDAPListener("localhost", |
| | | TestCaseUtils.findFreePort(), onlineServerConnectionFactory); |
| | | |
| | | final Connection connection; |
| | | try |
| | | { |
| | | // Connect and bind. |
| | | connection = new LDAPConnectionFactory( |
| | | onlineServerListener.getSocketAddress()).getConnection(); |
| | | try |
| | | { |
| | | connection.bind("cn=test", "password"); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | connection.close(); |
| | | throw e; |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | onlineServerConnection.context.disconnect(); |
| | | onlineServerListener.close(); |
| | | } |
| | | |
| | | try |
| | | { |
| | | // Connect and bind. |
| | | final Connection failedConnection = new LDAPConnectionFactory( |
| | | onlineServerListener.getSocketAddress()).getConnection(); |
| | | failedConnection.close(); |
| | | connection.close(); |
| | | Assert |
| | | .fail("Connection attempt to closed listener succeeded unexpectedly"); |
| | | } |
| | | catch (ConnectionException e) |
| | | { |
| | | // Expected. |
| | | } |
| | | |
| | | try |
| | | { |
| | | connection.bind("cn=test", "password"); |
| | | Assert.fail("Bind attempt on closed connection succeeded unexpectedly"); |
| | | } |
| | | catch (ErrorResultException e) |
| | | { |
| | | // Expected. |
| | | Assert.assertFalse(connection.isValid()); |
| | | Assert.assertFalse(connection.isClosed()); |
| | | } |
| | | finally |
| | | { |
| | | connection.close(); |
| | | Assert.assertFalse(connection.isValid()); |
| | | Assert.assertTrue(connection.isClosed()); |
| | | } |
| | | } |
| | | } |
| | |
| | | import org.opends.sdk.requests.*; |
| | | import org.opends.sdk.responses.*; |
| | | |
| | | import com.sun.grizzly.TransportFactory; |
| | | import com.sun.grizzly.nio.transport.TCPNIOTransport; |
| | | import org.glassfish.grizzly.TransportFactory; |
| | | import org.glassfish.grizzly.nio.transport.TCPNIOTransport; |
| | | import com.sun.opends.sdk.controls.AccountUsabilityRequestControl; |
| | | import com.sun.opends.sdk.controls.AccountUsabilityResponseControl; |
| | | import com.sun.opends.sdk.ldap.GrizzlyLDAPListenerOptions; |
| | |
| | | |
| | | |
| | | |
| | | private class LDAPServerConnection implements ServerConnection<Integer> |
| | | private class LDAPServerConnection implements |
| | | ServerConnection<Integer> |
| | | { |
| | | |
| | | private final LDAPClientContext clientContext; |
| | |
| | | final AbandonRequest request) throws UnsupportedOperationException |
| | | { |
| | | // Check if we have any concurrent operation with this message id. |
| | | final AbandonableRequest req = requestsInProgress.get(context); |
| | | final AbandonableRequest req = requestsInProgress.get(request |
| | | .getRequestID()); |
| | | if (req == null) |
| | | { |
| | | // Nothing to do here. |
| | |
| | | * @param intermediateResponseHandler |
| | | * @throws UnsupportedOperationException |
| | | */ |
| | | public void handleAdd(final Integer context, final AddRequest request, |
| | | final ResultHandler<? super Result> handler, |
| | | public void handleAdd(final Integer context, |
| | | final AddRequest request, final ResultHandler<? super Result> handler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * @param context |
| | | * @param request |
| | | * {@inheritDoc} |
| | | */ |
| | | public void handleConnectionClosed(final Integer context, |
| | | final UnbindRequest request) |
| | | { |
| | | close(); |
| | | } |
| | | |
| | | |
| | | |
| | | private void close() |
| | | { |
| | | if (saslServer != null) |
| | | { |
| | | try |
| | |
| | | |
| | | |
| | | /** |
| | | * @param error |
| | | * {@inheritDoc} |
| | | */ |
| | | public void handleConnectionException(final Throwable error) |
| | | public void handleConnectionDisconnected(ResultCode resultCode, |
| | | String message) |
| | | { |
| | | close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | close(); |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | final R result = request.getResultDecoder().adaptExtendedErrorResult( |
| | | final R result = request.getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.SUCCESS, "", ""); |
| | | resultHandler.handleResult(result); |
| | | clientContext.startTLS(sslContext, null, sslContext.getSocketFactory() |
| | |
| | | * @param context |
| | | * @param request |
| | | * @param resultHandler |
| | | * @param searchResulthandler |
| | | * @param intermediateResponseHandler |
| | | * @throws UnsupportedOperationException |
| | | */ |
| | | public void handleSearch(final Integer context, |
| | | final SearchRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final SearchResultHandler searchResulthandler, |
| | | final SearchRequest request, final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | |
| | | false, 10, false, 0)); |
| | | } |
| | | } |
| | | searchResulthandler.handleEntry(e); |
| | | resultHandler.handleEntry(e); |
| | | result = Responses.newResult(ResultCode.SUCCESS); |
| | | resultHandler.handleResult(result); |
| | | requestsInProgress.remove(context); |
| | |
| | | * @param context |
| | | * @return |
| | | */ |
| | | public ServerConnection<Integer> accept(final LDAPClientContext context) |
| | | public ServerConnection<Integer> handleAccept(final LDAPClientContext context) |
| | | { |
| | | return new LDAPServerConnection(context); |
| | | } |
| | |
| | | { |
| | | return; |
| | | } |
| | | try |
| | | { |
| | | listener.close(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | e.printStackTrace(); |
| | | } |
| | | listener.close(); |
| | | try |
| | | { |
| | | transport.stop(); |
| | |
| | | |
| | | |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Iterator; |
| | | import java.util.NoSuchElementException; |
| | | |
| | | import org.opends.sdk.schema.Schema; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.Test; |
| | |
| | | Assert.assertTrue(attribute.remove(ByteString.valueOf("another value"))); |
| | | Assert.assertEquals(attribute.size(), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testAdd() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertTrue(a.add(ByteString.valueOf("value1"))); |
| | | Assert.assertFalse(a.add(ByteString.valueOf("value1"))); |
| | | Assert.assertTrue(a.add(ByteString.valueOf("value2"))); |
| | | Assert.assertFalse(a.add(ByteString.valueOf("value2"))); |
| | | Assert.assertTrue(a.add(ByteString.valueOf("value3"))); |
| | | Assert.assertFalse(a.add(ByteString.valueOf("value3"))); |
| | | Assert.assertEquals(a.size(), 3); |
| | | Iterator<ByteString> i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testAddAll() |
| | | { |
| | | // addAll to an empty attribute. |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null)); |
| | | Iterator<ByteString> i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test"); |
| | | Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value1")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test"); |
| | | Assert.assertTrue(a.addAll( |
| | | Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | // addAll to a single-valued attribute. |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value2")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.addAll( |
| | | Arrays.asList(ByteString.valueOf("value2"), |
| | | ByteString.valueOf("value3")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | // addAll to a multi-valued attribute. |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | Assert.assertFalse(a.addAll(Collections.<ByteString> emptyList(), null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | Assert.assertTrue(a.addAll(Arrays.asList(ByteString.valueOf("value3")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | Assert.assertTrue(a.addAll( |
| | | Arrays.asList(ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value4")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testClear() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertTrue(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 0); |
| | | a.clear(); |
| | | Assert.assertTrue(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 0); |
| | | |
| | | a.add(ByteString.valueOf("value1")); |
| | | Assert.assertFalse(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 1); |
| | | a.clear(); |
| | | Assert.assertTrue(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 0); |
| | | |
| | | a.add(ByteString.valueOf("value1")); |
| | | a.add(ByteString.valueOf("value2")); |
| | | Assert.assertFalse(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 2); |
| | | a.clear(); |
| | | Assert.assertTrue(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 0); |
| | | |
| | | a.add(ByteString.valueOf("value1")); |
| | | a.add(ByteString.valueOf("value2")); |
| | | a.add(ByteString.valueOf("value3")); |
| | | Assert.assertFalse(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 3); |
| | | a.clear(); |
| | | Assert.assertTrue(a.isEmpty()); |
| | | Assert.assertEquals(a.size(), 0); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testContains() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.contains(ByteString.valueOf("value4"))); |
| | | |
| | | a.add(ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value1"))); |
| | | Assert.assertFalse(a.contains(ByteString.valueOf("value4"))); |
| | | |
| | | a.add(ByteString.valueOf("value2")); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value1"))); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value2"))); |
| | | Assert.assertFalse(a.contains(ByteString.valueOf("value4"))); |
| | | |
| | | a.add(ByteString.valueOf("value3")); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value1"))); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value2"))); |
| | | Assert.assertTrue(a.contains(ByteString.valueOf("value3"))); |
| | | Assert.assertFalse(a.contains(ByteString.valueOf("value4"))); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testContainsAll() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList())); |
| | | Assert |
| | | .assertFalse(a.containsAll(Arrays.asList(ByteString.valueOf("value1")))); |
| | | Assert.assertFalse(a.containsAll(Arrays.asList( |
| | | ByteString.valueOf("value1"), ByteString.valueOf("value2")))); |
| | | Assert.assertFalse(a.containsAll(Arrays.asList( |
| | | ByteString.valueOf("value1"), ByteString.valueOf("value2"), |
| | | ByteString.valueOf("value3")))); |
| | | |
| | | a.add(ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList())); |
| | | Assert |
| | | .assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1")))); |
| | | Assert.assertFalse(a.containsAll(Arrays.asList( |
| | | ByteString.valueOf("value1"), ByteString.valueOf("value2")))); |
| | | Assert.assertFalse(a.containsAll(Arrays.asList( |
| | | ByteString.valueOf("value1"), ByteString.valueOf("value2"), |
| | | ByteString.valueOf("value3")))); |
| | | |
| | | a.add(ByteString.valueOf("value2")); |
| | | Assert.assertTrue(a.containsAll(Collections.<ByteString> emptyList())); |
| | | Assert |
| | | .assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1")))); |
| | | Assert.assertTrue(a.containsAll(Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")))); |
| | | Assert.assertFalse(a.containsAll(Arrays.asList( |
| | | ByteString.valueOf("value1"), ByteString.valueOf("value2"), |
| | | ByteString.valueOf("value3")))); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testFirstValue() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | try |
| | | { |
| | | a.firstValue(); |
| | | Assert.fail("Expected NoSuchElementException"); |
| | | } |
| | | catch (NoSuchElementException e) |
| | | { |
| | | // Expected. |
| | | } |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertEquals(a.firstValue(), ByteString.valueOf("value1")); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | Assert.assertEquals(a.firstValue(), ByteString.valueOf("value1")); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value2"), |
| | | ByteString.valueOf("value1")); |
| | | Assert.assertEquals(a.firstValue(), ByteString.valueOf("value2")); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testGetAttributeDescription() |
| | | { |
| | | AttributeDescription ad = AttributeDescription.valueOf("test"); |
| | | Attribute a = new LinkedAttribute(ad); |
| | | Assert.assertEquals(a.getAttributeDescription(), ad); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testIterator() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Iterator<ByteString> i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testRemove() |
| | | { |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.remove(ByteString.valueOf("value1"))); |
| | | Iterator<ByteString> i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertFalse(a.remove(ByteString.valueOf("value2"))); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | Assert.assertTrue(a.remove(ByteString.valueOf("value1"))); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")); |
| | | Assert.assertFalse(a.remove(ByteString.valueOf("value3"))); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | Assert.assertTrue(a.remove(ByteString.valueOf("value1"))); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | Assert.assertTrue(a.remove(ByteString.valueOf("value2"))); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | } |
| | | |
| | | |
| | | |
| | | @Test |
| | | public void testRemoveAll() |
| | | { |
| | | // removeAll from an empty attribute. |
| | | Attribute a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null)); |
| | | Iterator<ByteString> i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.removeAll(Arrays.asList(ByteString.valueOf("value1")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test"); |
| | | Assert.assertFalse(a.removeAll(Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")))); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | // removeAll from single-valued attribute. |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null)); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1")); |
| | | Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")))); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | // removeAll from multi-valued attribute. |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertFalse(a.removeAll(Collections.<ByteString> emptyList(), null)); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value1")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value4")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1")), |
| | | null)); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value2")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value4")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertTrue(a.removeAll( |
| | | Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value3")); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value4")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertTrue(a.removeAll( |
| | | Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertTrue(i.hasNext()); |
| | | Assert.assertEquals(i.next(), ByteString.valueOf("value4")); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | |
| | | a = new LinkedAttribute("test", ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4")); |
| | | Assert.assertTrue(a.removeAll(Arrays.asList(ByteString.valueOf("value1"), |
| | | ByteString.valueOf("value2"), ByteString.valueOf("value3"), |
| | | ByteString.valueOf("value4"), ByteString.valueOf("value5")), null)); |
| | | i = a.iterator(); |
| | | Assert.assertFalse(i.hasNext()); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk; |
| | |
| | | |
| | | import java.io.File; |
| | | import java.io.FileWriter; |
| | | import java.io.IOException; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.ServerSocket; |
| | | |
| | | |
| | | |
| | |
| | | public static final String PROPERTY_LDAP_PORT = "org.opends.server.LdapPort"; |
| | | |
| | | /** |
| | | * Port number that's used by the server. Need to be used by the testcases to |
| | | * Port number that's used by the server. Need to be used by the test cases to |
| | | * create connections. |
| | | */ |
| | | public static int port = 11389; |
| | | public static int port; |
| | | |
| | | static |
| | | { |
| | |
| | | { |
| | | port = Integer.valueOf(ldapPort); |
| | | } |
| | | else |
| | | { |
| | | port = findFreePort(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | * Creates a temporary text file with the specified contents. It will be |
| | | * marked for automatic deletion when the JVM exits. |
| | | * |
| | | * @param lines |
| | | * The file contents. |
| | | * @return The absolute path to the file that was created. |
| | | * @throws Exception |
| | | * If an unexpected problem occurs. |
| | |
| | | |
| | | |
| | | /** |
| | | * Finds a free server socket port on the local host. |
| | | * |
| | | * @return The free port. |
| | | */ |
| | | public static int findFreePort() |
| | | { |
| | | int port; |
| | | try |
| | | { |
| | | ServerSocket serverLdapSocket = new ServerSocket(); |
| | | serverLdapSocket.setReuseAddress(true); |
| | | serverLdapSocket.bind(new InetSocketAddress("127.0.0.1", 0)); |
| | | port = serverLdapSocket.getLocalPort(); |
| | | serverLdapSocket.close(); |
| | | } |
| | | catch (IOException e) |
| | | { |
| | | throw new RuntimeException(e); |
| | | } |
| | | return port; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns an internal client connection to the running ldap server. |
| | | * |
| | | * @return The internal client connection. |
| | |
| | | * Starts the test ldap server. |
| | | * |
| | | * @throws Exception |
| | | * If an error occurs when starting the server. |
| | | */ |
| | | public static void startServer() throws Exception |
| | | { |
| | | // TODO:Try a couple of random ports before throwing exception. |
| | | LDAPServer.getInstance().start(port); |
| | | } |
| | | |
| | |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | import static org.testng.Assert.assertTrue; |
| | | import static org.testng.Assert.assertEquals; |
| | | |
| | | |
| | |
| | | @Test(dataProvider = "DigestMD5SASLBindRequests") |
| | | public void testQOP(DigestMD5SASLBindRequest request) throws Exception |
| | | { |
| | | DigestMD5SASLBindRequest.QOPOption [] options = |
| | | new DigestMD5SASLBindRequest.QOPOption[]{ |
| | | DigestMD5SASLBindRequest.QOPOption.AUTH, |
| | | DigestMD5SASLBindRequest.QOPOption.AUTH_INT, |
| | | DigestMD5SASLBindRequest.QOPOption.AUTH_CONF}; |
| | | request.setQOP(options); |
| | | |
| | | DigestMD5SASLBindRequest.QOPOption [] results = request.getQOP(); |
| | | for(int i = 0; i < options.length; i++) |
| | | { |
| | | assertEquals(options[i], results[i]); |
| | | } |
| | | String[] options = new String[] { |
| | | DigestMD5SASLBindRequest.QOP_AUTH, |
| | | DigestMD5SASLBindRequest.QOP_AUTH_INT, |
| | | DigestMD5SASLBindRequest.QOP_AUTH_CONF }; |
| | | request.addQOP(options); |
| | | assertEquals(request.getQOPs(), Arrays.asList(options)); |
| | | } |
| | | |
| | | @Test(dataProvider = "DigestMD5SASLBindRequests" ) |
| | | public void testStrength(DigestMD5SASLBindRequest request) throws Exception |
| | | { |
| | | DigestMD5SASLBindRequest.CipherOption[] options = |
| | | new DigestMD5SASLBindRequest.CipherOption[]{ |
| | | DigestMD5SASLBindRequest.CipherOption.RC4_40, |
| | | DigestMD5SASLBindRequest.CipherOption.TRIPLE_DES_RC4, |
| | | DigestMD5SASLBindRequest.CipherOption.DES_RC4_56}; |
| | | request.setCipher(options); |
| | | assertTrue(Arrays.deepEquals(options, request.getCipher())); |
| | | request.setCipher(DigestMD5SASLBindRequest.CIPHER_3DES); |
| | | assertEquals(request.getCipher(), DigestMD5SASLBindRequest.CIPHER_3DES); |
| | | |
| | | request.setCipher(DigestMD5SASLBindRequest.CIPHER_MEDIUM); |
| | | assertEquals(request.getCipher(), DigestMD5SASLBindRequest.CIPHER_MEDIUM); |
| | | } |
| | | |
| | | @Test(dataProvider = "DigestMD5SASLBindRequests") |
| | | public void testServerAuth(DigestMD5SASLBindRequest request) throws Exception |
| | | { |
| | | request.setServerAuth(true); |
| | | assertEquals(request.getServerAuth(), true); |
| | | assertEquals(request.isServerAuth(), true); |
| | | } |
| | | |
| | | @Test(dataProvider = "DigestMD5SASLBindRequests") |
| | |
| | | import java.util.Arrays; |
| | | |
| | | import static org.testng.Assert.assertEquals; |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | /** |
| | | * Tests GSSAPI SASL Bind requests. |
| | |
| | | @Test(dataProvider = "GSSAPISASLBindRequests") |
| | | public void testQOP(GSSAPISASLBindRequest request) throws Exception |
| | | { |
| | | GSSAPISASLBindRequest.QOPOption [] options = |
| | | new GSSAPISASLBindRequest.QOPOption[]{ |
| | | GSSAPISASLBindRequest.QOPOption.AUTH, |
| | | GSSAPISASLBindRequest.QOPOption.AUTH_INT, |
| | | GSSAPISASLBindRequest.QOPOption.AUTH_CONF}; |
| | | request.setQOP(options); |
| | | assertTrue(Arrays.deepEquals(options, request.getQOP())); |
| | | String[] options = new String[] { |
| | | GSSAPISASLBindRequest.QOP_AUTH, |
| | | GSSAPISASLBindRequest.QOP_AUTH_INT, |
| | | GSSAPISASLBindRequest.QOP_AUTH_CONF }; |
| | | request.addQOP(options); |
| | | assertEquals(request.getQOPs(), Arrays.asList(options)); |
| | | } |
| | | |
| | | @Test(dataProvider = "GSSAPISASLBindRequests") |
| | | public void testServerAuth(GSSAPISASLBindRequest request) throws Exception |
| | | { |
| | | request.setServerAuth(true); |
| | | assertEquals(request.getServerAuth(), true); |
| | | assertEquals(request.isServerAuth(), true); |
| | | } |
| | | |
| | | @Test(dataProvider = "GSSAPISASLBindRequests") |