| Controls and Extensions

## "Extended" Operations

> As mentioned earlier in this lesson, the LDAP v3 defines the "extended" operation, which takes a request as the argument and returns a response. The request contains an identifier that identifies the request and the arguments of the request. The response contains the results of performing the request. The pair of "extended" operation request/response is called an extension. For example, there can be an extension for Start TLS, which is a request for the client to the server to activate the TLS protocol. These extensions can be standard (defined by the LDAP community) or proprietary (defined by a particular directory vendor).

> The `javax.naming.ldap` package defines the interface `ExtendedRequest` to represent the argument to an "extended" operation, and the interface `ExtendedResponse` to represent the result of the operation. An extended response is usually paired with an extended request but not necessarily vice versa. That is, you can have an extended request that has no corresponding extended response. An unpaired extended response is called an unsolicited notification, described in detail in the Event Notification lesson.

> An application typically does not deal directly with these interfaces. Instead, it deals with classes that implement these interfaces. The application gets these classes either as part of a repertoire of "extended" operations standardized through the IETF or from directory vendors for vendor-specific "extended" operations. The request classes should have constructors that accept arguments in a type-safe and user-friendly manner, whereas the response classes should have access methods for getting the data of the response in a type-safe and user-friendly manner. Internally, the request/response classes deal with encoding and decoding BER values.

> Examples of extension classes are the `StartTlsRequest` and `StartTlsResponse` classes. See the next section for a detailed description of this extension and sample code that uses these classes.

> #### Extensions Supported by LDAP Servers

> Support for specific extensions is LDAP server-dependent. Eventually, when extensions are standardized, a set of popular extensions supported by most LDAP servers might be available. However, proprietary and vendor-specific extensions might still be around.

> Here is a simple program for finding out the list of extensions that an LDAP server supports.

> >     // Create the initial context
> >     DirContext ctx = new InitialDirContext();

> >     // Read supportedextension from the root DSE
> >     Attributes attrs = ctx.getAttributes(
> >         "ldap://localhost:389", new String[]{"supportedextension"});

> Here is the output produced by running this program against an LDAP server.

> >     {supportedextension=supportedextension:
> >       1.3.6.1.4.1.1466.20037
> >     }

> #### Implementations

> You typically will deal with implementation classes that implement `ExtendedRequest` and `ExtendedResponse` rather than directly use their methods. Such implementation classes typically have type-friendly constructors and accessor methods.

> For example, suppose that an LDAP server supports a Get Time "extended" operation. It would supply classes such as `GetTimeRequest` and `GetTimeResponse`, so that applications can use this feature. An application would use these classes as follows.

> >     // Invoke the "extended" operation
> >     GetTimeResponse resp =
> >         (GetTimeResponse) lctx.extendedOperation(new GetTimeRequest());

> >     // Get the "extended" operation's (decoded) response
> >     long time = resp.getTime();

> The `GetTimeRequest` and `GetTimeResponse` classes might be defined as follows.

> >     public class GetTimeRequest implements ExtendedRequest {
> >         // User-friendly constructor
> >         public GetTimeRequest() {
> >         };

> >         // Methods used by service providers
> >         public String getID() {
> >             return GETTIME_REQ_OID;
> >         }
> >         public byte[] getEncodedValue() {
> >             return null;  // No value is needed for the Get Time request
> >         }
> >         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;
> >         // Called by GetTimeRequest.createExtendedResponse()
> >         GetTimeResponse(String id, byte[] berValue, int offset, int length)
> >             throws NamingException {
> >             // Check the validity of the id
> >             long time =  ... // Decode berValue to get the time
> >         }

> >         // These are type-safe and user-friendly methods
> >         public java.util.Date getDate() { return new java.util.Date(time); }
> >         public long getTime() { return time; }

> >         // These are low-level methods
> >         public byte[] getEncodedValue() {
> >             return // berValue saved;
> >         }
> >         public String getID() {
> >             return GETTIME_RESP_OID;
> >         }
> >     }

| Controls and Extensions