Controles de Peticiones de Contexto
Podemos asociar controles de petición para enviarlas junto con peticiones LDAP emitidas por métodos
de
Context usando
LdapContext.setRequestControls(). Por ejemplo, podemos
configurar los controles de peticiones de contexto para incluir un control que le diga al servidor
que ordene los resultados de
Context.list() y DirContext.search(),
asumiendo que el servidor LDAP soporta ordenación en el lado del servidor,
como se muestra en este ejemplo:
// Create the initial context with no connection request controls
LdapContext ctx = new InitialLdapContext(env, null);
// Create the critical Sort control that sorts based on "cn"
Control[] ctxCtls = new Control[]{
new SortControl(new String[]{"cn"}, Control.CRITICAL)
};
// Set the context's request controls to be ctxCtls
ctx.setRequestControls(ctxCtls);
// Perform the list, will sort by cn
NamingEnumeration answer = ctx.list("");
Una vez configurados, los controles permanecen activos para el ejemplar de
Context hasta que sean reemplazados por los argumentos de otra
llamada a
setRequestControls(). Luego, después de hacer la lista, podemos
realizar una búsqueda usando el mismo ejemplar de Context; los
resultados seguirán siendo ordenados por el atributo "cn":
// Perform the search, which will still sort by "cn"
// because context request controls are still in effect
answer = ctx.search("ou=People", "(cn=*)", null);
Para decirle a un ejemplar de Context que no use ningún control de
petición, suministramos null como el argumento para
setRequestControls():
// Set the context's request controls to be nothing
ctx.setRequestControls(null);
Encontrar los Controles de Peticiones de Contexto que están Activos
Para encontrar los controles de petición que están activos para un contexto, usamos
LdapContext.getRequestControls(). Aquí hay un ejemplo
que configura los controles de petición para ser un control Sort y luego
chequea los controles usando getRequestControls():
// Set the context's request controls to be ctxCtls
ctx.setRequestControls(ctxCtls);
// Check the controls that are in effect for context
Control[] reqCtls = ctx.getRequestControls();
if (reqCtls != null) {
for (int i = 0; i < reqCtls.length; i++) {
System.out.println(reqCtls[i]);
}
}
Aquí está la salida producida por este ejemplo:
com.sun.jndi.ldap.ctl.SortControl@1fa4d711
com.sun.jndi.ldap.ManageReferralControl@1fa4d59d
Esta salida muestra tanto el control que fue añadido (el control Sort) así como un control
Manage Referral que envía el proveedor
LDAP cuando
las remisiones están siendo ignoradas (es decir, la propiedad de entorno
Context.REFERRAL está deseleccionada o configurada como
"ignore"). Para evitar que el proveedor LDAP envíe este control,
debemos configurar la
propiedad Context.REFERRAL como
"throw" o
"follow". Puedes ver más detalles en la lección
Remisiones.
Ambito
Un control de petición de contexto permanece activo para todas las operaciones sobre ese ejemplar
Context. Sin embargo, al contrario que las propiedades de entorno,
un control de petición de contexto no heredado por los contextos derivados de
este contexto.
Por ejemplo, si realizamos una
Context.lookup() y obtenemos un contexto, entonces ese
contexto no
tiene controles de peticion. Siempre debemos configurar explícitamente los controles de peticiones
de contexto
usando setRequestControls(), excepto cuando se usa
LdapContext.newInstance(), como se explica más adelante.
Programación Multithread
Tener un control de petición de contexto activo para todos los métodos llamados sobre un contexto
pone un poco de
desafío para que varios threads compartan un mismo contexto. Como siempre (independiente de los
controles), dichos
threads deben sincronizar sus accesos al contexto. Además, deben asegurarse de que el contexto
tiene el conjunto de
controles de petición correcto.
Por ejemplo, para asegurar que un método se ejecuta con los controles de petición correctos,
debemos tener un código
que se parezca a este:
synchronized(ctx) {
// Set the context's request controls to be myCtls
ctx.setRequestControls(myCtls);
// Perform the list by using the control
NamingEnumeration answer = ctx.list("");
// Do something useful with the answer
// Get any response controls
respCtls = ctx.getResponseControls();
}
Esto es muy enrebesado si queremos que un thread tenga controles de petición que persistan a través
de múltiples
operacones. En lugar de hacer esto, podemos usar
LdapContext.newInstance(). Este método nos permite crear
un clon del
ejemplar de Context exisente, con los controles de petición
inicializados a los
suministrados en el argumento:
// Create a clone with the request controls set to newCtls
LdapContext cloneCtx = ctx.newInstance(newCtls);
Cuando después actualicemos los controles de petición del clon, la actualizaciones no afectarán al
contexto original,
y viceversa. Donde sea apropiado y posible, el clon compartirá recursos con el contexto original,
como la conexión
subyacente con el seridor LDAP.
Aquí tenemos un ejemplo que usa
newInstance() para crear un clon de un contexto e inicializa el clon
con un control
Sort. Luego realiza una búsqueda en cada contexto. Los resultados desde el
clon están ordenados,
mientras que los del original no lo están:
// Create the initial context with no connection request controls
LdapContext ctx = new InitialLdapContext(env, null);
// Create the critical Sort that sorts based on "cn"
Control[] ctxCtls = new Control[]{
new SortControl(new String[]{"cn"}, Control.CRITICAL)
};
// Create a clone with request controls set to ctxCtls
LdapContext cloneCtx = ctx.newInstance(ctxCtls);
// Perform the search by using the original context
NamingEnumeration answer = ctx.search("", "(cn=*)", null);
// Enumerate the answers (not sorted)
System.out.println("-----> Unsorted");
while (answer.hasMore()) {
System.out.println(((SearchResult)answer.next()).getName());
}
// Perform the search by using a clone context; sort by "cn"
answer = cloneCtx.search("", "(cn=*)", null);
System.out.println("-----> Sorted");
// Enumerate the answers (sorted)
while (answer.hasMore()) {
System.out.println(((SearchResult)answer.next()).getName());
}
Aquí está la salida producida por el ejemplo:
# java NewInstance
-----> Unsorted
cn=Button
cn=Choice
cn=CheckboxGroup
cn=TextField
cn=CorbaHello
cn=RemoteHello
cn=RefHello
cn=Custom
cn=John Smith
-----> Sorted
cn=Button
cn=CheckboxGroup
cn=Choice
cn=CorbaHello
cn=Custom
cn=John Smith
cn=RefHello
cn=RemoteHello
cn=TextField