| | |
| | | <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") |