Una implementaci�n de contexto URL es un contexto que maneja strings URL arbitrarios del esquema URL soportado por el contexto. Es una clase que implementa el interface Context o uno de sus subinterfaces. Se diferencia de la implementaci�n de contexto (plano) descrita en la lecci�n Los Componentes Esenciales en la forma en que sus m�todos aceptan y procesan el argumento nombre
�Nombres Estructurados contra Nomres String
La lecci�n Las Reglas de Fondo sugiere que implementemos los m�todos de contexto que aceptan strings en t�rminos de sus contrapartes Name porque los nombres string deber�an ser tratados como nombres mixtos (JNDI). Esta regla no se aplica a las implementaciones de contexto URL, porque un string URL no es un nombre mixto JNDI. Un string URL deber�a procesarse de acuerdo a la s�ntaxis definida en su esquema de URL. De hecho, la dependencia tambi�n es a la inversa. es decir, las sobrecargas que aceptan Name tambi�n deber�an ser implementadas en t�rminos de sus contrapartes strings.
Si no queremos soportar federaciones, podemos s�lo lanzar una InvalidNameException cuando se presente un Name multi-componente:
public void bind(Name name, Object obj) throws NamingException {
if (name.size() == 1) {
bind(name.get(0), obj);
} else {
throw new InvalidNameException(
"Cannot have composite names with URLs");
}
}
Si soportamos federaciones, entonces cuando se presente con un CompositeName cuyo primer componente sea un string URL v�lido, deber�amos tratar el primer componente como una URL y luego el resto de los componentes de la federaci�n (es decir, resolver la URL nos dir� qu� sistema de nombres utilizar para resolver la parte restante). Si se presenta con un Name que no es un CompositeName, deber�amos tratar esto como un caso de error y lanzar una InvalidNameException. Esto es as� porque una URL embebida dentro de un nombre compuesto no tiene sentido.
Este ejemplo no comprueba si la entrada es un CompositeName. Aqu� est� la definici�n de bind() del ejemplo:
public void bind(Name name, Object obj) throws NamingException {
if (name.size() == 1) {
bind(name.get(0), obj);
} else {
Context ctx = getContinuationContext(name);
try {
ctx.bind(name.getSuffix(1), obj);
} finally {
ctx.close();
}
}
}
Todas las sobrecargas que aceptan un Name usan un patr�n similar. Si el nombre contiene un �nico componente, extrae el primer componente y lo pasa a la sobrecarga que acepta un nombre string. Esto se parece al llamador usando la sobrecarga que acepta nombres string en la primera posici�n. De otra forma, usa el m�todo de utilidad getContinuationContext() para resolver el primer componente (es decir, el string URL) y contin�a la operaci�n en ese contexto. Aqu� est� la definici�n de getContinuationContext():
protected Context getContinuationContext(Name n) throws NamingException {
Object obj = lookup(n.get(0));
CannotProceedException cpe = new CannotProceedException();
cpe.setResolvedObj(obj);
cpe.setEnvironment(myEnv);
return NamingManager.getContinuationContext(cpe);
}
Este m�todo de utilidad resuelve el primer componente del nombre y usa el resultado como el "objeto resuelto" en una llamada a NamingManager.getContinuationContext() para obtener el contexto fuente en el que continuar la operaci�n sobre el resto del nombre.
�El Contexto Ra�z URL
Observa que hemos tenido cuidado de las sobrecargas que aceptan Name, podemos cambiar nuestra atenci�n a las sobrecargas que aceptan java.lang.String. Las implementaciones de estos m�todos dependen en gran medida de su contraparte en la implementaci�n de contexto "no-URL". Por ejemplo, una implementaci�n de contexto URL para la URL LDAP es altamente dependiente de la implementaci�n de contexto para el servicio LDAP. Una b�squeda de una URL LDAP en un contexto LDAP URL normalmente resulta en una b�squeda en un contexto LDAP (de la implementaci�n de contexto LDAP) usando un DN LDAP. En este escenario, la implementaci�n de contexto URL realmente s�lo es una imagen de la implementaci�n de contexto real del servicio. A causa de esta relaci�n cerrada, este ejemplo podr�a no aplicarse tan bien en algunas implementaciones reales.
El ejemplo usa la noci�n de un contexto raiz que se deriva de la string URL de entrada. Define un m�todo de utilidad, getRootURLContext(), que acepta un string URL. Este m�todo devuelve un paquete que consta de un contexto que est� derivado de la informaci�n de la URL y el resto del nombre de la URL para ser resuelto en relaci�n al contexto ra�z. Por ejemplo, en el ejemplo LDAP, supongamos que el string URL de entrada es "ldap://favserver:289/o=jnditutorial". El contexto ra�z podr�a ser el contexto de la ra�z del servidor LDAP en la m�quina favserver y el puerto 289. En este caso, la porci�n "ldap://favserver:289/" del string URL ser� consumida en la producci�n del contexto ra�z y el resto del nombre ser� "o=jnditutorial".
En nuestro ejemplo de URL foo, el contexto ra�z apunta a la ra�z del espacio de nombres est�tico HierCtx, y "foo:/" es consumido para producir el contexto ra�z. El resto del nombre est� representado como un s�lo componente CompositeName:
protected ResolveResult getRootURLContext(String url, Hashtable env)
throws NamingException {
if (!url.startsWith("foo:/")) {
throw new IllegalArgumentException(url + " is not a foo URL");
}
String objName = url.length() > 5 ? url.substring(5) : null;
// Represent the object name as empty or a single-component composite name.
CompositeName remaining = new CompositeName();
if (objName != null) {
remaining.add(objName);
}
// Get the handle to the static namespace to use for testing
// In an actual implementation, this might be the root
// namespace on a particular server
Context ctx = tut.HierCtx.getStaticNamespace(env);
return (new ResolveResult(ctx, remaining));
}
Las sobrecargas que aceptan nombres string usan este m�todo de utilidad para procesar el string URL y completar la operaci�n. Aqu� tenemos la definici�n de bind() para el ejemplo:
public void bind(String name, Object obj) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.bind(res.getRemainingName(), obj);
} finally {
ctx.close();
}
}
Observa que antes de que el m�todo retorne, cierra el contexto ra�z. En este ejemplo, este paso no es realmente necesario porque fooURLContext no mantiene ninguna conexi�n ni recurso. Sin embargo, es una buena pr�ctica para asegurarse de que las implementaciones que mantienen conexiones o recursos las liberan apropiadamente. Esto tambi�n significa que los m�todos con estado como list() deben asegurarse de que la enumeraci�n resultante que devuelven permanezca utilizable despu�s de que se haya cerrado el contexto.
�Consideraciones Espaciales para rename()
rename() es diferente de otros m�todos de contexto en que acepta dos nombres en lugar de uno. Con un nombre, podemos usar getRootURLContext() para obtener un contexto trabajable para terminar la operaci�n. Con dos nombres, no podemos llamar a getRootURLContext() dos veces, una por cada nombre, porque cada llamada podr�a devolver un contexto diferente. rename() s�lo puede tener un contexto en el que hacer el resto.
Para resolver esto en nuestro ejemplo, primero extraemos de ambos nombres un prefijo com�n (usando la utilidad interna getURLPrefix()). Luego usamos getRootURLContext() para obtener el contexto ra�z y el resto del nombre del nombre original. Para obtener el resto del nombre del nuevo nombre, usamos otra utilidad interna getURLSuffix(). Observa que es muy importante que los tres metodos --getRootURLContext(), getURLPrefix(), y getURLSuffix()-- est�n completamente de acuerdo en c�mo se analiza un string URL y que partes se designan como prefijo y sufijo.
En particular, getRootURLContext() deber�a consumir la porci�n devuelta por getURLPrefix() para crear el contexto ra�z y devolver el como el resto del nombre la porci�n que devolver� getURLSuffix(). Tambi�n deber�amos tener en cuenta las restricciones sobre la habilidad de una implementaci�n de contexto para realizar renombrados a trav�s de diferentes servidores o espacios de nombre.
Aqu� tenemos un ejemplo de rename():
public void rename(String oldName, String newName)
throws NamingException {
String oldPrefix = getURLPrefix(oldName);
String newPrefix = getURLPrefix(newName);
if (!urlEquals(oldPrefix, newPrefix)) {
throw new OperationNotSupportedException(
"Renaming using different URL prefixes not supported : " +
oldName + " " + newName);
}
ResolveResult res = getRootURLContext(oldName, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.rename(res.getRemainingName(),
getURLSuffix(newPrefix, newName));
} finally {
ctx.close();
}
}
Aqu� est�n las implementaciones de getURLPrefix() y getURLSuffix():
protected String getURLPrefix(String url) throws NamingException {
int start = url.indexOf(":");
if (start < 0) {
throw new OperationNotSupportedException("Invalid URL: " + url);
}
++start; // Skip ":"
if (url.startsWith("//", start)) {
start += 2; // Skip the double forward slash
// Find the last forward slash
int posn = url.indexOf("/", start);
if (posn >= 0) {
start = posn;
} else {
start = url.length(); // Rest of the URL
}
}
// Else 0 or 1 initial slashes; the start is unchanged
return url.substring(0, start);
}
protected Name getURLSuffix(String prefix, String url)
throws NamingException {
String suffix = url.substring(prefix.length());
if (suffix.length() == 0) {
return new CompositeName();
}
if (suffix.charAt(0) == '/') {
suffix = suffix.substring(1); // Skip the leading forward slash
}
// Note: This is a simplified implementation;
// a real implementation should
// transform any URL-encoded characters into their Unicode char
// representations
return new CompositeName().add(suffix);
}