| Adding URL Support

## URL Context Factory

> A URL context factory is a special object factory that creates contexts for resolving URL strings. Like all object factories, it is a class that implements the `ObjectFactory` interface. A URL context factory must not only satisfy all of the requirements specified for object factories as stated in the Object Factories lesson. It also must adhere to the following rules.
> - A `null` object argument to `getObjectInstance()` means that the factory should create a context for resolving arbitrary URL strings of the scheme associated with the factory. For example, such an invocation on a factory for the `ldap` scheme would return a context that accepts arbitrary LDAP URL strings, such as `"ldap://ldap.wiz.com/o=wiz,c=us"` and `"ldap://ldap.umich.edu/o=umich,c=us"`.
> - If the object argument to `getObjectInstance()` is a URL string (`java.lang.String`) of a scheme acceptable to that factory, then the factory should return an object (which might not necessarily be a context) identified by the URL string. For example, if `getObjectInstance()` is given the string `"ldap://ldap.wiz.com/o=wiz,c=us"`, then it would return the object named by the DN `"o=wiz, c=us"` at the LDAP server `ldap.wiz.com`.
> - If the object argument to `getObjectInstance()` is an array of URL strings (`java.lang.String[]`), then the factory should return the object named by any one of the URL strings. All of the URL strings in the array are assumed to be equivalent in terms of the object to which they refer. Verification of whether the strings are, or need to be, equivalent is up to the factory. The order of the URL strings in the array is insignificant.
> If the factory receives any other type of object argument to `getObjectInstance()`, then its behavior is implementation-dependent.

> The first rule applies to supporting the resolution of URL strings from the `InitialContext`--this is described later in this lesson. The second and third rules apply to supporting the resolution of URL strings embedded in a `Reference`--this is also described later in this lesson. As indicated by the second and third rules, a URL context factory is not only a producer of context objects. It can produce any type of object named by a URL string.

> #### Class Name's Naming Convention

> The URL context factory's class name must use the following naming convention so that it can be located by the JNDI framework:

> > package_prefix.scheme_id.scheme_id `URLContextFactory`

> where
> - package_prefix is a valid prefix for a package in the Java programming language and
> - scheme_id is the naming/directory service's URL scheme id (for example, `ldap` is the scheme id for services that support the LDAP).
> For example, the class name `tut.foo.fooURLContextFactory` is for the `foo` URL scheme; it has the package prefix `"tut"`. In another example, the class name `com.sun.jndi.url.ldap.ldapURLContextFactory` is for the `ldap` URL scheme; it has the package prefix `"com.sun.jndi.url"`. Notice that package_prefix must not be empty.

> #### Sample Implementation

> This section offers an example of how to implement a URL context factory. This example is for illustrative purposes and is not meant to be prescriptive.

> The example is for the `foo` URL scheme, which has the syntax

> > `foo:`name in the `HierCtx` namespace

> `HierCtx` is an in-memory hierarchical namespace implementation. To make it work with the URL example, you need to create a static namespace that can be accessed by using a static method on the `HierCtx` class. Using a `foo` URL string, you can name the objects in this static namespace.

> Like all object factories, a URL context factory must be public and have a public constructor that accepts no arguments.

> >     public class fooURLContextFactory implements ObjectFactory {
> >         public fooURLContextFactory() {
> >         }
> >         ...
> >     }

> This factory's implementation of `getObjectInstance()` fairly well follows the three rules listed previously. The implementations of these rules use the following utility to create a context from the context implementation `fooURLContext`.

> >     protected Context getURLContext(Hashtable env) {
> >         return new fooURLContext(env);
> >     }

> An actual implementation may or may not choose this strategy of using one context implementation to satisfy all three requirements. It is perfectly acceptable to have a factory that uses different context implementations.

> In the following examples, `urlInfo` is the object argument to `getObjectInstance()`.

> For the first rule, you simply return the root `fooURLContext`.

> >     if (urlInfo == null) {
> >         return createURLContext(env);
> >     }

> For the second rule, you use the root `fooURLContext` to look up and return the object named by the URL string.

> >     if (urlInfo instanceof String) {
> >         Context urlCtx = createURLContext(env);
> >         try {
> >             return urlCtx.lookup((String)urlInfo);
> >         } finally {
> >             urlCtx.close();
> >         }
> >     }

> Notice that before the method returns, it closes the root `fooURLContext`. In this particular example, this step is not really necessary because `fooURLContext` doesn't maintain any connections or resources. However, doing this is good practice so as to ensure that implementations that do maintain connections or resources are cleaned up properly.

> For the third rule, you iterate over the array of URL strings until you find one that succeeds. You save one of the exceptions encountered along the way in case all of the URL strings fail and you need to indicate why.

> >     if (urlInfo instanceof String[]) {

> >         // Try each URL until lookup() succeeds for one of them.
> >         // If all URLs fail, throw one of the exceptions arbitrarily.
> >         String[] urls = (String[])urlInfo;
> >         if (urls.length == 0) {
> >             throw (new ConfigurationException("fooURLContextFactory: empty URL array"));
> >         }
> >         Context urlCtx = createURLContext(env);
> >         try {
> >     	NamingException ne = null;
> >     	for (int i = 0; i < urls.length; i++) {
> >     	    try {
> >     	        return urlCtx.lookup(urls[i]);
> >     	    } catch (NamingException e) {
> >     	        ne = e;
> >     	    }
> >             }
> >             throw ne;
> >         } finally {
> >             urlCtx.close();
> >         }
> >     }

| Adding URL Support