feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* This class provides a basic implementation of the <tt>Control</tt>
* interface. It represents an LDAPv3 Control as defined in
* <a href="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</a>.
*
* @since 1.5
* @author Vincent Ryan
*/
public class BasicControl implements Control {
/**
* The control's object identifier string.
*
* @serial
*/
protected String id;
/**
* The control's criticality.
*
* @serial
*/
protected boolean criticality = false; // default
/**
* The control's ASN.1 BER encoded value.
*
* @serial
*/
protected byte[] value = null;
private static final long serialVersionUID = -4233907508771791687L;
/**
* Constructs a non-critical control.
*
* @param id The control's object identifier string.
*
*/
public BasicControl(String id) {
this.id = id;
}
/**
* Constructs a control using the supplied arguments.
*
* @param id The control's object identifier string.
* @param criticality The control's criticality.
* @param value The control's ASN.1 BER encoded value.
* It is not cloned - any changes to value
* will affect the contents of the control.
* It may be null.
*/
public BasicControl(String id, boolean criticality, byte[] value) {
this.id = id;
this.criticality = criticality;
this.value = value;
}
/**
* Retrieves the control's object identifier string.
*
* @return The non-null object identifier string.
*/
public String getID() {
return id;
}
/**
* Determines the control's criticality.
*
* @return true if the control is critical; false otherwise.
*/
public boolean isCritical() {
return criticality;
}
/**
* Retrieves the control's ASN.1 BER encoded value.
* The result includes the BER tag and length for the control's value but
* does not include the control's object identifier and criticality setting.
*
* @return A possibly null byte array representing the control's
* ASN.1 BER encoded value. It is not cloned - any changes to the
* returned value will affect the contents of the control.
*/
public byte[] getEncodedValue() {
return value;
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* This interface represents an LDAPv3 control as defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
*<p>
* The LDAPv3 protocol uses controls to send and receive additional data
* to affect the behavior of predefined operations.
* Controls can be sent along with any LDAP operation to the server.
* These are referred to as <em>request controls</em>. For example, a
* "sort" control can be sent with an LDAP search operation to
* request that the results be returned in a particular order.
* Solicited and unsolicited controls can also be returned with
* responses from the server. Such controls are referred to as
* <em>response controls</em>. For example, an LDAP server might
* define a special control to return change notifications.
*<p>
* This interface is used to represent both request and response controls.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see ControlFactory
* @since 1.3
*/
public interface Control extends java.io.Serializable {
/**
* Indicates a critical control.
* The value of this constant is <tt>true</tt>.
*/
public static final boolean CRITICAL = true;
/**
* Indicates a non-critical control.
* The value of this constant is <tt>false</tt>.
*/
public static final boolean NONCRITICAL = false;
/**
* Retrieves the object identifier assigned for the LDAP control.
*
* @return The non-null object identifier string.
*/
public String getID();
/**
* Determines the criticality of the LDAP control.
* A critical control must not be ignored by the server.
* In other words, if the server receives a critical control
* that it does not support, regardless of whether the control
* makes sense for the operation, the operation will not be performed
* and an <tt>OperationNotSupportedException</tt> will be thrown.
* @return true if this control is critical; false otherwise.
*/
public boolean isCritical();
/**
* Retrieves the ASN.1 BER encoded value of the LDAP control.
* The result is the raw BER bytes including the tag and length of
* the control's value. It does not include the controls OID or criticality.
*
* Null is returned if the value is absent.
*
* @return A possibly null byte array representing the ASN.1 BER encoded
* value of the LDAP control.
*/
public byte[] getEncodedValue();
// static final long serialVersionUID = -591027748900004825L;
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.NamingException;
import javax.naming.Context;
import java.util.Hashtable;
import com.sun.naming.internal.FactoryEnumeration;
import com.sun.naming.internal.ResourceManager;
/**
* This abstract class represents a factory for creating LDAPv3 controls.
* LDAPv3 controls are defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
*<p>
* When a service provider receives a response control, it uses control
* factories to return the specific/appropriate control class implementation.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see Control
* @since 1.3
*/
public abstract class ControlFactory {
/**
* Creates a new instance of a control factory.
*/
protected ControlFactory() {
}
/**
* Creates a control using this control factory.
*<p>
* The factory is used by the service provider to return controls
* that it reads from the LDAP protocol as specialized control classes.
* Without this mechanism, the provider would be returning
* controls that only contained data in BER encoded format.
*<p>
* Typically, <tt>ctl</tt> is a "basic" control containing
* BER encoded data. The factory is used to create a specialized
* control implementation, usually by decoding the BER encoded data,
* that provides methods to access that data in a type-safe and friendly
* manner.
* <p>
* For example, a factory might use the BER encoded data in
* basic control and return an instance of a VirtualListReplyControl.
*<p>
* If this factory cannot create a control using the argument supplied,
* it should return null.
* A factory should only throw an exception if it is sure that
* it is the only intended factory and that no other control factories
* should be tried. This might happen, for example, if the BER data
* in the control does not match what is expected of a control with
* the given OID. Since this method throws <tt>NamingException</tt>,
* any other internally generated exception that should be propagated
* must be wrapped inside a <tt>NamingException</tt>.
*
* @param ctl A non-null control.
*
* @return A possibly null Control.
* @exception NamingException If <tt>ctl</tt> contains invalid data that prevents it
* from being used to create a control. A factory should only throw
* an exception if it knows how to produce the control (identified by the OID)
* but is unable to because of, for example invalid BER data.
*/
public abstract Control getControlInstance(Control ctl) throws NamingException;
/**
* Creates a control using known control factories.
* <p>
* The following rule is used to create the control:
*<ul>
* <li> Use the control factories specified in
* the <tt>LdapContext.CONTROL_FACTORIES</tt> property of the
* environment, and of the provider resource file associated with
* <tt>ctx</tt>, in that order.
* The value of this property is a colon-separated list of factory
* class names that are tried in order, and the first one that succeeds
* in creating the control is the one used.
* If none of the factories can be loaded,
* return <code>ctl</code>.
* If an exception is encountered while creating the control, the
* exception is passed up to the caller.
*</ul>
* <p>
* Note that a control factory
* must be public and must have a public constructor that accepts no arguments.
* <p>
* @param ctl The non-null control object containing the OID and BER data.
* @param ctx The possibly null context in which the control is being created.
* If null, no such information is available.
* @param env The possibly null environment of the context. This is used
* to find the value of the <tt>LdapContext.CONTROL_FACTORIES</tt> property.
* @return A control object created using <code>ctl</code>; or
* <code>ctl</code> if a control object cannot be created using
* the algorithm described above.
* @exception NamingException if a naming exception was encountered
* while attempting to create the control object.
* If one of the factories accessed throws an
* exception, it is propagated up to the caller.
* If an error was encountered while loading
* and instantiating the factory and object classes, the exception
* is wrapped inside a <tt>NamingException</tt> and then rethrown.
*/
public static Control getControlInstance(Control ctl, Context ctx,
Hashtable<?,?> env)
throws NamingException {
// Get object factories list from environment properties or
// provider resource file.
FactoryEnumeration factories = ResourceManager.getFactories(
LdapContext.CONTROL_FACTORIES, env, ctx);
if (factories == null) {
return ctl;
}
// Try each factory until one succeeds
Control answer = null;
ControlFactory factory;
while (answer == null && factories.hasMore()) {
factory = (ControlFactory)factories.next();
answer = factory.getControlInstance(ctl);
}
return (answer != null)? answer : ctl;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.NamingException;
/**
* This interface represents an LDAPv3 extended operation request as defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
* <pre>
* ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
* requestName [0] LDAPOID,
* requestValue [1] OCTET STRING OPTIONAL }
* </pre>
* It comprises an object identifier string and an optional ASN.1 BER
* encoded value.
*<p>
* The methods in this class are used by the service provider to construct
* the bits to send to the LDAP server. Applications typically only deal with
* the classes that implement this interface, supplying them with
* any information required for a particular extended operation request.
* It would then pass such a class as an argument to the
* <tt>LdapContext.extendedOperation()</tt> method for performing the
* LDAPv3 extended operation.
*<p>
* For example, suppose the LDAP server supported a 'get time' extended operation.
* It would supply GetTimeRequest and GetTimeResponse classes:
*<blockquote><pre>
* public class GetTimeRequest implements ExtendedRequest {
* public GetTimeRequest() {... };
* public ExtendedResponse createExtendedResponse(String id,
* byte[] berValue, int offset, int length)
* throws NamingException {
* return new GetTimeResponse(id, berValue, offset, length);
* }
* ...
* }
* public class GetTimeResponse implements ExtendedResponse {
* long time;
* public GetTimeResponse(String id, byte[] berValue, int offset,
* int length) throws NamingException {
* time = ... // decode berValue to get time
* }
* public java.util.Date getDate() { return new java.util.Date(time) };
* public long getTime() { return time };
* ...
* }
*</pre></blockquote>
* A program would use then these classes as follows:
*<blockquote><pre>
* GetTimeResponse resp =
* (GetTimeResponse) ectx.extendedOperation(new GetTimeRequest());
* long time = resp.getTime();
*</pre></blockquote>
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see ExtendedResponse
* @see LdapContext#extendedOperation
* @since 1.3
*/
public interface ExtendedRequest extends java.io.Serializable {
/**
* Retrieves the object identifier of the request.
*
* @return The non-null object identifier string representing the LDAP
* <tt>ExtendedRequest.requestName</tt> component.
*/
public String getID();
/**
* Retrieves the ASN.1 BER encoded value of the LDAP extended operation
* request. Null is returned if the value is absent.
*
* The result is the raw BER bytes including the tag and length of
* the request value. It does not include the request OID.
* This method is called by the service provider to get the bits to
* put into the extended operation to be sent to the LDAP server.
*
* @return A possibly null byte array representing the ASN.1 BER encoded
* contents of the LDAP <tt>ExtendedRequest.requestValue</tt>
* component.
* @exception IllegalStateException If the encoded value cannot be retrieved
* because the request contains insufficient or invalid data/state.
*/
public byte[] getEncodedValue();
/**
* Creates the response object that corresponds to this request.
*<p>
* After the service provider has sent the extended operation request
* to the LDAP server, it will receive a response from the server.
* If the operation failed, the provider will throw a NamingException.
* If the operation succeeded, the provider will invoke this method
* using the data that it got back in the response.
* It is the job of this method to return a class that implements
* the ExtendedResponse interface that is appropriate for the
* extended operation request.
*<p>
* For example, a Start TLS extended request class would need to know
* how to process a Start TLS extended response. It does this by creating
* a class that implements ExtendedResponse.
*
* @param id The possibly null object identifier of the response
* control.
* @param berValue The possibly null ASN.1 BER encoded value of the
* response control.
* This is the raw BER bytes including the tag and length of
* the response value. It does not include the response OID.
* @param offset The starting position in berValue of the bytes to use.
* @param length The number of bytes in berValue to use.
*
* @return A non-null object.
* @exception NamingException if cannot create extended response
* due to an error.
* @see ExtendedResponse
*/
public ExtendedResponse createExtendedResponse(String id,
byte[] berValue, int offset, int length) throws NamingException;
// static final long serialVersionUID = -7560110759229059814L;
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* This interface represents an LDAP extended operation response as defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
* <pre>
* ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
* COMPONENTS OF LDAPResult,
* responseName [10] LDAPOID OPTIONAL,
* response [11] OCTET STRING OPTIONAL }
* </pre>
* It comprises an optional object identifier and an optional ASN.1 BER
* encoded value.
*
*<p>
* The methods in this class can be used by the application to get low
* level information about the extended operation response. However, typically,
* the application will be using methods specific to the class that
* implements this interface. Such a class should have decoded the BER buffer
* in the response and should provide methods that allow the user to
* access that data in the response in a type-safe and friendly manner.
*<p>
* For example, suppose the LDAP server supported a 'get time' extended operation.
* It would supply GetTimeRequest and GetTimeResponse classes.
* The GetTimeResponse class might look like:
*<blockquote><pre>
* public class GetTimeResponse implements ExtendedResponse {
* public java.util.Date getDate() {...};
* public long getTime() {...};
* ....
* }
*</pre></blockquote>
* A program would use then these classes as follows:
*<blockquote><pre>
* GetTimeResponse resp =
* (GetTimeResponse) ectx.extendedOperation(new GetTimeRequest());
* java.util.Date now = resp.getDate();
*</pre></blockquote>
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see ExtendedRequest
* @since 1.3
*/
public interface ExtendedResponse extends java.io.Serializable {
/**
* Retrieves the object identifier of the response.
* The LDAP protocol specifies that the response object identifier is optional.
* If the server does not send it, the response will contain no ID (i.e. null).
*
* @return A possibly null object identifier string representing the LDAP
* <tt>ExtendedResponse.responseName</tt> component.
*/
public String getID();
/**
* Retrieves the ASN.1 BER encoded value of the LDAP extended operation
* response. Null is returned if the value is absent from the response
* sent by the LDAP server.
* The result is the raw BER bytes including the tag and length of
* the response value. It does not include the response OID.
*
* @return A possibly null byte array representing the ASN.1 BER encoded
* contents of the LDAP <tt>ExtendedResponse.response</tt>
* component.
*/
public byte[] getEncodedValue();
//static final long serialVersionUID = -3320509678029180273L;
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.NamingException;
/**
* This interface is for returning controls with objects returned
* in NamingEnumerations.
* For example, suppose a server sends back controls with the results
* of a search operation, the service provider would return a NamingEnumeration of
* objects that are both SearchResult and implement HasControls.
*<blockquote><pre>
* NamingEnumeration elts = ectx.search((Name)name, filter, sctls);
* while (elts.hasMore()) {
* Object entry = elts.next();
*
* // Get search result
* SearchResult res = (SearchResult)entry;
* // do something with it
*
* // Get entry controls
* if (entry instanceof HasControls) {
* Control[] entryCtls = ((HasControls)entry).getControls();
* // do something with controls
* }
* }
*</pre></blockquote>
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
* @since 1.3
*
*/
public interface HasControls {
/**
* Retrieves an array of <tt>Control</tt>s from the object that
* implements this interface. It is null if there are no controls.
*
* @return A possibly null array of <tt>Control</tt> objects.
* @throws NamingException If cannot return controls due to an error.
*/
public Control[] getControls() throws NamingException;
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;
/**
* This class is the starting context for performing
* LDAPv3-style extended operations and controls.
*<p>
* See <tt>javax.naming.InitialContext</tt> and
* <tt>javax.naming.InitialDirContext</tt> for details on synchronization,
* and the policy for how an initial context is created.
*
* <h1>Request Controls</h1>
* When you create an initial context (<tt>InitialLdapContext</tt>),
* you can specify a list of request controls.
* These controls will be used as the request controls for any
* implicit LDAP "bind" operation performed by the context or contexts
* derived from the context. These are called <em>connection request controls</em>.
* Use <tt>getConnectControls()</tt> to get a context's connection request
* controls.
*<p>
* The request controls supplied to the initial context constructor
* are <em>not</em> used as the context request controls
* for subsequent context operations such as searches and lookups.
* Context request controls are set and updated by using
* <tt>setRequestControls()</tt>.
*<p>
* As shown, there can be two different sets of request controls
* associated with a context: connection request controls and context
* request controls.
* This is required for those applications needing to send critical
* controls that might not be applicable to both the context operation and
* any implicit LDAP "bind" operation.
* A typical user program would do the following:
*<blockquote><pre>
* InitialLdapContext lctx = new InitialLdapContext(env, critConnCtls);
* lctx.setRequestControls(critModCtls);
* lctx.modifyAttributes(name, mods);
* Controls[] respCtls = lctx.getResponseControls();
*</pre></blockquote>
* It specifies first the critical controls for creating the initial context
* (<tt>critConnCtls</tt>), and then sets the context's request controls
* (<tt>critModCtls</tt>) for the context operation. If for some reason
* <tt>lctx</tt> needs to reconnect to the server, it will use
* <tt>critConnCtls</tt>. See the <tt>LdapContext</tt> interface for
* more discussion about request controls.
*<p>
* Service provider implementors should read the "Service Provider" section
* in the <tt>LdapContext</tt> class description for implementation details.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see LdapContext
* @see javax.naming.InitialContext
* @see javax.naming.directory.InitialDirContext
* @see javax.naming.spi.NamingManager#setInitialContextFactoryBuilder
* @since 1.3
*/
public class InitialLdapContext extends InitialDirContext implements LdapContext {
private static final String
BIND_CONTROLS_PROPERTY = "java.naming.ldap.control.connect";
/**
* Constructs an initial context using no environment properties or
* connection request controls.
* Equivalent to <tt>new InitialLdapContext(null, null)</tt>.
*
* @throws NamingException if a naming exception is encountered
*/
public InitialLdapContext() throws NamingException {
super(null);
}
/**
* Constructs an initial context
* using environment properties and connection request controls.
* See <tt>javax.naming.InitialContext</tt> for a discussion of
* environment properties.
*
* <p> This constructor will not modify its parameters or
* save references to them, but may save a clone or copy.
* Caller should not modify mutable keys and values in
* <tt>environment</tt> after it has been passed to the constructor.
*
* <p> <tt>connCtls</tt> is used as the underlying context instance's
* connection request controls. See the class description
* for details.
*
* @param environment
* environment used to create the initial DirContext.
* Null indicates an empty environment.
* @param connCtls
* connection request controls for the initial context.
* If null, no connection request controls are used.
*
* @throws NamingException if a naming exception is encountered
*
* @see #reconnect
* @see LdapContext#reconnect
*/
@SuppressWarnings("unchecked")
public InitialLdapContext(Hashtable<?,?> environment,
Control[] connCtls)
throws NamingException {
super(true); // don't initialize yet
// Clone environment since caller owns it.
Hashtable<Object,Object> env = (environment == null)
? new Hashtable<>(11)
: (Hashtable<Object,Object>)environment.clone();
// Put connect controls into environment. Copy them first since
// caller owns the array.
if (connCtls != null) {
Control[] copy = new Control[connCtls.length];
System.arraycopy(connCtls, 0, copy, 0, connCtls.length);
env.put(BIND_CONTROLS_PROPERTY, copy);
}
// set version to LDAPv3
env.put("java.naming.ldap.version", "3");
// Initialize with updated environment
init(env);
}
/**
* Retrieves the initial LDAP context.
*
* @return The non-null cached initial context.
* @exception NotContextException If the initial context is not an
* instance of <tt>LdapContext</tt>.
* @exception NamingException If a naming exception was encountered.
*/
private LdapContext getDefaultLdapInitCtx() throws NamingException{
Context answer = getDefaultInitCtx();
if (!(answer instanceof LdapContext)) {
if (answer == null) {
throw new NoInitialContextException();
} else {
throw new NotContextException(
"Not an instance of LdapContext");
}
}
return (LdapContext)answer;
}
// LdapContext methods
// Most Javadoc is deferred to the LdapContext interface.
public ExtendedResponse extendedOperation(ExtendedRequest request)
throws NamingException {
return getDefaultLdapInitCtx().extendedOperation(request);
}
public LdapContext newInstance(Control[] reqCtls)
throws NamingException {
return getDefaultLdapInitCtx().newInstance(reqCtls);
}
public void reconnect(Control[] connCtls) throws NamingException {
getDefaultLdapInitCtx().reconnect(connCtls);
}
public Control[] getConnectControls() throws NamingException {
return getDefaultLdapInitCtx().getConnectControls();
}
public void setRequestControls(Control[] requestControls)
throws NamingException {
getDefaultLdapInitCtx().setRequestControls(requestControls);
}
public Control[] getRequestControls() throws NamingException {
return getDefaultLdapInitCtx().getRequestControls();
}
public Control[] getResponseControls() throws NamingException {
return getDefaultLdapInitCtx().getResponseControls();
}
}

View File

@@ -0,0 +1,347 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import java.util.Hashtable;
/**
* This interface represents a context in which you can perform
* operations with LDAPv3-style controls and perform LDAPv3-style
* extended operations.
*
* For applications that do not require such controls or extended
* operations, the more generic <tt>javax.naming.directory.DirContext</tt>
* should be used instead.
*
* <h3>Usage Details About Controls</h3>
*
* This interface provides support for LDAP v3 controls.
* At a high level, this support allows a user
* program to set request controls for LDAP operations that are executed
* in the course of the user program's invocation of
* <tt>Context</tt>/<tt>DirContext</tt>
* methods, and read response controls resulting from LDAP operations.
* At the implementation level, there are some details that developers of
* both the user program and service providers need to understand in order
* to correctly use request and response controls.
*
* <h3>Request Controls</h3>
* <p>
* There are two types of request controls:
* <ul>
* <li>Request controls that affect how a connection is created
* <li>Request controls that affect context methods
* </ul>
*
* The former is used whenever a connection needs to be established or
* re-established with an LDAP server. The latter is used when all other
* LDAP operations are sent to the LDAP server. The reason why a
* distinction between these two types of request controls is necessary
* is because JNDI is a high-level API that does not deal directly with
* connections. It is the job of service providers to do any necessary
* connection management. Consequently, a single
* connection may be shared by multiple context instances, and a service provider
* is free to use its own algorithms to conserve connection and network
* usage. Thus, when a method is invoked on the context instance, the service
* provider might need to do some connection management in addition to
* performing the corresponding LDAP operations. For connection management,
* it uses the <em>connection request controls</em>, while for the normal
* LDAP operations, it uses the <em>context request controls</em>.
*<p>Unless explicitly qualified, the term "request controls" refers to
* context request controls.
*
* <h4>Context Request Controls</h4>
* There are two ways in which a context instance gets its request controls:
* <ol>
* <li><tt>ldapContext.newInstance(<strong>reqCtls</strong>)</tt>
* <li><tt>ldapContext.setRequestControls(<strong>reqCtls</strong>)</tt>
* </ol>
* where <tt>ldapContext</tt> is an instance of <tt>LdapContext</tt>.
* Specifying <tt>null</tt> or an empty array for <tt>reqCtls</tt>
* means no request controls.
* <tt>newInstance()</tt> creates a new instance of a context using
* <tt>reqCtls</tt>, while <tt>setRequestControls()</tt>
* updates an existing context instance's request controls to <tt>reqCtls</tt>.
* <p>
* Unlike environment properties, request controls of a context instance
* <em>are not inherited</em> by context instances that are derived from
* it. Derived context instances have <tt>null</tt> as their context
* request controls. You must set the request controls of a derived context
* instance explicitly using <tt>setRequestControls()</tt>.
* <p>
* A context instance's request controls are retrieved using
* the method <tt>getRequestControls()</tt>.
*
* <h4>Connection Request Controls</h4>
* There are three ways in which connection request controls are set:
* <ol>
* <li><tt>
* new InitialLdapContext(env, <strong>connCtls</strong>)</tt>
* <li><tt>refException.getReferralContext(env, <strong>connCtls</strong>)</tt>
* <li><tt>ldapContext.reconnect(<strong>connCtls</strong>);</tt>
* </ol>
* where <tt>refException</tt> is an instance of
* <tt>LdapReferralException</tt>, and <tt>ldapContext</tt> is an
* instance of <tt>LdapContext</tt>.
* Specifying <tt>null</tt> or an empty array for <tt>connCtls</tt>
* means no connection request controls.
* <p>
* Like environment properties, connection request controls of a context
* <em>are inherited</em> by contexts that are derived from it.
* Typically, you initialize the connection request controls using the
* <tt>InitialLdapContext</tt> constructor or
* <tt>LdapReferralContext.getReferralContext()</tt>. These connection
* request controls are inherited by contexts that share the same
* connection--that is, contexts derived from the initial or referral
* contexts.
* <p>
* Use <tt>reconnect()</tt> to change the connection request controls of
* a context.
* Invoking <tt>ldapContext.reconnect()</tt> affects only the
* connection used by <tt>ldapContext</tt> and any new contexts instances that are
* derived form <tt>ldapContext</tt>. Contexts that previously shared the
* connection with <tt>ldapContext</tt> remain unchanged. That is, a context's
* connection request controls must be explicitly changed and is not
* affected by changes to another context's connection request
* controls.
* <p>
* A context instance's connection request controls are retrieved using
* the method <tt>getConnectControls()</tt>.
*
* <h4>Service Provider Requirements</h4>
*
* A service provider supports connection and context request controls
* in the following ways. Context request controls must be associated on
* a per context instance basis while connection request controls must be
* associated on a per connection instance basis. The service provider
* must look for the connection request controls in the environment
* property "java.naming.ldap.control.connect" and pass this environment
* property on to context instances that it creates.
*
* <h3>Response Controls</h3>
*
* The method <tt>LdapContext.getResponseControls()</tt> is used to
* retrieve the response controls generated by LDAP operations executed
* as the result of invoking a <tt>Context</tt>/<tt>DirContext</tt>
* operation. The result is all of the responses controls generated
* by the underlying LDAP operations, including any implicit reconnection.
* To get only the reconnection response controls,
* use <tt>reconnect()</tt> followed by <tt>getResponseControls()</tt>.
*
* <h3>Parameters</h3>
*
* A <tt>Control[]</tt> array
* passed as a parameter to any method is owned by the caller.
* The service provider will not modify the array or keep a reference to it,
* although it may keep references to the individual <tt>Control</tt> objects
* in the array.
* A <tt>Control[]</tt> array returned by any method is immutable, and may
* not subsequently be modified by either the caller or the service provider.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see InitialLdapContext
* @see LdapReferralException#getReferralContext(java.util.Hashtable,javax.naming.ldap.Control[])
* @since 1.3
*/
public interface LdapContext extends DirContext {
/**
* Performs an extended operation.
*
* This method is used to support LDAPv3 extended operations.
* @param request The non-null request to be performed.
* @return The possibly null response of the operation. null means
* the operation did not generate any response.
* @throws NamingException If an error occurred while performing the
* extended operation.
*/
public ExtendedResponse extendedOperation(ExtendedRequest request)
throws NamingException;
/**
* Creates a new instance of this context initialized using request controls.
*
* This method is a convenience method for creating a new instance
* of this context for the purposes of multithreaded access.
* For example, if multiple threads want to use different context
* request controls,
* each thread may use this method to get its own copy of this context
* and set/get context request controls without having to synchronize with other
* threads.
*<p>
* The new context has the same environment properties and connection
* request controls as this context. See the class description for details.
* Implementations might also allow this context and the new context
* to share the same network connection or other resources if doing
* so does not impede the independence of either context.
*
* @param requestControls The possibly null request controls
* to use for the new context.
* If null, the context is initialized with no request controls.
*
* @return A non-null <tt>LdapContext</tt> instance.
* @exception NamingException If an error occurred while creating
* the new instance.
* @see InitialLdapContext
*/
public LdapContext newInstance(Control[] requestControls)
throws NamingException;
/**
* Reconnects to the LDAP server using the supplied controls and
* this context's environment.
*<p>
* This method is a way to explicitly initiate an LDAP "bind" operation.
* For example, you can use this method to set request controls for
* the LDAP "bind" operation, or to explicitly connect to the server
* to get response controls returned by the LDAP "bind" operation.
*<p>
* This method sets this context's <tt>connCtls</tt>
* to be its new connection request controls. This context's
* context request controls are not affected.
* After this method has been invoked, any subsequent
* implicit reconnections will be done using <tt>connCtls</tt>.
* <tt>connCtls</tt> are also used as
* connection request controls for new context instances derived from this
* context.
* These connection request controls are not
* affected by <tt>setRequestControls()</tt>.
*<p>
* Service provider implementors should read the "Service Provider" section
* in the class description for implementation details.
* @param connCtls The possibly null controls to use. If null, no
* controls are used.
* @exception NamingException If an error occurred while reconnecting.
* @see #getConnectControls
* @see #newInstance
*/
public void reconnect(Control[] connCtls) throws NamingException;
/**
* Retrieves the connection request controls in effect for this context.
* The controls are owned by the JNDI implementation and are
* immutable. Neither the array nor the controls may be modified by the
* caller.
*
* @return A possibly-null array of controls. null means no connect controls
* have been set for this context.
* @exception NamingException If an error occurred while getting the request
* controls.
*/
public Control[] getConnectControls() throws NamingException;
/**
* Sets the request controls for methods subsequently
* invoked on this context.
* The request controls are owned by the JNDI implementation and are
* immutable. Neither the array nor the controls may be modified by the
* caller.
* <p>
* This removes any previous request controls and adds
* <tt>requestControls</tt>
* for use by subsequent methods invoked on this context.
* This method does not affect this context's connection request controls.
*<p>
* Note that <tt>requestControls</tt> will be in effect until the next
* invocation of <tt>setRequestControls()</tt>. You need to explicitly
* invoke <tt>setRequestControls()</tt> with <tt>null</tt> or an empty
* array to clear the controls if you don't want them to affect the
* context methods any more.
* To check what request controls are in effect for this context, use
* <tt>getRequestControls()</tt>.
* @param requestControls The possibly null controls to use. If null, no
* controls are used.
* @exception NamingException If an error occurred while setting the
* request controls.
* @see #getRequestControls
*/
public void setRequestControls(Control[] requestControls)
throws NamingException;
/**
* Retrieves the request controls in effect for this context.
* The request controls are owned by the JNDI implementation and are
* immutable. Neither the array nor the controls may be modified by the
* caller.
*
* @return A possibly-null array of controls. null means no request controls
* have been set for this context.
* @exception NamingException If an error occurred while getting the request
* controls.
* @see #setRequestControls
*/
public Control[] getRequestControls() throws NamingException;
/**
* Retrieves the response controls produced as a result of the last
* method invoked on this context.
* The response controls are owned by the JNDI implementation and are
* immutable. Neither the array nor the controls may be modified by the
* caller.
*<p>
* These response controls might have been generated by a successful or
* failed operation.
*<p>
* When a context method that may return response controls is invoked,
* response controls from the previous method invocation are cleared.
* <tt>getResponseControls()</tt> returns all of the response controls
* generated by LDAP operations used by the context method in the order
* received from the LDAP server.
* Invoking <tt>getResponseControls()</tt> does not
* clear the response controls. You can call it many times (and get
* back the same controls) until the next context method that may return
* controls is invoked.
*<p>
* @return A possibly null array of controls. If null, the previous
* method invoked on this context did not produce any controls.
* @exception NamingException If an error occurred while getting the response
* controls.
*/
public Control[] getResponseControls() throws NamingException;
/**
* Constant that holds the name of the environment property
* for specifying the list of control factories to use. The value
* of the property should be a colon-separated list of the fully
* qualified class names of factory classes that will create a control
* given another control. See
* <tt>ControlFactory.getControlInstance()</tt> for details.
* This property may be specified in the environment, an applet
* parameter, a system property, or one or more resource files.
*<p>
* The value of this constant is "java.naming.factory.control".
*
* @see ControlFactory
* @see javax.naming.Context#addToEnvironment
* @see javax.naming.Context#removeFromEnvironment
*/
static final String CONTROL_FACTORIES = "java.naming.factory.control";
}

View File

@@ -0,0 +1,787 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.Name;
import javax.naming.InvalidNameException;
import java.util.Enumeration;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Collections;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* This class represents a distinguished name as specified by
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
* A distinguished name, or DN, is composed of an ordered list of
* components called <em>relative distinguished name</em>s, or RDNs.
* Details of a DN's syntax are described in RFC 2253.
*<p>
* This class resolves a few ambiguities found in RFC 2253
* as follows:
* <ul>
* <li> RFC 2253 leaves the term "whitespace" undefined. The
* ASCII space character 0x20 (" ") is used in its place.
* <li> Whitespace is allowed on either side of ',', ';', '=', and '+'.
* Such whitespace is accepted but not generated by this code,
* and is ignored when comparing names.
* <li> AttributeValue strings containing '=' or non-leading '#'
* characters (unescaped) are accepted.
* </ul>
*<p>
* String names passed to <code>LdapName</code> or returned by it
* use the full Unicode character set. They may also contain
* characters encoded into UTF-8 with each octet represented by a
* three-character substring such as "\\B4".
* They may not, however, contain characters encoded into UTF-8 with
* each octet represented by a single character in the string: the
* meaning would be ambiguous.
*<p>
* <code>LdapName</code> will properly parse all valid names, but
* does not attempt to detect all possible violations when parsing
* invalid names. It is "generous" in accepting invalid names.
* The "validity" of a name is determined ultimately when it
* is supplied to an LDAP server, which may accept or
* reject the name based on factors such as its schema information
* and interoperability considerations.
*<p>
* When names are tested for equality, attribute types, both binary
* and string values, are case-insensitive.
* String values with different but equivalent usage of quoting,
* escaping, or UTF8-hex-encoding are considered equal. The order of
* components in multi-valued RDNs (such as "ou=Sales+cn=Bob") is not
* significant.
* <p>
* The components of a LDAP name, that is, RDNs, are numbered. The
* indexes of a LDAP name with n RDNs range from 0 to n-1.
* This range may be written as [0,n).
* The right most RDN is at index 0, and the left most RDN is at
* index n-1. For example, the distinguished name:
* "CN=Steve Kille, O=Isode Limited, C=GB" is numbered in the following
* sequence ranging from 0 to 2: {C=GB, O=Isode Limited, CN=Steve Kille}. An
* empty LDAP name is represented by an empty RDN list.
*<p>
* Concurrent multithreaded read-only access of an instance of
* <tt>LdapName</tt> need not be synchronized.
*<p>
* Unless otherwise noted, the behavior of passing a null argument
* to a constructor or method in this class will cause a
* NullPointerException to be thrown.
*
* @author Scott Seligman
* @since 1.5
*/
public class LdapName implements Name {
private transient List<Rdn> rdns; // parsed name components
private transient String unparsed; // if non-null, the DN in unparsed form
private static final long serialVersionUID = -1595520034788997356L;
/**
* Constructs an LDAP name from the given distinguished name.
*
* @param name This is a non-null distinguished name formatted
* according to the rules defined in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
*
* @throws InvalidNameException if a syntax violation is detected.
* @see Rdn#escapeValue(Object value)
*/
public LdapName(String name) throws InvalidNameException {
unparsed = name;
parse();
}
/**
* Constructs an LDAP name given its parsed RDN components.
* <p>
* The indexing of RDNs in the list follows the numbering of
* RDNs described in the class description.
*
* @param rdns The non-null list of <tt>Rdn</tt>s forming this LDAP name.
*/
public LdapName(List<Rdn> rdns) {
// if (rdns instanceof ArrayList<Rdn>) {
// this.rdns = rdns.clone();
// } else if (rdns instanceof List<Rdn>) {
// this.rdns = new ArrayList<Rdn>(rdns);
// } else {
// throw IllegalArgumentException(
// "Invalid entries, list entries must be of type Rdn");
// }
this.rdns = new ArrayList<>(rdns.size());
for (int i = 0; i < rdns.size(); i++) {
Object obj = rdns.get(i);
if (!(obj instanceof Rdn)) {
throw new IllegalArgumentException("Entry:" + obj +
" not a valid type;list entries must be of type Rdn");
}
this.rdns.add((Rdn)obj);
}
}
/*
* Constructs an LDAP name given its parsed components (the elements
* of "rdns" in the range [beg,end)) and, optionally
* (if "name" is not null), the unparsed DN.
*
*/
private LdapName(String name, List<Rdn> rdns, int beg, int end) {
unparsed = name;
// this.rdns = rdns.subList(beg, end);
List<Rdn> sList = rdns.subList(beg, end);
this.rdns = new ArrayList<>(sList);
}
/**
* Retrieves the number of components in this LDAP name.
* @return The non-negative number of components in this LDAP name.
*/
public int size() {
return rdns.size();
}
/**
* Determines whether this LDAP name is empty.
* An empty name is one with zero components.
* @return true if this LDAP name is empty, false otherwise.
*/
public boolean isEmpty() {
return rdns.isEmpty();
}
/**
* Retrieves the components of this name as an enumeration
* of strings. The effect of updates to this name on this enumeration
* is undefined. If the name has zero components, an empty (non-null)
* enumeration is returned.
* The order of the components returned by the enumeration is same as
* the order in which the components are numbered as described in the
* class description.
*
* @return A non-null enumeration of the components of this LDAP name.
* Each element of the enumeration is of class String.
*/
public Enumeration<String> getAll() {
final Iterator<Rdn> iter = rdns.iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
return iter.hasNext();
}
public String nextElement() {
return iter.next().toString();
}
};
}
/**
* Retrieves a component of this LDAP name as a string.
* @param posn The 0-based index of the component to retrieve.
* Must be in the range [0,size()).
* @return The non-null component at index posn.
* @exception IndexOutOfBoundsException if posn is outside the
* specified range.
*/
public String get(int posn) {
return rdns.get(posn).toString();
}
/**
* Retrieves an RDN of this LDAP name as an Rdn.
* @param posn The 0-based index of the RDN to retrieve.
* Must be in the range [0,size()).
* @return The non-null RDN at index posn.
* @exception IndexOutOfBoundsException if posn is outside the
* specified range.
*/
public Rdn getRdn(int posn) {
return rdns.get(posn);
}
/**
* Creates a name whose components consist of a prefix of the
* components of this LDAP name.
* Subsequent changes to this name will not affect the name
* that is returned and vice versa.
* @param posn The 0-based index of the component at which to stop.
* Must be in the range [0,size()].
* @return An instance of <tt>LdapName</tt> consisting of the
* components at indexes in the range [0,posn).
* If posn is zero, an empty LDAP name is returned.
* @exception IndexOutOfBoundsException
* If posn is outside the specified range.
*/
public Name getPrefix(int posn) {
try {
return new LdapName(null, rdns, 0, posn);
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException(
"Posn: " + posn + ", Size: "+ rdns.size());
}
}
/**
* Creates a name whose components consist of a suffix of the
* components in this LDAP name.
* Subsequent changes to this name do not affect the name that is
* returned and vice versa.
*
* @param posn The 0-based index of the component at which to start.
* Must be in the range [0,size()].
* @return An instance of <tt>LdapName</tt> consisting of the
* components at indexes in the range [posn,size()).
* If posn is equal to size(), an empty LDAP name is
* returned.
* @exception IndexOutOfBoundsException
* If posn is outside the specified range.
*/
public Name getSuffix(int posn) {
try {
return new LdapName(null, rdns, posn, rdns.size());
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException(
"Posn: " + posn + ", Size: "+ rdns.size());
}
}
/**
* Determines whether this LDAP name starts with a specified LDAP name
* prefix.
* A name <tt>n</tt> is a prefix if it is equal to
* <tt>getPrefix(n.size())</tt>--in other words this LDAP
* name starts with 'n'. If n is null or not a RFC2253 formatted name
* as described in the class description, false is returned.
*
* @param n The LDAP name to check.
* @return true if <tt>n</tt> is a prefix of this LDAP name,
* false otherwise.
* @see #getPrefix(int posn)
*/
public boolean startsWith(Name n) {
if (n == null) {
return false;
}
int len1 = rdns.size();
int len2 = n.size();
return (len1 >= len2 &&
matches(0, len2, n));
}
/**
* Determines whether the specified RDN sequence forms a prefix of this
* LDAP name. Returns true if this LdapName is at least as long as rdns,
* and for every position p in the range [0, rdns.size()) the component
* getRdn(p) matches rdns.get(p). Returns false otherwise. If rdns is
* null, false is returned.
*
* @param rdns The sequence of <tt>Rdn</tt>s to check.
* @return true if <tt>rdns</tt> form a prefix of this LDAP name,
* false otherwise.
*/
public boolean startsWith(List<Rdn> rdns) {
if (rdns == null) {
return false;
}
int len1 = this.rdns.size();
int len2 = rdns.size();
return (len1 >= len2 &&
doesListMatch(0, len2, rdns));
}
/**
* Determines whether this LDAP name ends with a specified
* LDAP name suffix.
* A name <tt>n</tt> is a suffix if it is equal to
* <tt>getSuffix(size()-n.size())</tt>--in other words this LDAP
* name ends with 'n'. If n is null or not a RFC2253 formatted name
* as described in the class description, false is returned.
*
* @param n The LDAP name to check.
* @return true if <tt>n</tt> is a suffix of this name, false otherwise.
* @see #getSuffix(int posn)
*/
public boolean endsWith(Name n) {
if (n == null) {
return false;
}
int len1 = rdns.size();
int len2 = n.size();
return (len1 >= len2 &&
matches(len1 - len2, len1, n));
}
/**
* Determines whether the specified RDN sequence forms a suffix of this
* LDAP name. Returns true if this LdapName is at least as long as rdns,
* and for every position p in the range [size() - rdns.size(), size())
* the component getRdn(p) matches rdns.get(p). Returns false otherwise.
* If rdns is null, false is returned.
*
* @param rdns The sequence of <tt>Rdn</tt>s to check.
* @return true if <tt>rdns</tt> form a suffix of this LDAP name,
* false otherwise.
*/
public boolean endsWith(List<Rdn> rdns) {
if (rdns == null) {
return false;
}
int len1 = this.rdns.size();
int len2 = rdns.size();
return (len1 >= len2 &&
doesListMatch(len1 - len2, len1, rdns));
}
private boolean doesListMatch(int beg, int end, List<Rdn> rdns) {
for (int i = beg; i < end; i++) {
if (!this.rdns.get(i).equals(rdns.get(i - beg))) {
return false;
}
}
return true;
}
/*
* Helper method for startsWith() and endsWith().
* Returns true if components [beg,end) match the components of "n".
* If "n" is not an LdapName, each of its components is parsed as
* the string form of an RDN.
* The following must hold: end - beg == n.size().
*/
private boolean matches(int beg, int end, Name n) {
if (n instanceof LdapName) {
LdapName ln = (LdapName) n;
return doesListMatch(beg, end, ln.rdns);
} else {
for (int i = beg; i < end; i++) {
Rdn rdn;
String rdnString = n.get(i - beg);
try {
rdn = (new Rfc2253Parser(rdnString)).parseRdn();
} catch (InvalidNameException e) {
return false;
}
if (!rdn.equals(rdns.get(i))) {
return false;
}
}
}
return true;
}
/**
* Adds the components of a name -- in order -- to the end of this name.
*
* @param suffix The non-null components to add.
* @return The updated name (not a new instance).
*
* @throws InvalidNameException if <tt>suffix</tt> is not a valid LDAP
* name, or if the addition of the components would violate the
* syntax rules of this LDAP name.
*/
public Name addAll(Name suffix) throws InvalidNameException {
return addAll(size(), suffix);
}
/**
* Adds the RDNs of a name -- in order -- to the end of this name.
*
* @param suffixRdns The non-null suffix <tt>Rdn</tt>s to add.
* @return The updated name (not a new instance).
*/
public Name addAll(List<Rdn> suffixRdns) {
return addAll(size(), suffixRdns);
}
/**
* Adds the components of a name -- in order -- at a specified position
* within this name. Components of this LDAP name at or after the
* index (if any) of the first new component are shifted up
* (away from index 0) to accommodate the new components.
*
* @param suffix The non-null components to add.
* @param posn The index at which to add the new component.
* Must be in the range [0,size()].
*
* @return The updated name (not a new instance).
*
* @throws InvalidNameException if <tt>suffix</tt> is not a valid LDAP
* name, or if the addition of the components would violate the
* syntax rules of this LDAP name.
* @throws IndexOutOfBoundsException
* If posn is outside the specified range.
*/
public Name addAll(int posn, Name suffix)
throws InvalidNameException {
unparsed = null; // no longer valid
if (suffix instanceof LdapName) {
LdapName s = (LdapName) suffix;
rdns.addAll(posn, s.rdns);
} else {
Enumeration<String> comps = suffix.getAll();
while (comps.hasMoreElements()) {
rdns.add(posn++,
(new Rfc2253Parser(comps.nextElement()).
parseRdn()));
}
}
return this;
}
/**
* Adds the RDNs of a name -- in order -- at a specified position
* within this name. RDNs of this LDAP name at or after the
* index (if any) of the first new RDN are shifted up (away from index 0) to
* accommodate the new RDNs.
*
* @param suffixRdns The non-null suffix <tt>Rdn</tt>s to add.
* @param posn The index at which to add the suffix RDNs.
* Must be in the range [0,size()].
*
* @return The updated name (not a new instance).
* @throws IndexOutOfBoundsException
* If posn is outside the specified range.
*/
public Name addAll(int posn, List<Rdn> suffixRdns) {
unparsed = null;
for (int i = 0; i < suffixRdns.size(); i++) {
Object obj = suffixRdns.get(i);
if (!(obj instanceof Rdn)) {
throw new IllegalArgumentException("Entry:" + obj +
" not a valid type;suffix list entries must be of type Rdn");
}
rdns.add(i + posn, (Rdn)obj);
}
return this;
}
/**
* Adds a single component to the end of this LDAP name.
*
* @param comp The non-null component to add.
* @return The updated LdapName, not a new instance.
* Cannot be null.
* @exception InvalidNameException If adding comp at end of the name
* would violate the name's syntax.
*/
public Name add(String comp) throws InvalidNameException {
return add(size(), comp);
}
/**
* Adds a single RDN to the end of this LDAP name.
*
* @param comp The non-null RDN to add.
*
* @return The updated LdapName, not a new instance.
* Cannot be null.
*/
public Name add(Rdn comp) {
return add(size(), comp);
}
/**
* Adds a single component at a specified position within this
* LDAP name.
* Components of this LDAP name at or after the index (if any) of the new
* component are shifted up by one (away from index 0) to accommodate
* the new component.
*
* @param comp The non-null component to add.
* @param posn The index at which to add the new component.
* Must be in the range [0,size()].
* @return The updated LdapName, not a new instance.
* Cannot be null.
* @exception IndexOutOfBoundsException
* If posn is outside the specified range.
* @exception InvalidNameException If adding comp at the
* specified position would violate the name's syntax.
*/
public Name add(int posn, String comp) throws InvalidNameException {
Rdn rdn = (new Rfc2253Parser(comp)).parseRdn();
rdns.add(posn, rdn);
unparsed = null; // no longer valid
return this;
}
/**
* Adds a single RDN at a specified position within this
* LDAP name.
* RDNs of this LDAP name at or after the index (if any) of the new
* RDN are shifted up by one (away from index 0) to accommodate
* the new RDN.
*
* @param comp The non-null RDN to add.
* @param posn The index at which to add the new RDN.
* Must be in the range [0,size()].
* @return The updated LdapName, not a new instance.
* Cannot be null.
* @exception IndexOutOfBoundsException
* If posn is outside the specified range.
*/
public Name add(int posn, Rdn comp) {
if (comp == null) {
throw new NullPointerException("Cannot set comp to null");
}
rdns.add(posn, comp);
unparsed = null; // no longer valid
return this;
}
/**
* Removes a component from this LDAP name.
* The component of this name at the specified position is removed.
* Components with indexes greater than this position (if any)
* are shifted down (toward index 0) by one.
*
* @param posn The index of the component to remove.
* Must be in the range [0,size()).
* @return The component removed (a String).
*
* @throws IndexOutOfBoundsException
* if posn is outside the specified range.
* @throws InvalidNameException if deleting the component
* would violate the syntax rules of the name.
*/
public Object remove(int posn) throws InvalidNameException {
unparsed = null; // no longer valid
return rdns.remove(posn).toString();
}
/**
* Retrieves the list of relative distinguished names.
* The contents of the list are unmodifiable.
* The indexing of RDNs in the returned list follows the numbering of
* RDNs as described in the class description.
* If the name has zero components, an empty list is returned.
*
* @return The name as a list of RDNs which are instances of
* the class {@link Rdn Rdn}.
*/
public List<Rdn> getRdns() {
return Collections.unmodifiableList(rdns);
}
/**
* Generates a new copy of this name.
* Subsequent changes to the components of this name will not
* affect the new copy, and vice versa.
*
* @return A copy of the this LDAP name.
*/
public Object clone() {
return new LdapName(unparsed, rdns, 0, rdns.size());
}
/**
* Returns a string representation of this LDAP name in a format
* defined by <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* and described in the class description. If the name has zero
* components an empty string is returned.
*
* @return The string representation of the LdapName.
*/
public String toString() {
if (unparsed != null) {
return unparsed;
}
StringBuilder builder = new StringBuilder();
int size = rdns.size();
if ((size - 1) >= 0) {
builder.append(rdns.get(size - 1));
}
for (int next = size - 2; next >= 0; next--) {
builder.append(',');
builder.append(rdns.get(next));
}
unparsed = builder.toString();
return unparsed;
}
/**
* Determines whether two LDAP names are equal.
* If obj is null or not an LDAP name, false is returned.
* <p>
* Two LDAP names are equal if each RDN in one is equal
* to the corresponding RDN in the other. This implies
* both have the same number of RDNs, and each RDN's
* equals() test against the corresponding RDN in the other
* name returns true. See {@link Rdn#equals(Object obj)}
* for a definition of RDN equality.
*
* @param obj The possibly null object to compare against.
* @return true if obj is equal to this LDAP name,
* false otherwise.
* @see #hashCode
*/
public boolean equals(Object obj) {
// check possible shortcuts
if (obj == this) {
return true;
}
if (!(obj instanceof LdapName)) {
return false;
}
LdapName that = (LdapName) obj;
if (rdns.size() != that.rdns.size()) {
return false;
}
if (unparsed != null && unparsed.equalsIgnoreCase(
that.unparsed)) {
return true;
}
// Compare RDNs one by one for equality
for (int i = 0; i < rdns.size(); i++) {
// Compare a single pair of RDNs.
Rdn rdn1 = rdns.get(i);
Rdn rdn2 = that.rdns.get(i);
if (!rdn1.equals(rdn2)) {
return false;
}
}
return true;
}
/**
* Compares this LdapName with the specified Object for order.
* Returns a negative integer, zero, or a positive integer as this
* Name is less than, equal to, or greater than the given Object.
* <p>
* If obj is null or not an instance of LdapName, ClassCastException
* is thrown.
* <p>
* Ordering of LDAP names follows the lexicographical rules for
* string comparison, with the extension that this applies to all
* the RDNs in the LDAP name. All the RDNs are lined up in their
* specified order and compared lexicographically.
* See {@link Rdn#compareTo(Object obj) Rdn.compareTo(Object obj)}
* for RDN comparison rules.
* <p>
* If this LDAP name is lexicographically lesser than obj,
* a negative number is returned.
* If this LDAP name is lexicographically greater than obj,
* a positive number is returned.
* @param obj The non-null LdapName instance to compare against.
*
* @return A negative integer, zero, or a positive integer as this Name
* is less than, equal to, or greater than the given obj.
* @exception ClassCastException if obj is null or not a LdapName.
*/
public int compareTo(Object obj) {
if (!(obj instanceof LdapName)) {
throw new ClassCastException("The obj is not a LdapName");
}
// check possible shortcuts
if (obj == this) {
return 0;
}
LdapName that = (LdapName) obj;
if (unparsed != null && unparsed.equalsIgnoreCase(
that.unparsed)) {
return 0;
}
// Compare RDNs one by one, lexicographically.
int minSize = Math.min(rdns.size(), that.rdns.size());
for (int i = 0; i < minSize; i++) {
// Compare a single pair of RDNs.
Rdn rdn1 = rdns.get(i);
Rdn rdn2 = that.rdns.get(i);
int diff = rdn1.compareTo(rdn2);
if (diff != 0) {
return diff;
}
}
return (rdns.size() - that.rdns.size()); // longer DN wins
}
/**
* Computes the hash code of this LDAP name.
* The hash code is the sum of the hash codes of individual RDNs
* of this name.
*
* @return An int representing the hash code of this name.
* @see #equals
*/
public int hashCode() {
// Sum up the hash codes of the components.
int hash = 0;
// For each RDN...
for (int i = 0; i < rdns.size(); i++) {
Rdn rdn = rdns.get(i);
hash += rdn.hashCode();
}
return hash;
}
/**
* Serializes only the unparsed DN, for compactness and to avoid
* any implementation dependency.
*
* @serialData The DN string
*/
private void writeObject(ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeObject(toString());
}
private void readObject(ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
unparsed = (String)s.readObject();
try {
parse();
} catch (InvalidNameException e) {
// shouldn't happen
throw new java.io.StreamCorruptedException(
"Invalid name: " + unparsed);
}
}
private void parse() throws InvalidNameException {
// rdns = (ArrayList<Rdn>) (new RFC2253Parser(unparsed)).getDN();
rdns = new Rfc2253Parser(unparsed).parseDn();
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.ReferralException;
import javax.naming.Context;
import javax.naming.NamingException;
import java.util.Hashtable;
/**
* This abstract class is used to represent an LDAP referral exception.
* It extends the base <tt>ReferralException</tt> by providing a
* <tt>getReferralContext()</tt> method that accepts request controls.
* LdapReferralException is an abstract class. Concrete implementations of it
* determine its synchronization and serialization properties.
*<p>
* A <tt>Control[]</tt> array passed as a parameter to
* the <tt>getReferralContext()</tt> method is owned by the caller.
* The service provider will not modify the array or keep a reference to it,
* although it may keep references to the individual <tt>Control</tt> objects
* in the array.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
* @since 1.3
*/
public abstract class LdapReferralException extends ReferralException {
/**
* Constructs a new instance of LdapReferralException using the
* explanation supplied. All other fields are set to null.
*
* @param explanation Additional detail about this exception. Can be null.
* @see java.lang.Throwable#getMessage
*/
protected LdapReferralException(String explanation) {
super(explanation);
}
/**
* Constructs a new instance of LdapReferralException.
* All fields are set to null.
*/
protected LdapReferralException() {
super();
}
/**
* Retrieves the context at which to continue the method using the
* context's environment and no controls.
* The referral context is created using the environment properties of
* the context that threw the <tt>ReferralException</tt> and no controls.
*<p>
* This method is equivalent to
*<blockquote><pre>
* getReferralContext(ctx.getEnvironment(), null);
*</pre></blockquote>
* where <tt>ctx</tt> is the context that threw the <tt>ReferralException.</tt>
*<p>
* It is overridden in this class for documentation purposes only.
* See <tt>ReferralException</tt> for how to use this method.
*
* @return The non-null context at which to continue the method.
* @exception NamingException If a naming exception was encountered.
* Call either <tt>retryReferral()</tt> or <tt>skipReferral()</tt>
* to continue processing referrals.
*/
public abstract Context getReferralContext() throws NamingException;
/**
* Retrieves the context at which to continue the method using
* environment properties and no controls.
* The referral context is created using <tt>env</tt> as its environment
* properties and no controls.
*<p>
* This method is equivalent to
*<blockquote><pre>
* getReferralContext(env, null);
*</pre></blockquote>
*<p>
* It is overridden in this class for documentation purposes only.
* See <tt>ReferralException</tt> for how to use this method.
*
* @param env The possibly null environment to use when retrieving the
* referral context. If null, no environment properties will be used.
*
* @return The non-null context at which to continue the method.
* @exception NamingException If a naming exception was encountered.
* Call either <tt>retryReferral()</tt> or <tt>skipReferral()</tt>
* to continue processing referrals.
*/
public abstract Context
getReferralContext(Hashtable<?,?> env)
throws NamingException;
/**
* Retrieves the context at which to continue the method using
* request controls and environment properties.
* Regardless of whether a referral is encountered directly during a
* context operation, or indirectly, for example, during a search
* enumeration, the referral exception should provide a context
* at which to continue the operation.
* To continue the operation, the client program should re-invoke
* the method using the same arguments as the original invocation.
*<p>
* <tt>reqCtls</tt> is used when creating the connection to the referred
* server. These controls will be used as the connection request controls for
* the context and context instances
* derived from the context.
* <tt>reqCtls</tt> will also be the context's request controls for
* subsequent context operations. See the <tt>LdapContext</tt> class
* description for details.
*<p>
* This method should be used instead of the other two overloaded forms
* when the caller needs to supply request controls for creating
* the referral context. It might need to do this, for example, when
* it needs to supply special controls relating to authentication.
*<p>
* Service provider implementors should read the "Service Provider" section
* in the <tt>LdapContext</tt> class description for implementation details.
*
* @param reqCtls The possibly null request controls to use for the new context.
* If null or the empty array means use no request controls.
* @param env The possibly null environment properties to use when
* for the new context. If null, the context is initialized with no environment
* properties.
* @return The non-null context at which to continue the method.
* @exception NamingException If a naming exception was encountered.
* Call either <tt>retryReferral()</tt> or <tt>skipReferral()</tt>
* to continue processing referrals.
*/
public abstract Context
getReferralContext(Hashtable<?,?> env,
Control[] reqCtls)
throws NamingException;
private static final long serialVersionUID = -1668992791764950804L;
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* Requests that referral and other special LDAP objects be manipulated
* as normal LDAP objects. It enables the requestor to interrogate or
* update such objects.
*<p>
* This class implements the LDAPv3 Request Control for ManageDsaIT
* as defined in
* <a href="http://www.ietf.org/rfc/rfc3296.txt">RFC 3296</a>.
*
* The control has no control value.
*
* @since 1.5
* @author Vincent Ryan
*/
final public class ManageReferralControl extends BasicControl {
/**
* The ManageReferral control's assigned object identifier
* is 2.16.840.1.113730.3.4.2.
*/
public static final String OID = "2.16.840.1.113730.3.4.2";
private static final long serialVersionUID = 3017756160149982566L;
/**
* Constructs a critical ManageReferral control.
*/
public ManageReferralControl() {
super(OID, true, null);
}
/**
* Constructs a ManageReferral control.
*
* @param criticality The control's criticality setting.
*/
public ManageReferralControl(boolean criticality) {
super(OID, criticality, null);
}
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.io.IOException;
import com.sun.jndi.ldap.Ber;
import com.sun.jndi.ldap.BerEncoder;
/**
* Requests that the results of a search operation be returned by the LDAP
* server in batches of a specified size.
* The requestor controls the rate at which batches are returned by the rate
* at which it invokes search operations.
* <p>
* The following code sample shows how the class may be used:
* <pre>{@code
*
* // Open an LDAP association
* LdapContext ctx = new InitialLdapContext();
*
* // Activate paged results
* int pageSize = 20; // 20 entries per page
* byte[] cookie = null;
* int total;
* ctx.setRequestControls(new Control[]{
* new PagedResultsControl(pageSize, Control.CRITICAL) });
*
* do {
* // Perform the search
* NamingEnumeration results =
* ctx.search("", "(objectclass=*)", new SearchControls());
*
* // Iterate over a batch of search results
* while (results != null && results.hasMore()) {
* // Display an entry
* SearchResult entry = (SearchResult)results.next();
* System.out.println(entry.getName());
* System.out.println(entry.getAttributes());
*
* // Handle the entry's response controls (if any)
* if (entry instanceof HasControls) {
* // ((HasControls)entry).getControls();
* }
* }
* // Examine the paged results control response
* Control[] controls = ctx.getResponseControls();
* if (controls != null) {
* for (int i = 0; i < controls.length; i++) {
* if (controls[i] instanceof PagedResultsResponseControl) {
* PagedResultsResponseControl prrc =
* (PagedResultsResponseControl)controls[i];
* total = prrc.getResultSize();
* cookie = prrc.getCookie();
* } else {
* // Handle other response controls (if any)
* }
* }
* }
*
* // Re-activate paged results
* ctx.setRequestControls(new Control[]{
* new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
* } while (cookie != null);
*
* // Close the LDAP association
* ctx.close();
* ...
*
* } </pre>
* <p>
* This class implements the LDAPv3 Control for paged-results as defined in
* <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
*
* The control's value has the following ASN.1 definition:
* <pre>{@code
*
* realSearchControlValue ::= SEQUENCE {
* size INTEGER (0..maxInt),
* -- requested page size from client
* -- result set size estimate from server
* cookie OCTET STRING
* }
*
* }</pre>
*
* @since 1.5
* @see PagedResultsResponseControl
* @author Vincent Ryan
*/
final public class PagedResultsControl extends BasicControl {
/**
* The paged-results control's assigned object identifier
* is 1.2.840.113556.1.4.319.
*/
public static final String OID = "1.2.840.113556.1.4.319";
private static final byte[] EMPTY_COOKIE = new byte[0];
private static final long serialVersionUID = 6684806685736844298L;
/**
* Constructs a control to set the number of entries to be returned per
* page of results.
*
* @param pageSize The number of entries to return in a page.
* @param criticality If true then the server must honor the control
* and return search results as indicated by
* pageSize or refuse to perform the search.
* If false, then the server need not honor the
* control.
* @exception IOException If an error was encountered while encoding the
* supplied arguments into a control.
*/
public PagedResultsControl(int pageSize, boolean criticality)
throws IOException {
super(OID, criticality, null);
value = setEncodedValue(pageSize, EMPTY_COOKIE);
}
/**
* Constructs a control to set the number of entries to be returned per
* page of results. The cookie is provided by the server and may be
* obtained from the paged-results response control.
* <p>
* A sequence of paged-results can be abandoned by setting the pageSize
* to zero and setting the cookie to the last cookie received from the
* server.
*
* @param pageSize The number of entries to return in a page.
* @param cookie A possibly null server-generated cookie.
* @param criticality If true then the server must honor the control
* and return search results as indicated by
* pageSize or refuse to perform the search.
* If false, then the server need not honor the
* control.
* @exception IOException If an error was encountered while encoding the
* supplied arguments into a control.
*/
public PagedResultsControl(int pageSize, byte[] cookie,
boolean criticality) throws IOException {
super(OID, criticality, null);
if (cookie == null) {
cookie = EMPTY_COOKIE;
}
value = setEncodedValue(pageSize, cookie);
}
/*
* Encodes the paged-results control's value using ASN.1 BER.
* The result includes the BER tag and length for the control's value but
* does not include the control's object identifier and criticality setting.
*
* @param pageSize The number of entries to return in a page.
* @param cookie A non-null server-generated cookie.
* @return A possibly null byte array representing the ASN.1 BER encoded
* value of the LDAP paged-results control.
* @exception IOException If a BER encoding error occurs.
*/
private byte[] setEncodedValue(int pageSize, byte[] cookie)
throws IOException {
// build the ASN.1 encoding
BerEncoder ber = new BerEncoder(10 + cookie.length);
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
ber.encodeInt(pageSize);
ber.encodeOctetString(cookie, Ber.ASN_OCTET_STR);
ber.endSeq();
return ber.getTrimmedBuf();
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.io.IOException;
import com.sun.jndi.ldap.Ber;
import com.sun.jndi.ldap.BerDecoder;
/**
* Indicates the end of a batch of search results.
* Contains an estimate of the total number of entries in the result set
* and an opaque cookie. The cookie must be supplied to the next search
* operation in order to get the next batch of results.
* <p>
* The code sample in {@link PagedResultsControl} shows how this class may
* be used.
* <p>
* This class implements the LDAPv3 Response Control for
* paged-results as defined in
* <a href="http://www.ietf.org/rfc/rfc2696">RFC 2696</a>.
*
* The control's value has the following ASN.1 definition:
* <pre>
*
* realSearchControlValue ::= SEQUENCE {
* size INTEGER (0..maxInt),
* -- requested page size from client
* -- result set size estimate from server
* cookie OCTET STRING
* }
*
* </pre>
*
* @since 1.5
* @see PagedResultsControl
* @author Vincent Ryan
*/
final public class PagedResultsResponseControl extends BasicControl {
/**
* The paged-results response control's assigned object identifier
* is 1.2.840.113556.1.4.319.
*/
public static final String OID = "1.2.840.113556.1.4.319";
private static final long serialVersionUID = -8819778744844514666L;
/**
* An estimate of the number of entries in the search result.
*
* @serial
*/
private int resultSize;
/**
* A server-generated cookie.
*
* @serial
*/
private byte[] cookie;
/**
* Constructs a paged-results response control.
*
* @param id The control's object identifier string.
* @param criticality The control's criticality.
* @param value The control's ASN.1 BER encoded value.
* It is not cloned - any changes to value
* will affect the contents of the control.
* @exception IOException If an error was encountered while decoding
* the control's value.
*/
public PagedResultsResponseControl(String id, boolean criticality,
byte[] value) throws IOException {
super(id, criticality, value);
// decode value
BerDecoder ber = new BerDecoder(value, 0, value.length);
ber.parseSeq(null);
resultSize = ber.parseInt();
cookie = ber.parseOctetString(Ber.ASN_OCTET_STR, null);
}
/**
* Retrieves (an estimate of) the number of entries in the search result.
*
* @return The number of entries in the search result, or zero if unknown.
*/
public int getResultSize() {
return resultSize;
}
/**
* Retrieves the server-generated cookie. Null is returned when there are
* no more entries for the server to return.
*
* @return A possibly null server-generated cookie. It is not cloned - any
* changes to the cookie will update the control's state and thus
* are not recommended.
*/
public byte[] getCookie() {
if (cookie.length == 0) {
return null;
} else {
return cookie;
}
}
}

View File

@@ -0,0 +1,759 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Collections;
import javax.naming.InvalidNameException;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* This class represents a relative distinguished name, or RDN, which is a
* component of a distinguished name as specified by
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
* An example of an RDN is "OU=Sales+CN=J.Smith". In this example,
* the RDN consist of multiple attribute type/value pairs. The
* RDN is parsed as described in the class description for
* {@link javax.naming.ldap.LdapName <tt>LdapName</tt>}.
* <p>
* The Rdn class represents an RDN as attribute type/value mappings,
* which can be viewed using
* {@link javax.naming.directory.Attributes Attributes}.
* In addition, it contains convenience methods that allow easy retrieval
* of type and value when the Rdn consist of a single type/value pair,
* which is how it appears in a typical usage.
* It also contains helper methods that allow escaping of the unformatted
* attribute value and unescaping of the value formatted according to the
* escaping syntax defined in RFC2253. For methods that take or return
* attribute value as an Object, the value is either a String
* (in unescaped form) or a byte array.
* <p>
* <code>Rdn</code> will properly parse all valid RDNs, but
* does not attempt to detect all possible violations when parsing
* invalid RDNs. It is "generous" in accepting invalid RDNs.
* The "validity" of a name is determined ultimately when it
* is supplied to an LDAP server, which may accept or
* reject the name based on factors such as its schema information
* and interoperability considerations.
*
* <p>
* The following code example shows how to construct an Rdn using the
* constructor that takes type and value as arguments:
* <pre>
* Rdn rdn = new Rdn("cn", "Juicy, Fruit");
* System.out.println(rdn.toString());
* </pre>
* The last line will print <tt>cn=Juicy\, Fruit</tt>. The
* {@link #unescapeValue(String) <tt>unescapeValue()</tt>} method can be
* used to unescape the escaped comma resulting in the original
* value <tt>"Juicy, Fruit"</tt>. The {@link #escapeValue(Object)
* <tt>escapeValue()</tt>} method adds the escape back preceding the comma.
* <p>
* This class can be instantiated by a string representation
* of the RDN defined in RFC 2253 as shown in the following code example:
* <pre>
* Rdn rdn = new Rdn("cn=Juicy\\, Fruit");
* System.out.println(rdn.toString());
* </pre>
* The last line will print <tt>cn=Juicy\, Fruit</tt>.
* <p>
* Concurrent multithreaded read-only access of an instance of
* <tt>Rdn</tt> need not be synchronized.
* <p>
* Unless otherwise noted, the behavior of passing a null argument
* to a constructor or method in this class will cause NullPointerException
* to be thrown.
*
* @since 1.5
*/
public class Rdn implements Serializable, Comparable<Object> {
private transient ArrayList<RdnEntry> entries;
// The common case.
private static final int DEFAULT_SIZE = 1;
private static final long serialVersionUID = -5994465067210009656L;
/**
* Constructs an Rdn from the given attribute set. See
* {@link javax.naming.directory.Attributes Attributes}.
* <p>
* The string attribute values are not interpreted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is, the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param attrSet The non-null and non-empty attributes containing
* type/value mappings.
* @throws InvalidNameException If contents of <tt>attrSet</tt> cannot
* be used to construct a valid RDN.
*/
public Rdn(Attributes attrSet) throws InvalidNameException {
if (attrSet.size() == 0) {
throw new InvalidNameException("Attributes cannot be empty");
}
entries = new ArrayList<>(attrSet.size());
NamingEnumeration<? extends Attribute> attrs = attrSet.getAll();
try {
for (int nEntries = 0; attrs.hasMore(); nEntries++) {
RdnEntry entry = new RdnEntry();
Attribute attr = attrs.next();
entry.type = attr.getID();
entry.value = attr.get();
entries.add(nEntries, entry);
}
} catch (NamingException e) {
InvalidNameException e2 = new InvalidNameException(
e.getMessage());
e2.initCause(e);
throw e2;
}
sort(); // arrange entries for comparison
}
/**
* Constructs an Rdn from the given string.
* This constructor takes a string formatted according to the rules
* defined in <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* and described in the class description for
* {@link javax.naming.ldap.LdapName}.
*
* @param rdnString The non-null and non-empty RFC2253 formatted string.
* @throws InvalidNameException If a syntax error occurs during
* parsing of the rdnString.
*/
public Rdn(String rdnString) throws InvalidNameException {
entries = new ArrayList<>(DEFAULT_SIZE);
(new Rfc2253Parser(rdnString)).parseRdn(this);
}
/**
* Constructs an Rdn from the given <tt>rdn</tt>.
* The contents of the <tt>rdn</tt> are simply copied into the newly
* created Rdn.
* @param rdn The non-null Rdn to be copied.
*/
public Rdn(Rdn rdn) {
entries = new ArrayList<>(rdn.entries.size());
entries.addAll(rdn.entries);
}
/**
* Constructs an Rdn from the given attribute type and
* value.
* The string attribute values are not interpreted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is, the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param type The non-null and non-empty string attribute type.
* @param value The non-null and non-empty attribute value.
* @throws InvalidNameException If type/value cannot be used to
* construct a valid RDN.
* @see #toString()
*/
public Rdn(String type, Object value) throws InvalidNameException {
if (value == null) {
throw new NullPointerException("Cannot set value to null");
}
if (type.equals("") || isEmptyValue(value)) {
throw new InvalidNameException(
"type or value cannot be empty, type:" + type +
" value:" + value);
}
entries = new ArrayList<>(DEFAULT_SIZE);
put(type, value);
}
private boolean isEmptyValue(Object val) {
return ((val instanceof String) && val.equals("")) ||
((val instanceof byte[]) && (((byte[]) val).length == 0));
}
// An empty constructor used by the parser
Rdn() {
entries = new ArrayList<>(DEFAULT_SIZE);
}
/*
* Adds the given attribute type and value to this Rdn.
* The string attribute values are not interpreted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param type The non-null and non-empty string attribute type.
* @param value The non-null and non-empty attribute value.
* @return The updated Rdn, not a new one. Cannot be null.
* @see #toString()
*/
Rdn put(String type, Object value) {
// create new Entry
RdnEntry newEntry = new RdnEntry();
newEntry.type = type;
if (value instanceof byte[]) { // clone the byte array
newEntry.value = ((byte[]) value).clone();
} else {
newEntry.value = value;
}
entries.add(newEntry);
return this;
}
void sort() {
if (entries.size() > 1) {
Collections.sort(entries);
}
}
/**
* Retrieves one of this Rdn's value.
* This is a convenience method for obtaining the value,
* when the RDN contains a single type and value mapping,
* which is the common RDN usage.
* <p>
* For a multi-valued RDN, this method returns value corresponding
* to the type returned by {@link #getType() getType()} method.
*
* @return The non-null attribute value.
*/
public Object getValue() {
return entries.get(0).getValue();
}
/**
* Retrieves one of this Rdn's type.
* This is a convenience method for obtaining the type,
* when the RDN contains a single type and value mapping,
* which is the common RDN usage.
* <p>
* For a multi-valued RDN, the type/value pairs have
* no specific order defined on them. In that case, this method
* returns type of one of the type/value pairs.
* The {@link #getValue() getValue()} method returns the
* value corresponding to the type returned by this method.
*
* @return The non-null attribute type.
*/
public String getType() {
return entries.get(0).getType();
}
/**
* Returns this Rdn as a string represented in a format defined by
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> and described
* in the class description for {@link javax.naming.ldap.LdapName LdapName}.
*
* @return The string representation of the Rdn.
*/
public String toString() {
StringBuilder builder = new StringBuilder();
int size = entries.size();
if (size > 0) {
builder.append(entries.get(0));
}
for (int next = 1; next < size; next++) {
builder.append('+');
builder.append(entries.get(next));
}
return builder.toString();
}
/**
* Compares this Rdn with the specified Object for order.
* Returns a negative integer, zero, or a positive integer as this
* Rdn is less than, equal to, or greater than the given Object.
* <p>
* If obj is null or not an instance of Rdn, ClassCastException
* is thrown.
* <p>
* The attribute type and value pairs of the RDNs are lined up
* against each other and compared lexicographically. The order of
* components in multi-valued Rdns (such as "ou=Sales+cn=Bob") is not
* significant.
*
* @param obj The non-null object to compare against.
* @return A negative integer, zero, or a positive integer as this Rdn
* is less than, equal to, or greater than the given Object.
* @exception ClassCastException if obj is null or not a Rdn.
*/
public int compareTo(Object obj) {
if (!(obj instanceof Rdn)) {
throw new ClassCastException("The obj is not a Rdn");
}
if (obj == this) {
return 0;
}
Rdn that = (Rdn) obj;
int minSize = Math.min(entries.size(), that.entries.size());
for (int i = 0; i < minSize; i++) {
// Compare a single pair of type/value pairs.
int diff = entries.get(i).compareTo(that.entries.get(i));
if (diff != 0) {
return diff;
}
}
return (entries.size() - that.entries.size()); // longer RDN wins
}
/**
* Compares the specified Object with this Rdn for equality.
* Returns true if the given object is also a Rdn and the two Rdns
* represent the same attribute type and value mappings. The order of
* components in multi-valued Rdns (such as "ou=Sales+cn=Bob") is not
* significant.
* <p>
* Type and value equality matching is done as below:
* <ul>
* <li> The types are compared for equality with their case ignored.
* <li> String values with different but equivalent usage of quoting,
* escaping, or UTF8-hex-encoding are considered equal.
* The case of the values is ignored during the comparison.
* </ul>
* <p>
* If obj is null or not an instance of Rdn, false is returned.
* <p>
* @param obj object to be compared for equality with this Rdn.
* @return true if the specified object is equal to this Rdn.
* @see #hashCode()
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Rdn)) {
return false;
}
Rdn that = (Rdn) obj;
if (entries.size() != that.size()) {
return false;
}
for (int i = 0; i < entries.size(); i++) {
if (!entries.get(i).equals(that.entries.get(i))) {
return false;
}
}
return true;
}
/**
* Returns the hash code of this RDN. Two RDNs that are
* equal (according to the equals method) will have the same
* hash code.
*
* @return An int representing the hash code of this Rdn.
* @see #equals
*/
public int hashCode() {
// Sum up the hash codes of the components.
int hash = 0;
// For each type/value pair...
for (int i = 0; i < entries.size(); i++) {
hash += entries.get(i).hashCode();
}
return hash;
}
/**
* Retrieves the {@link javax.naming.directory.Attributes Attributes}
* view of the type/value mappings contained in this Rdn.
*
* @return The non-null attributes containing the type/value
* mappings of this Rdn.
*/
public Attributes toAttributes() {
Attributes attrs = new BasicAttributes(true);
for (int i = 0; i < entries.size(); i++) {
RdnEntry entry = entries.get(i);
Attribute attr = attrs.put(entry.getType(), entry.getValue());
if (attr != null) {
attr.add(entry.getValue());
attrs.put(attr);
}
}
return attrs;
}
private static class RdnEntry implements Comparable<RdnEntry> {
private String type;
private Object value;
// If non-null, a cannonical representation of the value suitable
// for comparison using String.compareTo()
private String comparable = null;
String getType() {
return type;
}
Object getValue() {
return value;
}
public int compareTo(RdnEntry that) {
int diff = type.compareToIgnoreCase(that.type);
if (diff != 0) {
return diff;
}
if (value.equals(that.value)) { // try shortcut
return 0;
}
return getValueComparable().compareTo(
that.getValueComparable());
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof RdnEntry)) {
return false;
}
// Any change here must be reflected in hashCode()
RdnEntry that = (RdnEntry) obj;
return (type.equalsIgnoreCase(that.type)) &&
(getValueComparable().equals(
that.getValueComparable()));
}
public int hashCode() {
return (type.toUpperCase(Locale.ENGLISH).hashCode() +
getValueComparable().hashCode());
}
public String toString() {
return type + "=" + escapeValue(value);
}
private String getValueComparable() {
if (comparable != null) {
return comparable; // return cached result
}
// cache result
if (value instanceof byte[]) {
comparable = escapeBinaryValue((byte[]) value);
} else {
comparable = ((String) value).toUpperCase(Locale.ENGLISH);
}
return comparable;
}
}
/**
* Retrieves the number of attribute type/value pairs in this Rdn.
* @return The non-negative number of type/value pairs in this Rdn.
*/
public int size() {
return entries.size();
}
/**
* Given the value of an attribute, returns a string escaped according
* to the rules specified in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
* <p>
* For example, if the val is "Sue, Grabbit and Runn", the escaped
* value returned by this method is "Sue\, Grabbit and Runn".
* <p>
* A string value is represented as a String and binary value
* as a byte array.
*
* @param val The non-null object to be escaped.
* @return Escaped string value.
* @throws ClassCastException if val is is not a String or byte array.
*/
public static String escapeValue(Object val) {
return (val instanceof byte[])
? escapeBinaryValue((byte[])val)
: escapeStringValue((String)val);
}
/*
* Given the value of a string-valued attribute, returns a
* string suitable for inclusion in a DN. This is accomplished by
* using backslash (\) to escape the following characters:
* leading and trailing whitespace
* , = + < > # ; " \
*/
private static final String escapees = ",=+<>#;\"\\";
private static String escapeStringValue(String val) {
char[] chars = val.toCharArray();
StringBuilder builder = new StringBuilder(2 * val.length());
// Find leading and trailing whitespace.
int lead; // index of first char that is not leading whitespace
for (lead = 0; lead < chars.length; lead++) {
if (!isWhitespace(chars[lead])) {
break;
}
}
int trail; // index of last char that is not trailing whitespace
for (trail = chars.length - 1; trail >= 0; trail--) {
if (!isWhitespace(chars[trail])) {
break;
}
}
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if ((i < lead) || (i > trail) || (escapees.indexOf(c) >= 0)) {
builder.append('\\');
}
builder.append(c);
}
return builder.toString();
}
/*
* Given the value of a binary attribute, returns a string
* suitable for inclusion in a DN (such as "#CEB1DF80").
* TBD: This method should actually generate the ber encoding
* of the binary value
*/
private static String escapeBinaryValue(byte[] val) {
StringBuilder builder = new StringBuilder(1 + 2 * val.length);
builder.append("#");
for (int i = 0; i < val.length; i++) {
byte b = val[i];
builder.append(Character.forDigit(0xF & (b >>> 4), 16));
builder.append(Character.forDigit(0xF & b, 16));
}
return builder.toString();
}
/**
* Given an attribute value string formated according to the rules
* specified in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>,
* returns the unformated value. Escapes and quotes are
* stripped away, and hex-encoded UTF-8 is converted to equivalent
* UTF-16 characters. Returns a string value as a String, and a
* binary value as a byte array.
* <p>
* Legal and illegal values are defined in RFC 2253.
* This method is generous in accepting the values and does not
* catch all illegal values.
* Therefore, passing in an illegal value might not necessarily
* trigger an <tt>IllegalArgumentException</tt>.
*
* @param val The non-null string to be unescaped.
* @return Unescaped value.
* @throws IllegalArgumentException When an Illegal value
* is provided.
*/
public static Object unescapeValue(String val) {
char[] chars = val.toCharArray();
int beg = 0;
int end = chars.length;
// Trim off leading and trailing whitespace.
while ((beg < end) && isWhitespace(chars[beg])) {
++beg;
}
while ((beg < end) && isWhitespace(chars[end - 1])) {
--end;
}
// Add back the trailing whitespace with a preceding '\'
// (escaped or unescaped) that was taken off in the above
// loop. Whether or not to retain this whitespace is decided below.
if (end != chars.length &&
(beg < end) &&
chars[end - 1] == '\\') {
end++;
}
if (beg >= end) {
return "";
}
if (chars[beg] == '#') {
// Value is binary (eg: "#CEB1DF80").
return decodeHexPairs(chars, ++beg, end);
}
// Trim off quotes.
if ((chars[beg] == '\"') && (chars[end - 1] == '\"')) {
++beg;
--end;
}
StringBuilder builder = new StringBuilder(end - beg);
int esc = -1; // index of the last escaped character
for (int i = beg; i < end; i++) {
if ((chars[i] == '\\') && (i + 1 < end)) {
if (!Character.isLetterOrDigit(chars[i + 1])) {
++i; // skip backslash
builder.append(chars[i]); // snarf escaped char
esc = i;
} else {
// Convert hex-encoded UTF-8 to 16-bit chars.
byte[] utf8 = getUtf8Octets(chars, i, end);
if (utf8.length > 0) {
try {
builder.append(new String(utf8, "UTF8"));
} catch (java.io.UnsupportedEncodingException e) {
// shouldn't happen
}
i += utf8.length * 3 - 1;
} else { // no utf8 bytes available, invalid DN
// '/' has no meaning, throw exception
throw new IllegalArgumentException(
"Not a valid attribute string value:" +
val + ",improper usage of backslash");
}
}
} else {
builder.append(chars[i]); // snarf unescaped char
}
}
// Get rid of the unescaped trailing whitespace with the
// preceding '\' character that was previously added back.
int len = builder.length();
if (isWhitespace(builder.charAt(len - 1)) && esc != (end - 1)) {
builder.setLength(len - 1);
}
return builder.toString();
}
/*
* Given an array of chars (with starting and ending indexes into it)
* representing bytes encoded as hex-pairs (such as "CEB1DF80"),
* returns a byte array containing the decoded bytes.
*/
private static byte[] decodeHexPairs(char[] chars, int beg, int end) {
byte[] bytes = new byte[(end - beg) / 2];
for (int i = 0; beg + 1 < end; i++) {
int hi = Character.digit(chars[beg], 16);
int lo = Character.digit(chars[beg + 1], 16);
if (hi < 0 || lo < 0) {
break;
}
bytes[i] = (byte)((hi<<4) + lo);
beg += 2;
}
if (beg != end) {
throw new IllegalArgumentException(
"Illegal attribute value: " + new String(chars));
}
return bytes;
}
/*
* Given an array of chars (with starting and ending indexes into it),
* finds the largest prefix consisting of hex-encoded UTF-8 octets,
* and returns a byte array containing the corresponding UTF-8 octets.
*
* Hex-encoded UTF-8 octets look like this:
* \03\B1\DF\80
*/
private static byte[] getUtf8Octets(char[] chars, int beg, int end) {
byte[] utf8 = new byte[(end - beg) / 3]; // allow enough room
int len = 0; // index of first unused byte in utf8
while ((beg + 2 < end) &&
(chars[beg++] == '\\')) {
int hi = Character.digit(chars[beg++], 16);
int lo = Character.digit(chars[beg++], 16);
if (hi < 0 || lo < 0) {
break;
}
utf8[len++] = (byte)((hi<<4) + lo);
}
if (len == utf8.length) {
return utf8;
} else {
byte[] res = new byte[len];
System.arraycopy(utf8, 0, res, 0, len);
return res;
}
}
/*
* Best guess as to what RFC 2253 means by "whitespace".
*/
private static boolean isWhitespace(char c) {
return (c == ' ' || c == '\r');
}
/**
* Serializes only the unparsed RDN, for compactness and to avoid
* any implementation dependency.
*
* @serialData The RDN string
*/
private void writeObject(ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeObject(toString());
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
entries = new ArrayList<>(DEFAULT_SIZE);
String unparsed = (String) s.readObject();
try {
(new Rfc2253Parser(unparsed)).parseRdn(this);
} catch (InvalidNameException e) {
// shouldn't happen
throw new java.io.StreamCorruptedException(
"Invalid name: " + unparsed);
}
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.util.List;
import java.util.ArrayList;
import javax.naming.InvalidNameException;
/*
* RFC2253Parser implements a recursive descent parser for a single DN.
*/
final class Rfc2253Parser {
private final String name; // DN being parsed
private final char[] chars; // characters in LDAP name being parsed
private final int len; // length of "chars"
private int cur = 0; // index of first unconsumed char in "chars"
/*
* Given an LDAP DN in string form, returns a parser for it.
*/
Rfc2253Parser(String name) {
this.name = name;
len = name.length();
chars = name.toCharArray();
}
/*
* Parses the DN, returning a List of its RDNs.
*/
// public List<Rdn> getDN() throws InvalidNameException {
List<Rdn> parseDn() throws InvalidNameException {
cur = 0;
// ArrayList<Rdn> rdns =
// new ArrayList<Rdn>(len / 3 + 10); // leave room for growth
ArrayList<Rdn> rdns =
new ArrayList<>(len / 3 + 10); // leave room for growth
if (len == 0) {
return rdns;
}
rdns.add(doParse(new Rdn()));
while (cur < len) {
if (chars[cur] == ',' || chars[cur] == ';') {
++cur;
rdns.add(0, doParse(new Rdn()));
} else {
throw new InvalidNameException("Invalid name: " + name);
}
}
return rdns;
}
/*
* Parses the DN, if it is known to contain a single RDN.
*/
Rdn parseRdn() throws InvalidNameException {
return parseRdn(new Rdn());
}
/*
* Parses the DN, if it is known to contain a single RDN.
*/
Rdn parseRdn(Rdn rdn) throws InvalidNameException {
rdn = doParse(rdn);
if (cur < len) {
throw new InvalidNameException("Invalid RDN: " + name);
}
return rdn;
}
/*
* Parses the next RDN and returns it. Throws an exception if
* none is found. Leading and trailing whitespace is consumed.
*/
private Rdn doParse(Rdn rdn) throws InvalidNameException {
while (cur < len) {
consumeWhitespace();
String attrType = parseAttrType();
consumeWhitespace();
if (cur >= len || chars[cur] != '=') {
throw new InvalidNameException("Invalid name: " + name);
}
++cur; // consume '='
consumeWhitespace();
String value = parseAttrValue();
consumeWhitespace();
rdn.put(attrType, Rdn.unescapeValue(value));
if (cur >= len || chars[cur] != '+') {
break;
}
++cur; // consume '+'
}
rdn.sort();
return rdn;
}
/*
* Returns the attribute type that begins at the next unconsumed
* char. No leading whitespace is expected.
* This routine is more generous than RFC 2253. It accepts
* attribute types composed of any nonempty combination of Unicode
* letters, Unicode digits, '.', '-', and internal space characters.
*/
private String parseAttrType() throws InvalidNameException {
final int beg = cur;
while (cur < len) {
char c = chars[cur];
if (Character.isLetterOrDigit(c) ||
c == '.' ||
c == '-' ||
c == ' ') {
++cur;
} else {
break;
}
}
// Back out any trailing spaces.
while ((cur > beg) && (chars[cur - 1] == ' ')) {
--cur;
}
if (beg == cur) {
throw new InvalidNameException("Invalid name: " + name);
}
return new String(chars, beg, cur - beg);
}
/*
* Returns the attribute value that begins at the next unconsumed
* char. No leading whitespace is expected.
*/
private String parseAttrValue() throws InvalidNameException {
if (cur < len && chars[cur] == '#') {
return parseBinaryAttrValue();
} else if (cur < len && chars[cur] == '"') {
return parseQuotedAttrValue();
} else {
return parseStringAttrValue();
}
}
private String parseBinaryAttrValue() throws InvalidNameException {
final int beg = cur;
++cur; // consume '#'
while ((cur < len) &&
Character.isLetterOrDigit(chars[cur])) {
++cur;
}
return new String(chars, beg, cur - beg);
}
private String parseQuotedAttrValue() throws InvalidNameException {
final int beg = cur;
++cur; // consume '"'
while ((cur < len) && chars[cur] != '"') {
if (chars[cur] == '\\') {
++cur; // consume backslash, then what follows
}
++cur;
}
if (cur >= len) { // no closing quote
throw new InvalidNameException("Invalid name: " + name);
}
++cur; // consume closing quote
return new String(chars, beg, cur - beg);
}
private String parseStringAttrValue() throws InvalidNameException {
final int beg = cur;
int esc = -1; // index of the most recently escaped character
while ((cur < len) && !atTerminator()) {
if (chars[cur] == '\\') {
++cur; // consume backslash, then what follows
esc = cur;
}
++cur;
}
if (cur > len) { // 'twas backslash followed by nothing
throw new InvalidNameException("Invalid name: " + name);
}
// Trim off (unescaped) trailing whitespace.
int end;
for (end = cur; end > beg; end--) {
if (!isWhitespace(chars[end - 1]) || (esc == end - 1)) {
break;
}
}
return new String(chars, beg, end - beg);
}
private void consumeWhitespace() {
while ((cur < len) && isWhitespace(chars[cur])) {
++cur;
}
}
/*
* Returns true if next unconsumed character is one that terminates
* a string attribute value.
*/
private boolean atTerminator() {
return (cur < len &&
(chars[cur] == ',' ||
chars[cur] == ';' ||
chars[cur] == '+'));
}
/*
* Best guess as to what RFC 2253 means by "whitespace".
*/
private static boolean isWhitespace(char c) {
return (c == ' ' || c == '\r');
}
}

View File

@@ -0,0 +1,222 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.io.IOException;
import com.sun.jndi.ldap.Ber;
import com.sun.jndi.ldap.BerEncoder;
/**
* Requests that the results of a search operation be sorted by the LDAP server
* before being returned.
* The sort criteria are specified using an ordered list of one or more sort
* keys, with associated sort parameters.
* Search results are sorted at the LDAP server according to the parameters
* supplied in the sort control and then returned to the requestor. If sorting
* is not supported at the server (and the sort control is marked as critical)
* then the search operation is not performed and an error is returned.
* <p>
* The following code sample shows how the class may be used:
* <pre>{@code
*
* // Open an LDAP association
* LdapContext ctx = new InitialLdapContext();
*
* // Activate sorting
* String sortKey = "cn";
* ctx.setRequestControls(new Control[]{
* new SortControl(sortKey, Control.CRITICAL) });
*
* // Perform a search
* NamingEnumeration results =
* ctx.search("", "(objectclass=*)", new SearchControls());
*
* // Iterate over search results
* while (results != null && results.hasMore()) {
* // Display an entry
* SearchResult entry = (SearchResult)results.next();
* System.out.println(entry.getName());
* System.out.println(entry.getAttributes());
*
* // Handle the entry's response controls (if any)
* if (entry instanceof HasControls) {
* // ((HasControls)entry).getControls();
* }
* }
* // Examine the sort control response
* Control[] controls = ctx.getResponseControls();
* if (controls != null) {
* for (int i = 0; i < controls.length; i++) {
* if (controls[i] instanceof SortResponseControl) {
* SortResponseControl src = (SortResponseControl)controls[i];
* if (! src.isSorted()) {
* throw src.getException();
* }
* } else {
* // Handle other response controls (if any)
* }
* }
* }
*
* // Close the LDAP association
* ctx.close();
* ...
*
* }</pre>
* <p>
* This class implements the LDAPv3 Request Control for server-side sorting
* as defined in
* <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
*
* The control's value has the following ASN.1 definition:
* <pre>
*
* SortKeyList ::= SEQUENCE OF SEQUENCE {
* attributeType AttributeDescription,
* orderingRule [0] MatchingRuleId OPTIONAL,
* reverseOrder [1] BOOLEAN DEFAULT FALSE }
*
* </pre>
*
* @since 1.5
* @see SortKey
* @see SortResponseControl
* @author Vincent Ryan
*/
final public class SortControl extends BasicControl {
/**
* The server-side sort control's assigned object identifier
* is 1.2.840.113556.1.4.473.
*/
public static final String OID = "1.2.840.113556.1.4.473";
private static final long serialVersionUID = -1965961680233330744L;
/**
* Constructs a control to sort on a single attribute in ascending order.
* Sorting will be performed using the ordering matching rule defined
* for use with the specified attribute.
*
* @param sortBy An attribute ID to sort by.
* @param criticality If true then the server must honor the control
* and return the search results sorted as
* requested or refuse to perform the search.
* If false, then the server need not honor the
* control.
* @exception IOException If an error was encountered while encoding the
* supplied arguments into a control.
*/
public SortControl(String sortBy, boolean criticality) throws IOException {
super(OID, criticality, null);
super.value = setEncodedValue(new SortKey[]{ new SortKey(sortBy) });
}
/**
* Constructs a control to sort on a list of attributes in ascending order.
* Sorting will be performed using the ordering matching rule defined
* for use with each of the specified attributes.
*
* @param sortBy A non-null list of attribute IDs to sort by.
* The list is in order of highest to lowest sort key
* precedence.
* @param criticality If true then the server must honor the control
* and return the search results sorted as
* requested or refuse to perform the search.
* If false, then the server need not honor the
* control.
* @exception IOException If an error was encountered while encoding the
* supplied arguments into a control.
*/
public SortControl(String[] sortBy, boolean criticality)
throws IOException {
super(OID, criticality, null);
SortKey[] sortKeys = new SortKey[sortBy.length];
for (int i = 0; i < sortBy.length; i++) {
sortKeys[i] = new SortKey(sortBy[i]);
}
super.value = setEncodedValue(sortKeys);
}
/**
* Constructs a control to sort on a list of sort keys.
* Each sort key specifies the sort order and ordering matching rule to use.
*
* @param sortBy A non-null list of keys to sort by.
* The list is in order of highest to lowest sort key
* precedence.
* @param criticality If true then the server must honor the control
* and return the search results sorted as
* requested or refuse to perform the search.
* If false, then the server need not honor the
* control.
* @exception IOException If an error was encountered while encoding the
* supplied arguments into a control.
*/
public SortControl(SortKey[] sortBy, boolean criticality)
throws IOException {
super(OID, criticality, null);
super.value = setEncodedValue(sortBy);
}
/*
* Encodes the sort control's value using ASN.1 BER.
* The result includes the BER tag and length for the control's value but
* does not include the control's object identifer and criticality setting.
*
* @param sortKeys A non-null list of keys to sort by.
* @return A possibly null byte array representing the ASN.1 BER encoded
* value of the sort control.
* @exception IOException If a BER encoding error occurs.
*/
private byte[] setEncodedValue(SortKey[] sortKeys) throws IOException {
// build the ASN.1 BER encoding
BerEncoder ber = new BerEncoder(30 * sortKeys.length + 10);
String matchingRule;
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
for (int i = 0; i < sortKeys.length; i++) {
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
ber.encodeString(sortKeys[i].getAttributeID(), true); // v3
if ((matchingRule = sortKeys[i].getMatchingRuleID()) != null) {
ber.encodeString(matchingRule, (Ber.ASN_CONTEXT | 0), true);
}
if (! sortKeys[i].isAscending()) {
ber.encodeBoolean(true, (Ber.ASN_CONTEXT | 1));
}
ber.endSeq();
}
ber.endSeq();
return ber.getTrimmedBuf();
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* A sort key and its associated sort parameters.
* This class implements a sort key which is used by the LDAPv3
* Control for server-side sorting of search results as defined in
* <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
*
* @since 1.5
* @see SortControl
* @author Vincent Ryan
*/
public class SortKey {
/*
* The ID of the attribute to sort by.
*/
private String attrID;
/*
* The sort order. Ascending order, by default.
*/
private boolean reverseOrder = false;
/*
* The ID of the matching rule to use for ordering attribute values.
*/
private String matchingRuleID = null;
/**
* Creates the default sort key for an attribute. Entries will be sorted
* according to the specified attribute in ascending order using the
* ordering matching rule defined for use with that attribute.
*
* @param attrID The non-null ID of the attribute to be used as a sort
* key.
*/
public SortKey(String attrID) {
this.attrID = attrID;
}
/**
* Creates a sort key for an attribute. Entries will be sorted according to
* the specified attribute in the specified sort order and using the
* specified matching rule, if supplied.
*
* @param attrID The non-null ID of the attribute to be used as
* a sort key.
* @param ascendingOrder If true then entries are arranged in ascending
* order. Otherwise there are arranged in
* descending order.
* @param matchingRuleID The possibly null ID of the matching rule to
* use to order the attribute values. If not
* specified then the ordering matching rule
* defined for the sort key attribute is used.
*/
public SortKey(String attrID, boolean ascendingOrder,
String matchingRuleID) {
this.attrID = attrID;
reverseOrder = (! ascendingOrder);
this.matchingRuleID = matchingRuleID;
}
/**
* Retrieves the attribute ID of the sort key.
*
* @return The non-null Attribute ID of the sort key.
*/
public String getAttributeID() {
return attrID;
}
/**
* Determines the sort order.
*
* @return true if the sort order is ascending, false if descending.
*/
public boolean isAscending() {
return (! reverseOrder);
}
/**
* Retrieves the matching rule ID used to order the attribute values.
*
* @return The possibly null matching rule ID. If null then the
* ordering matching rule defined for the sort key attribute
* is used.
*/
public String getMatchingRuleID() {
return matchingRuleID;
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.io.IOException;
import javax.naming.*;
import javax.naming.directory.*;
import com.sun.jndi.ldap.Ber;
import com.sun.jndi.ldap.BerDecoder;
import com.sun.jndi.ldap.LdapCtx;
/**
* Indicates whether the requested sort of search results was successful or not.
* When the result code indicates success then the results have been sorted as
* requested. Otherwise the sort was unsuccessful and additional details
* regarding the cause of the error may have been provided by the server.
* <p>
* The code sample in {@link SortControl} shows how this class may be used.
* <p>
* This class implements the LDAPv3 Response Control for server-side sorting
* as defined in
* <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
*
* The control's value has the following ASN.1 definition:
* <pre>
*
* SortResult ::= SEQUENCE {
* sortResult ENUMERATED {
* success (0), -- results are sorted
* operationsError (1), -- server internal failure
* timeLimitExceeded (3), -- timelimit reached before
* -- sorting was completed
* strongAuthRequired (8), -- refused to return sorted
* -- results via insecure
* -- protocol
* adminLimitExceeded (11), -- too many matching entries
* -- for the server to sort
* noSuchAttribute (16), -- unrecognized attribute
* -- type in sort key
* inappropriateMatching (18), -- unrecognized or inappro-
* -- priate matching rule in
* -- sort key
* insufficientAccessRights (50), -- refused to return sorted
* -- results to this client
* busy (51), -- too busy to process
* unwillingToPerform (53), -- unable to sort
* other (80)
* },
* attributeType [0] AttributeType OPTIONAL }
*
* </pre>
*
* @since 1.5
* @see SortControl
* @author Vincent Ryan
*/
final public class SortResponseControl extends BasicControl {
/**
* The server-side sort response control's assigned object identifier
* is 1.2.840.113556.1.4.474.
*/
public static final String OID = "1.2.840.113556.1.4.474";
private static final long serialVersionUID = 5142939176006310877L;
/**
* The sort result code.
*
* @serial
*/
private int resultCode = 0;
/**
* The ID of the attribute that caused the sort to fail.
*
* @serial
*/
private String badAttrId = null;
/**
* Constructs a control to indicate the outcome of a sort request.
*
* @param id The control's object identifier string.
* @param criticality The control's criticality.
* @param value The control's ASN.1 BER encoded value.
* It is not cloned - any changes to value
* will affect the contents of the control.
* @exception IOException if an error is encountered
* while decoding the control's value.
*/
public SortResponseControl(String id, boolean criticality, byte[] value)
throws IOException {
super(id, criticality, value);
// decode value
BerDecoder ber = new BerDecoder(value, 0, value.length);
ber.parseSeq(null);
resultCode = ber.parseEnumeration();
if ((ber.bytesLeft() > 0) && (ber.peekByte() == Ber.ASN_CONTEXT)) {
badAttrId = ber.parseStringWithTag(Ber.ASN_CONTEXT, true, null);
}
}
/**
* Determines if the search results have been successfully sorted.
* If an error occurred during sorting a NamingException is thrown.
*
* @return true if the search results have been sorted.
*/
public boolean isSorted() {
return (resultCode == 0); // a result code of zero indicates success
}
/**
* Retrieves the LDAP result code of the sort operation.
*
* @return The result code. A zero value indicates success.
*/
public int getResultCode() {
return resultCode;
}
/**
* Retrieves the ID of the attribute that caused the sort to fail.
* Returns null if no ID was returned by the server.
*
* @return The possibly null ID of the bad attribute.
*/
public String getAttributeID() {
return badAttrId;
}
/**
* Retrieves the NamingException appropriate for the result code.
*
* @return A NamingException or null if the result code indicates
* success.
*/
public NamingException getException() {
return LdapCtx.mapErrorCode(resultCode, null);
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.util.Iterator;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.naming.ConfigurationException;
import javax.naming.NamingException;
import com.sun.naming.internal.VersionHelper;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
/**
* This class implements the LDAPv3 Extended Request for StartTLS as
* defined in
* <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
* Access Protocol (v3): Extension for Transport Layer Security</a>
*
* The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
* and no extended request value is defined.
*<p>
* <tt>StartTlsRequest</tt>/<tt>StartTlsResponse</tt> are used to establish
* a TLS connection over the existing LDAP connection associated with
* the JNDI context on which <tt>extendedOperation()</tt> is invoked.
* Typically, a JNDI program uses these classes as follows.
* <blockquote><pre>
* import javax.naming.ldap.*;
*
* // Open an LDAP association
* LdapContext ctx = new InitialLdapContext();
*
* // Perform a StartTLS extended operation
* StartTlsResponse tls =
* (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
*
* // Open a TLS connection (over the existing LDAP association) and get details
* // of the negotiated TLS session: cipher suite, peer certificate, etc.
* SSLSession session = tls.negotiate();
*
* // ... use ctx to perform protected LDAP operations
*
* // Close the TLS connection (revert back to the underlying LDAP association)
* tls.close();
*
* // ... use ctx to perform unprotected LDAP operations
*
* // Close the LDAP association
* ctx.close;
* </pre></blockquote>
*
* @since 1.4
* @see StartTlsResponse
* @author Vincent Ryan
*/
public class StartTlsRequest implements ExtendedRequest {
// Constant
/**
* The StartTLS extended request's assigned object identifier
* is 1.3.6.1.4.1.1466.20037.
*/
public static final String OID = "1.3.6.1.4.1.1466.20037";
// Constructors
/**
* Constructs a StartTLS extended request.
*/
public StartTlsRequest() {
}
// ExtendedRequest methods
/**
* Retrieves the StartTLS request's object identifier string.
*
* @return The object identifier string, "1.3.6.1.4.1.1466.20037".
*/
public String getID() {
return OID;
}
/**
* Retrieves the StartTLS request's ASN.1 BER encoded value.
* Since the request has no defined value, null is always
* returned.
*
* @return The null value.
*/
public byte[] getEncodedValue() {
return null;
}
/**
* Creates an extended response object that corresponds to the
* LDAP StartTLS extended request.
* <p>
* The result must be a concrete subclass of StartTlsResponse
* and must have a public zero-argument constructor.
* <p>
* This method locates the implementation class by locating
* configuration files that have the name:
* <blockquote><tt>
* META-INF/services/javax.naming.ldap.StartTlsResponse
* </tt></blockquote>
* The configuration files and their corresponding implementation classes must
* be accessible to the calling thread's context class loader.
* <p>
* Each configuration file should contain a list of fully-qualified class
* names, one per line. Space and tab characters surrounding each name, as
* well as blank lines, are ignored. The comment character is <tt>'#'</tt>
* (<tt>0x23</tt>); on each line all characters following the first comment
* character are ignored. The file must be encoded in UTF-8.
* <p>
* This method will return an instance of the first implementation
* class that it is able to load and instantiate successfully from
* the list of class names collected from the configuration files.
* This method uses the calling thread's context classloader to find the
* configuration files and to load the implementation class.
* <p>
* If no class can be found in this way, this method will use
* an implementation-specific way to locate an implementation.
* If none is found, a NamingException is thrown.
*
* @param id The object identifier of the extended response.
* Its value must be "1.3.6.1.4.1.1466.20037" or null.
* Both values are equivalent.
* @param berValue The possibly null ASN.1 BER encoded value of the
* extended response. This is the raw BER bytes
* including the tag and length of the response value.
* It does not include the response OID.
* Its value is ignored because a Start TLS response
* is not expected to contain any response value.
* @param offset The starting position in berValue of the bytes to use.
* Its value is ignored because a Start TLS response
* is not expected to contain any response value.
* @param length The number of bytes in berValue to use.
* Its value is ignored because a Start TLS response
* is not expected to contain any response value.
* @return The StartTLS extended response object.
* @exception NamingException If a naming exception was encountered
* while creating the StartTLS extended response object.
*/
public ExtendedResponse createExtendedResponse(String id, byte[] berValue,
int offset, int length) throws NamingException {
// Confirm that the object identifier is correct
if ((id != null) && (!id.equals(OID))) {
throw new ConfigurationException(
"Start TLS received the following response instead of " +
OID + ": " + id);
}
StartTlsResponse resp = null;
ServiceLoader<StartTlsResponse> sl = ServiceLoader.load(
StartTlsResponse.class, getContextClassLoader());
Iterator<StartTlsResponse> iter = sl.iterator();
while (resp == null && privilegedHasNext(iter)) {
resp = iter.next();
}
if (resp != null) {
return resp;
}
try {
VersionHelper helper = VersionHelper.getVersionHelper();
Class<?> clas = helper.loadClass(
"com.sun.jndi.ldap.ext.StartTlsResponseImpl");
resp = (StartTlsResponse) clas.newInstance();
} catch (IllegalAccessException e) {
throw wrapException(e);
} catch (InstantiationException e) {
throw wrapException(e);
} catch (ClassNotFoundException e) {
throw wrapException(e);
}
return resp;
}
/*
* Wrap an exception, thrown while attempting to load the StartTlsResponse
* class, in a configuration exception.
*/
private ConfigurationException wrapException(Exception e) {
ConfigurationException ce = new ConfigurationException(
"Cannot load implementation of javax.naming.ldap.StartTlsResponse");
ce.setRootCause(e);
return ce;
}
/*
* Acquire the class loader associated with this thread.
*/
private final ClassLoader getContextClassLoader() {
return AccessController.doPrivileged(
new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
}
);
}
private final static boolean privilegedHasNext(final Iterator<StartTlsResponse> iter) {
Boolean answer = AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.valueOf(iter.hasNext());
}
});
return answer.booleanValue();
}
private static final long serialVersionUID = 4441679576360753397L;
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import java.io.IOException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.HostnameVerifier;
/**
* This class implements the LDAPv3 Extended Response for StartTLS as
* defined in
* <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
* Access Protocol (v3): Extension for Transport Layer Security</a>
*
* The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
* and no extended response value is defined.
*
*<p>
* The Start TLS extended request and response are used to establish
* a TLS connection over the existing LDAP connection associated with
* the JNDI context on which <tt>extendedOperation()</tt> is invoked.
* Typically, a JNDI program uses the StartTLS extended request and response
* classes as follows.
* <blockquote><pre>
* import javax.naming.ldap.*;
*
* // Open an LDAP association
* LdapContext ctx = new InitialLdapContext();
*
* // Perform a StartTLS extended operation
* StartTlsResponse tls =
* (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
*
* // Open a TLS connection (over the existing LDAP association) and get details
* // of the negotiated TLS session: cipher suite, peer certificate, ...
* SSLSession session = tls.negotiate();
*
* // ... use ctx to perform protected LDAP operations
*
* // Close the TLS connection (revert back to the underlying LDAP association)
* tls.close();
*
* // ... use ctx to perform unprotected LDAP operations
*
* // Close the LDAP association
* ctx.close;
* </pre></blockquote>
*
* @since 1.4
* @see StartTlsRequest
* @author Vincent Ryan
*/
public abstract class StartTlsResponse implements ExtendedResponse {
// Constant
/**
* The StartTLS extended response's assigned object identifier
* is 1.3.6.1.4.1.1466.20037.
*/
public static final String OID = "1.3.6.1.4.1.1466.20037";
// Called by subclass
/**
* Constructs a StartTLS extended response.
* A concrete subclass must have a public no-arg constructor.
*/
protected StartTlsResponse() {
}
// ExtendedResponse methods
/**
* Retrieves the StartTLS response's object identifier string.
*
* @return The object identifier string, "1.3.6.1.4.1.1466.20037".
*/
public String getID() {
return OID;
}
/**
* Retrieves the StartTLS response's ASN.1 BER encoded value.
* Since the response has no defined value, null is always
* returned.
*
* @return The null value.
*/
public byte[] getEncodedValue() {
return null;
}
// StartTls-specific methods
/**
* Overrides the default list of cipher suites enabled for use on the
* TLS connection. The cipher suites must have already been listed by
* <tt>SSLSocketFactory.getSupportedCipherSuites()</tt> as being supported.
* Even if a suite has been enabled, it still might not be used because
* the peer does not support it, or because the requisite certificates
* (and private keys) are not available.
*
* @param suites The non-null list of names of all the cipher suites to
* enable.
* @see #negotiate
*/
public abstract void setEnabledCipherSuites(String[] suites);
/**
* Sets the hostname verifier used by <tt>negotiate()</tt>
* after the TLS handshake has completed and the default hostname
* verification has failed.
* <tt>setHostnameVerifier()</tt> must be called before
* <tt>negotiate()</tt> is invoked for it to have effect.
* If called after
* <tt>negotiate()</tt>, this method does not do anything.
*
* @param verifier The non-null hostname verifier callback.
* @see #negotiate
*/
public abstract void setHostnameVerifier(HostnameVerifier verifier);
/**
* Negotiates a TLS session using the default SSL socket factory.
* <p>
* This method is equivalent to <tt>negotiate(null)</tt>.
*
* @return The negotiated SSL session
* @throws IOException If an IO error was encountered while establishing
* the TLS session.
* @see #setEnabledCipherSuites
* @see #setHostnameVerifier
*/
public abstract SSLSession negotiate() throws IOException;
/**
* Negotiates a TLS session using an SSL socket factory.
* <p>
* Creates an SSL socket using the supplied SSL socket factory and
* attaches it to the existing connection. Performs the TLS handshake
* and returns the negotiated session information.
* <p>
* If cipher suites have been set via <tt>setEnabledCipherSuites</tt>
* then they are enabled before the TLS handshake begins.
* <p>
* Hostname verification is performed after the TLS handshake completes.
* The default hostname verification performs a match of the server's
* hostname against the hostname information found in the server's certificate.
* If this verification fails and no callback has been set via
* <tt>setHostnameVerifier</tt> then the negotiation fails.
* If this verification fails and a callback has been set via
* <tt>setHostnameVerifier</tt>, then the callback is used to determine whether
* the negotiation succeeds.
* <p>
* If an error occurs then the SSL socket is closed and an IOException
* is thrown. The underlying connection remains intact.
*
* @param factory The possibly null SSL socket factory to use.
* If null, the default SSL socket factory is used.
* @return The negotiated SSL session
* @throws IOException If an IO error was encountered while establishing
* the TLS session.
* @see #setEnabledCipherSuites
* @see #setHostnameVerifier
*/
public abstract SSLSession negotiate(SSLSocketFactory factory)
throws IOException;
/**
* Closes the TLS connection gracefully and reverts back to the underlying
* connection.
*
* @throws IOException If an IO error was encountered while closing the
* TLS connection
*/
public abstract void close() throws IOException;
private static final long serialVersionUID = 8372842182579276418L;
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.NamingException;
/**
* This interface represents an unsolicited notification as defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
* An unsolicited notification is sent by the LDAP server to the LDAP
* client without any provocation from the client.
* Its format is that of an extended response (<tt>ExtendedResponse</tt>).
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see ExtendedResponse
* @see UnsolicitedNotificationEvent
* @see UnsolicitedNotificationListener
* @since 1.3
*/
public interface UnsolicitedNotification extends ExtendedResponse, HasControls {
/**
* Retrieves the referral(s) sent by the server.
*
* @return A possibly null array of referrals, each of which is represented
* by a URL string. If null, no referral was sent by the server.
*/
public String[] getReferrals();
/**
* Retrieves the exception as constructed using information
* sent by the server.
* @return A possibly null exception as constructed using information
* sent by the server. If null, a "success" status was indicated by
* the server.
*/
public NamingException getException();
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
/**
* This class represents an event fired in response to an unsolicited
* notification sent by the LDAP server.
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see UnsolicitedNotification
* @see UnsolicitedNotificationListener
* @see javax.naming.event.EventContext#addNamingListener
* @see javax.naming.event.EventDirContext#addNamingListener
* @see javax.naming.event.EventContext#removeNamingListener
* @since 1.3
*/
public class UnsolicitedNotificationEvent extends java.util.EventObject {
/**
* The notification that caused this event to be fired.
* @serial
*/
private UnsolicitedNotification notice;
/**
* Constructs a new instance of <tt>UnsolicitedNotificationEvent</tt>.
*
* @param src The non-null source that fired the event.
* @param notice The non-null unsolicited notification.
*/
public UnsolicitedNotificationEvent(Object src,
UnsolicitedNotification notice) {
super(src);
this.notice = notice;
}
/**
* Returns the unsolicited notification.
* @return The non-null unsolicited notification that caused this
* event to be fired.
*/
public UnsolicitedNotification getNotification() {
return notice;
}
/**
* Invokes the <tt>notificationReceived()</tt> method on
* a listener using this event.
* @param listener The non-null listener on which to invoke
* <tt>notificationReceived</tt>.
*/
public void dispatch(UnsolicitedNotificationListener listener) {
listener.notificationReceived(this);
}
private static final long serialVersionUID = -2382603380799883705L;
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.ldap;
import javax.naming.event.NamingListener;
/**
* This interface is for handling <tt>UnsolicitedNotificationEvent</tt>.
* "Unsolicited notification" is defined in
* <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>.
* It allows the server to send unsolicited notifications to the client.
* A <tt>UnsolicitedNotificationListener</tt> must:
*<ol>
* <li>Implement this interface and its method
* <li>Implement <tt>NamingListener.namingExceptionThrown()</tt> so
* that it will be notified of exceptions thrown while attempting to
* collect unsolicited notification events.
* <li>Register with the context using one of the <tt>addNamingListener()</tt>
* methods from <tt>EventContext</tt> or <tt>EventDirContext</tt>.
* Only the <tt>NamingListener</tt> argument of these methods are applicable;
* the rest are ignored for a <tt>UnsolicitedNotificationListener</tt>.
* (These arguments might be applicable to the listener if it implements
* other listener interfaces).
*</ol>
*
* @author Rosanna Lee
* @author Scott Seligman
* @author Vincent Ryan
*
* @see UnsolicitedNotificationEvent
* @see UnsolicitedNotification
* @see javax.naming.event.EventContext#addNamingListener
* @see javax.naming.event.EventDirContext#addNamingListener
* @see javax.naming.event.EventContext#removeNamingListener
* @since 1.3
*/
public interface UnsolicitedNotificationListener extends NamingListener {
/**
* Called when an unsolicited notification has been received.
*
* @param evt The non-null UnsolicitedNotificationEvent
*/
void notificationReceived(UnsolicitedNotificationEvent evt);
}