Redesigned scopes to enable custom implementations. Renamed DependencyException to ConfigurationException. Cleaned up Container's interface. It now returns a Factory instead of a direct instance so clients don't have to keep passing in the paramters resulting in a map lookup. Added support for injecting Factory<T> where T is any bound type.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@17 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/DependencyException.java b/src/com/google/inject/ConfigurationException.java
similarity index 72%
rename from src/com/google/inject/DependencyException.java
rename to src/com/google/inject/ConfigurationException.java
index 25fa5b1..a1ea74a 100644
--- a/src/com/google/inject/DependencyException.java
+++ b/src/com/google/inject/ConfigurationException.java
@@ -17,21 +17,21 @@
 package com.google.inject;
 
 /**
- * Thrown when a dependency is misconfigured.
+ * Thrown when the {@link ContainerBuilder} is misconfigured.
  *
  * @author crazybob@google.com (Bob Lee)
  */
-public class DependencyException extends RuntimeException {
+public class ConfigurationException extends RuntimeException {
 
-  public DependencyException(String message) {
+  public ConfigurationException(String message) {
     super(message);
   }
 
-  public DependencyException(String message, Throwable cause) {
+  public ConfigurationException(String message, Throwable cause) {
     super(message, cause);
   }
 
-  public DependencyException(Throwable cause) {
+  public ConfigurationException(Throwable cause) {
     super(cause);
   }
 }
diff --git a/src/com/google/inject/ConstantConversionException.java b/src/com/google/inject/ConstantConversionException.java
index 6fb0467..23e6558 100644
--- a/src/com/google/inject/ConstantConversionException.java
+++ b/src/com/google/inject/ConstantConversionException.java
@@ -23,7 +23,7 @@
  *
  * @author crazybob@google.com (Bob Lee)
  */
-class ConstantConversionException extends DependencyException {
+class ConstantConversionException extends ConfigurationException {
 
   ConstantConversionException(Member member, Key<?> key, String value,
       String reason) {
diff --git a/src/com/google/inject/ConstructionContext.java b/src/com/google/inject/ConstructionContext.java
index 2da79e1..25a9fe4 100644
--- a/src/com/google/inject/ConstructionContext.java
+++ b/src/com/google/inject/ConstructionContext.java
@@ -66,7 +66,7 @@
     // instance (as opposed to one per caller).
 
     if (!expectedType.isInterface()) {
-      throw new DependencyException(
+      throw new ConfigurationException(
           expectedType.getName() + " is not an interface.");
     }
 
diff --git a/src/com/google/inject/Container.java b/src/com/google/inject/Container.java
index 3fe50a5..44f8e33 100644
--- a/src/com/google/inject/Container.java
+++ b/src/com/google/inject/Container.java
@@ -18,7 +18,7 @@
 
 /**
  * Injects dependencies into constructors, methods and fields annotated with
- * {@link Inject}. Immutable.
+ * {@link Inject}.
  *
  * <p>When injecting a method or constructor, you can additionally annotate
  * its parameters with {@link Inject} and specify a dependency name. When a
@@ -52,11 +52,12 @@
  *  }
  * </pre>
  *
- * <p>To create and inject an instance of {@code Foo}:
+ * <p>To get an instance of {@code Foo}:
  *
  * <pre>
  *  Container c = ...;
- *  Foo foo = c.inject(Foo.class);
+ *  Factory&lt;Foo> fooFactory = c.getFactory(Key.get(Foo.class));
+ *  Foo foo = fooFactory.get();
  * </pre>
  *
  * @see ContainerBuilder
@@ -67,34 +68,17 @@
   /**
    * Injects dependencies into the fields and methods of an existing object.
    */
-  void inject(Object o);
+  void injectMembers(Object o);
 
   /**
    * Creates and injects a new instance of type {@code implementation}.
    */
-  <T> T inject(Class<T> implementation);
+  <T> T newInstance(Class<T> implementation);
 
   /**
-   * Gets an instance of the given dependency which was declared in
-   * {@link com.google.inject.ContainerBuilder}.
+   * Gets the factory bound to the given key.
    */
-  <T> T getInstance(Class<T> type, String name);
-
-  /**
-   * Convenience method.&nbsp;Equivalent to {@code get(type,
-   * DEFAULT_NAME)}.
-   */
-  <T> T getInstance(Class<T> type);
-
-  /**
-   * Sets the scope strategy for the current thread.
-   */
-  void setScopeStrategy(Scope.Strategy scopeStrategy);
-
-  /**
-   * Removes the scope strategy for the current thread.
-   */
-  void removeScopeStrategy();
+  <T> Factory<T> getFactory(Key<T> key);
 
   /**
    * Checks whether the container has a binding for given key.
diff --git a/src/com/google/inject/ContainerBuilder.java b/src/com/google/inject/ContainerBuilder.java
index 655a677..c5e7634 100644
--- a/src/com/google/inject/ContainerBuilder.java
+++ b/src/com/google/inject/ContainerBuilder.java
@@ -51,12 +51,16 @@
  */
 public final class ContainerBuilder {
 
+  private static final Logger logger =
+      Logger.getLogger(ContainerBuilder.class.getName());
+
   final List<BindingBuilder<?>> bindingBuilders =
       new ArrayList<BindingBuilder<?>>();
   final List<ConstantBindingBuilder> constantBindingBuilders =
       new ArrayList<ConstantBindingBuilder>();
   final List<LinkedBindingBuilder<?>> linkedBindingBuilders =
       new ArrayList<LinkedBindingBuilder<?>>();
+  final Map<String, Scope> scopes = new HashMap<String, Scope>();
 
   final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
 
@@ -85,18 +89,28 @@
 
   static final String UNKNOWN_SOURCE = "[unknown source]";
 
+  static final Scope DEFAULT_SCOPE = new Scope() {
+    public <T> Factory<T> scope(Key<T> key, Factory<T> creator) {
+      // We actually optimize around this.
+      throw new UnsupportedOperationException();
+    }
+  };
+
   /**
    * Constructs a new builder.
    */
   public ContainerBuilder() {
+    put(Scopes.DEFAULT, DEFAULT_SCOPE);
+    put(Scopes.SINGLETON, SingletonScope.INSTANCE);
+
     bind(Container.class).to(CONTAINER_FACTORY);
     bind(Logger.class).to(LOGGER_FACTORY);
   }
 
   /**
-   * Creates a source object to be associated with a binding. Called by
-   * default for each binding. The default implementation returns {@code
-   * ContainerBuilder}'s caller's {@code StackTraceElement}.
+   * Creates a source object to be associated with a binding. Useful for
+   * debugging. Called by default for each binding. The default implementation
+   * returns {@code ContainerBuilder}'s caller's {@code StackTraceElement}.
    *
    * <p>If you plan on manually setting the source (say for example you've
    * implemented an XML configuration), you might override this method and
@@ -112,6 +126,19 @@
   }
 
   /**
+   * Maps a {@link Scope} instance to a given name. Scopes should be mapped
+   * before used in bindings. @{@link Scoped#value()} references this name.
+   */
+  public void put(String name, Scope scope) {
+    if (scopes.containsKey(nonNull(name, "name"))) {
+      add(new ErrorMessage(source(), "Scope named '" + name
+          + "' is already defined."));
+    } else {
+        scopes.put(nonNull(name, "name"), nonNull(scope, "scope"));
+    }
+  }
+
+  /**
    * Binds the given key.
    */
   public <T> BindingBuilder<T> bind(Key<T> key) {
@@ -166,7 +193,7 @@
   }
 
   /**
-   * Binds string constants based on the given properties.
+   * Binds a string constant for each property.
    */
   public ContainerBuilder bindProperties(Map<String, String> properties) {
     ensureNotCreated();
@@ -180,7 +207,7 @@
   }
 
   /**
-   * Binds string constants based on the given properties.
+   * Binds a string constant for each property.
    */
   public ContainerBuilder bindProperties(Properties properties) {
     ensureNotCreated();
@@ -227,6 +254,7 @@
 
     HashMap<Key<?>, InternalFactory<?>> factories =
         new HashMap<Key<?>, InternalFactory<?>>();
+    ContainerImpl container = new ContainerImpl(factories);
 
     for (ConstantBindingBuilder builder : constantBindingBuilders) {
       if (builder.hasValue()) {
@@ -242,7 +270,7 @@
 
     for (BindingBuilder<?> builder : bindingBuilders) {
       final Key<?> key = builder.getKey();
-      final InternalFactory<?> factory = builder.getInternalFactory();
+      final InternalFactory<?> factory = builder.getInternalFactory(container);
       factories.put(key, factory);
 
       if (builder.isSingleton()) {
@@ -284,13 +312,12 @@
     // TODO: Handle this better.
     if (!errorMessages.isEmpty()) {
       for (ErrorMessage errorMessage : errorMessages) {
-        System.err.println(errorMessage);
-        throw new DependencyException("Configuration errors.");
+        logger.severe(errorMessage.toString());
       }
+      throw new ConfigurationException("We encountered configuration errors."
+        + " See the log for details.");
     }
 
-    final ContainerImpl container = new ContainerImpl(factories);
-
     container.injectStatics(staticInjections);
 
     if (loadSingletons) {
@@ -323,21 +350,9 @@
   }
 
   /**
-   * Implemented by classes which participate in building a container. Useful
-   * for encapsulating and reusing configuration logic.
-   */
-  public interface Command {
-
-    /**
-     * Configures the given builder.
-     */
-    void build(ContainerBuilder builder);
-  }
-
-  /**
    * Binds a {@link Key} to an implementation in a given scope.
    */
-  public class BindingBuilder<T> implements SourceAware<BindingBuilder<T>> {
+  public class BindingBuilder<T> {
 
     Object source = ContainerBuilder.UNKNOWN_SOURCE;
     Key<T> key;
@@ -352,7 +367,7 @@
       return key;
     }
 
-    public BindingBuilder<T> from(Object source) {
+    BindingBuilder<T> from(Object source) {
       this.source = source;
       return this;
     }
@@ -466,32 +481,79 @@
     }
 
     /**
-     * Specifies the scope.
+     * Specifies the scope. References the name passed to {@link
+     * ContainerBuilder#put(String, Scope)}.
      */
-    public BindingBuilder<T> in(Scope scope) {
-      if (this.scope != null) {
-        add(new ErrorMessage(source, "Scope set more than once."));
-      }
+    public BindingBuilder<T> in(String scopeName) {
+      ensureScopeNotSet();
 
-      this.scope = scope;
+      // We could defer this lookup to when we create the container, but this
+      // is fine for now.
+      this.scope = scopes.get(scopeName);
+      if (this.scope == null) {
+        add(new ErrorMessage(source, "Scope named '" + scopeName
+            + "' not found."));
+      }
       return this;
     }
 
-    InternalFactory<? extends T> getInternalFactory() {
+    /**
+     * Specifies the scope.
+     */
+    public BindingBuilder<T> in(Scope scope) {
+      ensureScopeNotSet();
+
+      this.scope = nonNull(scope, "scope");
+      return this;
+    }
+
+    private void ensureScopeNotSet() {
+      if (this.scope != null) {
+        add(new ErrorMessage(source, "Scope set more than once."));
+      }
+    }
+
+    InternalFactory<? extends T> getInternalFactory(
+        final ContainerImpl container) {
       // If an implementation wasn't specified, use the injection type.
       if (this.factory == null) {
         to(key.getTypeToken());
       }
 
-      if (scope == null) {
+      if (scope == null || scope == DEFAULT_SCOPE) {
         return this.factory;
       }
 
-      return scope.scopeFactory(key, this.factory);
+      // TODO: This is a little hairy.
+      final InternalFactory<? extends T> internalFactory = this.factory;
+      final Factory<T> factory = scope.scope(this.key, new Factory<T>() {
+        public T get() {
+          return container.callInContext(
+              new ContainerImpl.ContextualCallable<T>() {
+            public T call(InternalContext context) {
+              return internalFactory.get(context);
+            }
+          });
+        }
+
+        public String toString() {
+          return internalFactory.toString();
+        }
+      });
+
+      return new InternalFactory<T>() {
+        public T get(InternalContext context) {
+          return factory.get();
+        }
+
+        public String toString() {
+          return factory.toString();
+        }
+      };
     }
 
     boolean isSingleton() {
-      return this.scope == Scope.SINGLETON;
+      return this.scope == SingletonScope.INSTANCE;
     }
 
     /**
@@ -499,6 +561,7 @@
      */
     private class DefaultFactory<I extends T> implements InternalFactory<I> {
 
+      ContainerImpl container;
       volatile ContainerImpl.ConstructorInjector<I> constructor;
 
       private final TypeToken<I> implementation;
@@ -526,8 +589,7 @@
   /**
    * Builds a constant binding.
    */
-  public class ConstantBindingBuilder
-      implements SourceAware<ConstantBindingBuilder> {
+  public class ConstantBindingBuilder {
 
     final String name;
     Class<?> type;
@@ -554,7 +616,7 @@
       return new ConstantFactory<Object>(value);
     }
 
-    public ConstantBindingBuilder from(Object source) {
+    ConstantBindingBuilder from(Object source) {
       this.source = source;
       return this;
     }
@@ -642,8 +704,7 @@
   /**
    * Links one binding to another.
    */
-  public class LinkedBindingBuilder<T>
-      implements SourceAware<LinkedBindingBuilder<T>> {
+  public class LinkedBindingBuilder<T> {
 
     Key<T> key;
     Key<? extends T> destination;
@@ -665,7 +726,7 @@
       return destination;
     }
 
-    public LinkedBindingBuilder<T> from(Object source) {
+    LinkedBindingBuilder<T> from(Object source) {
       this.source = source;
       return this;
     }
@@ -678,4 +739,9 @@
       return this;
     }
   }
+
+  interface ContainerAwareFactory<T> extends Factory<T> {
+
+    void setContainer(ContainerImpl container);
+  }
 }
diff --git a/src/com/google/inject/ContainerImpl.java b/src/com/google/inject/ContainerImpl.java
index 68a6228..b8a6164 100644
--- a/src/com/google/inject/ContainerImpl.java
+++ b/src/com/google/inject/ContainerImpl.java
@@ -29,6 +29,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
+import java.lang.reflect.ParameterizedType;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -62,6 +63,25 @@
       return internalFactory;
     }
 
+    // Handle cases where T is a Factory<?>.
+    if (key.getTypeToken().getRawType().equals(Factory.class)) {
+      Type factoryType = key.getTypeToken().getType();
+      if (!(factoryType instanceof ParameterizedType)) {
+        return null;
+      }
+      Type entryType =
+          ((ParameterizedType) factoryType).getActualTypeArguments()[0];
+
+      // This can throw ConfigurationException.
+      final Factory<?> factory = getFactory(Key.get(entryType, key.getName()));
+      return new InternalFactory<T>() {
+        @SuppressWarnings({"unchecked"})
+        public T get(InternalContext context) {
+          return (T) factory;
+        }
+      };
+    }
+
     // Do we have a constant String factory of the same name?
     InternalFactory<String> stringFactory =
         (InternalFactory<String>) factories.get(
@@ -192,7 +212,7 @@
             injectors.add(injectorFactory.create(this, member, inject.value()));
           } catch (MissingDependencyException e) {
             if (inject.required()) {
-              throw new DependencyException(e);
+              throw new ConfigurationException(e);
             }
           }
         }
@@ -224,7 +244,8 @@
       factory = container.getFactory(field, key);
       if (factory == null) {
         throw new MissingDependencyException(
-            "No mapping found for dependency " + key + " in " + field + ".");
+            "No mapping found for dependency " + key + " for field: "
+                + field);
       }
 
       this.externalContext = ExternalContext.newInstance(field, key, container);
@@ -275,7 +296,8 @@
     InternalFactory<? extends T> factory = getFactory(member, key);
     if (factory == null) {
       throw new MissingDependencyException(
-          "No mapping found for dependency " + key + " in " + member + ".");
+          "No mapping found for dependency " + key + " for member: "
+              + member + "");
     }
 
     ExternalContext<T> externalContext =
@@ -314,7 +336,7 @@
 
       Type[] parameterTypes = method.getGenericParameterTypes();
       if (parameterTypes.length == 0) {
-        throw new DependencyException(
+        throw new ConfigurationException(
             method + " has no parameters to inject.");
       }
       parameterInjectors = container.getParametersInjectors(
@@ -362,7 +384,7 @@
                 inject.value()
             );
       } catch (MissingDependencyException e) {
-        throw new DependencyException(e);
+        throw new ConfigurationException(e);
       }
       injectors = container.injectors.get(implementation);
     }
@@ -374,7 +396,7 @@
           : implementation.getDeclaredConstructors()) {
         if (constructor.getAnnotation(Inject.class) != null) {
           if (found != null) {
-            throw new DependencyException("More than one constructor annotated"
+            throw new ConfigurationException("More than one constructor annotated"
                 + " with @Inject found in " + implementation + ".");
           }
           found = constructor;
@@ -389,7 +411,7 @@
       try {
         return implementation.getDeclaredConstructor();
       } catch (NoSuchMethodException e) {
-        throw new DependencyException("Could not find a suitable constructor"
+        throw new ConfigurationException("Could not find a suitable constructor"
             + " in " + implementation.getName() + ".");
       }
     }
@@ -485,14 +507,14 @@
     return parameters;
   }
 
-  void inject(Object o, InternalContext context) {
+  void injectMembers(Object o, InternalContext context) {
     List<Injector> injectors = this.injectors.get(o.getClass());
     for (Injector injector : injectors) {
       injector.inject(context, o);
     }
   }
 
-  <T> T inject(Class<T> implementation, InternalContext context) {
+  <T> T newInstance(Class<T> implementation, InternalContext context) {
     try {
       ConstructorInjector<T> constructor = getConstructor(implementation);
       return implementation.cast(
@@ -504,26 +526,6 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
-  <T> T getInstance(Class<T> type, String name, InternalContext context) {
-    ExternalContext<?> previous = context.getExternalContext();
-    Key<T> key = Key.get(type, name);
-    context.setExternalContext(ExternalContext.newInstance(null, key, this));
-    try {
-      InternalFactory<? extends T> factory = getFactory(null, key);
-      if (factory == null) {
-        throw new DependencyException("Missing binding for " + key + ".");
-      }
-      return factory.get(context);
-    } finally {
-      context.setExternalContext(previous);
-    }
-  }
-
-  <T> T getInstance(Class<T> type, InternalContext context) {
-    return getInstance(type, Key.DEFAULT_NAME, context);
-  }
-
   public boolean hasBindingFor(Key<?> key) {
     try {
       return getFactory(null, key) != null;
@@ -532,37 +534,46 @@
     }
   }
 
-  public void inject(final Object o) {
+  public void injectMembers(final Object o) {
     callInContext(new ContextualCallable<Void>() {
       public Void call(InternalContext context) {
-        inject(o, context);
+        injectMembers(o, context);
         return null;
       }
     });
   }
 
-  public <T> T inject(final Class<T> implementation) {
+  public <T> T newInstance(final Class<T> implementation) {
     return callInContext(new ContextualCallable<T>() {
       public T call(InternalContext context) {
-        return inject(implementation, context);
+        return newInstance(implementation, context);
       }
     });
   }
 
-  public <T> T getInstance(final Class<T> type, final String name) {
-    return callInContext(new ContextualCallable<T>() {
-      public T call(InternalContext context) {
-        return getInstance(type, name, context);
-      }
-    });
-  }
+  public <T> Factory<T> getFactory(final Key<T> key) {
+    final InternalFactory<? extends T> factory = getFactory(null, key);
 
-  public <T> T getInstance(final Class<T> type) {
-    return callInContext(new ContextualCallable<T>() {
-      public T call(InternalContext context) {
-        return getInstance(type, context);
+    if (factory == null) {
+      throw new ConfigurationException("Missing binding for " + key + ".");
+    }
+
+    return new Factory<T>() {
+      public T get() {
+        return callInContext(new ContextualCallable<T>() {
+          public T call(InternalContext context) {
+            ExternalContext<?> previous = context.getExternalContext();
+            context.setExternalContext(
+                ExternalContext.newInstance(null, key, ContainerImpl.this));
+            try {
+              return factory.get(context);
+            } finally {
+              context.setExternalContext(previous);
+            }
+          }
+        });
       }
-    });
+    };
   }
 
   ThreadLocal<InternalContext[]> localContext =
@@ -579,7 +590,7 @@
   <T> T callInContext(ContextualCallable<T> callable) {
     InternalContext[] reference = localContext.get();
     if (reference[0] == null) {
-      reference[0] = new InternalContext(this, localScopeStrategy.get());
+      reference[0] = new InternalContext(this);
       try {
         return callable.call(reference[0]);
       } finally {
@@ -609,17 +620,6 @@
     return constructors.get(implementation.getRawType());
   }
 
-  final ThreadLocal<Scope.Strategy> localScopeStrategy =
-      new ThreadLocal<Scope.Strategy>();
-
-  public void setScopeStrategy(Scope.Strategy scopeStrategy) {
-    this.localScopeStrategy.set(scopeStrategy);
-  }
-
-  public void removeScopeStrategy() {
-    this.localScopeStrategy.remove();
-  }
-
   /**
    * Injects a field or method in a given object.
    */
diff --git a/src/com/google/inject/Context.java b/src/com/google/inject/Context.java
index 866cc31..afab26d 100644
--- a/src/com/google/inject/Context.java
+++ b/src/com/google/inject/Context.java
@@ -31,27 +31,14 @@
   Container getContainer();
 
   /**
-   * Gets the current scope strategy. See {@link
-   * Container#setScopeStrategy(Scope.Strategy)}.
-   *
-   * @throws IllegalStateException if no strategy has been set
-   */
-  Scope.Strategy getScopeStrategy();
-
-  /**
    * Gets the field, method or constructor which is being injected. Returns
-   * {@code null} if the object currently being constructed is pre-loaded as
-   * a singleton or requested from {@link Container#getInstance(Class)}.
+   * {@code null} if the object isn't being directly injected (i.e. it's
+   * a preloaded singleton, returned from {@link Factory#get()}, etc.
    */
   Member getMember();
 
   /**
-   * Gets the type of the field or parameter which is being injected.
+   * Gets the binding key for the object currently being retrieved.
    */
-  Class<?> getType();
-
-  /**
-   * Gets the name of the injection specified by {@link @Inject#name()}.
-   */
-  String getName();
+  Key<?> getKey();
 }
diff --git a/src/com/google/inject/ExternalContext.java b/src/com/google/inject/ExternalContext.java
index c6a5e71..4e2c815 100644
--- a/src/com/google/inject/ExternalContext.java
+++ b/src/com/google/inject/ExternalContext.java
@@ -37,12 +37,8 @@
     this.container = container;
   }
 
-  public Class<T> getType() {
-    return key.getRawType();
-  }
-
-  public Scope.Strategy getScopeStrategy() {
-    return container.localScopeStrategy.get();
+  public Key<?> getKey() {
+    return this.key;
   }
 
   public Container getContainer() {
@@ -53,15 +49,10 @@
     return member;
   }
 
-  public String getName() {
-    return key.getName();
-  }
-
   public String toString() {
     return "Context" + new LinkedHashMap<String, Object>() {{
       put("member", member);
-      put("type", getType());
-      put("name", getName());
+      put("key", getKey());
       put("container", container);
     }}.toString();
   }
diff --git a/src/com/google/inject/InternalContext.java b/src/com/google/inject/InternalContext.java
index 322e065..d79b5d6 100644
--- a/src/com/google/inject/InternalContext.java
+++ b/src/com/google/inject/InternalContext.java
@@ -30,12 +30,10 @@
   final ContainerImpl container;
   final Map<Object, ConstructionContext<?>> constructionContexts =
       new HashMap<Object, ConstructionContext<?>>();
-  final Scope.Strategy scopeStrategy;
   ExternalContext<?> externalContext;
 
-  InternalContext(ContainerImpl container, Scope.Strategy scopeStrategy) {
+  InternalContext(ContainerImpl container) {
     this.container = container;
-    this.scopeStrategy = scopeStrategy;
   }
 
   public Container getContainer() {
@@ -46,15 +44,6 @@
     return container;
   }
 
-  Scope.Strategy getScopeStrategy() {
-    if (scopeStrategy == null) {
-      throw new IllegalStateException("Scope strategy not set. "
-          + "Please call Container.setScopeStrategy().");
-    }
-
-    return scopeStrategy;
-  }
-
   @SuppressWarnings("unchecked")
   <T> ConstructionContext<T> getConstructionContext(Object key) {
     ConstructionContext<T> constructionContext =
diff --git a/src/com/google/inject/Key.java b/src/com/google/inject/Key.java
index 32ffb43..2f9217f 100644
--- a/src/com/google/inject/Key.java
+++ b/src/com/google/inject/Key.java
@@ -26,12 +26,12 @@
  *
  * <p>For example, <tt>new Key&lt;List&lt;String>>("cities") {}</tt> will match:
  *
- * <tt>
- *   @Inject("cities")
+ * <pre>
+ *   &#64;Inject("cities")
  *   public void setList(List&lt;String> cities) {
  *     ...
  *   }
- * </tt>
+ * </pre>
  *
  * @author crazybob@google.com (Bob Lee)
  */
diff --git a/src/com/google/inject/SourceAware.java b/src/com/google/inject/Module.java
similarity index 66%
rename from src/com/google/inject/SourceAware.java
rename to src/com/google/inject/Module.java
index d97572c..814e291 100644
--- a/src/com/google/inject/SourceAware.java
+++ b/src/com/google/inject/Module.java
@@ -17,16 +17,13 @@
 package com.google.inject;
 
 /**
- * Implemented by classes which can remember their source.
- *
- * @author crazybob@google.com (Bob Lee)
+ * Implemented by classes which participate in building a container. Useful
+ * for encapsulating and reusing configuration logic.
  */
-interface SourceAware<R> {
+public interface Module {
 
   /**
-   * Sets the source object. Useful for debugging. Contents may include the
-   * name of the file and the line number this binding came from, a code
-   * snippet, etc.
+   * Configures the given builder.
    */
-  R from(Object source);
+  void configure(ContainerBuilder builder);
 }
diff --git a/src/com/google/inject/Scope.java b/src/com/google/inject/Scope.java
index 0db8887..c912189 100644
--- a/src/com/google/inject/Scope.java
+++ b/src/com/google/inject/Scope.java
@@ -1,206 +1,25 @@
-/**
- * Copyright (C) 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// Copyright 2006 Google Inc. All Rights Reserved.
 
 package com.google.inject;
 
-import java.util.concurrent.Callable;
-
 /**
- * Scope of an injected objects.
+ * A scope which bound objects can reside in. Add a new scope using {@link
+ * com.google.inject.ContainerBuilder#put(String, Scope)} and reference it from
+ * bindings using its name.
  *
- * @author crazybob
+ * @author crazybob@google.com (Bob Lee)
  */
-public enum Scope {
+public interface Scope {
 
   /**
-   * One instance per injection.
-   */
-  DEFAULT {
-    <T> InternalFactory<? extends T> scopeFactory(Key<T> key,
-        InternalFactory<? extends T> factory) {
-      return factory;
-    }
-  },
-
-  /**
-   * One instance per container.
-   */
-  SINGLETON {
-    <T> InternalFactory<? extends T> scopeFactory(Key<T> key,
-        final InternalFactory<? extends T> factory) {
-      return new InternalFactory<T>() {
-        T instance;
-        public T get(InternalContext context) {
-          synchronized (context.getContainer()) {
-            if (instance == null) {
-              instance = factory.get(context);
-            }
-            return instance;
-          }
-        }
-
-        public String toString() {
-          return factory.toString();
-        }
-      };
-    }
-  },
-
-  /**
-   * One instance per thread.
+   * Scopes a factory. The returned factory returns objects from this scope.
+   * If an object does not exist in this scope, the factory can use the given
+   * creator to create one.
    *
-   * <p><b>Note:</b> if a thread local object strongly references its {@link
-   * Container}, neither the {@code Container} nor the object will be
-   * eligible for garbage collection, i.e. memory leak.
+   * @param key binding key
+   * @param creator creates new instances as needed
+   * @return a new factory which only delegates to the given factory when an
+   *  instance of the requested object doesn't already exist in the scope
    */
-  THREAD {
-    <T> InternalFactory<? extends T> scopeFactory(Key<T> key,
-        final InternalFactory<? extends T> factory) {
-      return new InternalFactory<T>() {
-        final ThreadLocal<T> threadLocal = new ThreadLocal<T>();
-        public T get(final InternalContext context) {
-          T t = threadLocal.get();
-          if (t == null) {
-            t = factory.get(context);
-            threadLocal.set(t);
-          }
-          return t;
-        }
-
-        public String toString() {
-          return factory.toString();
-        }
-      };
-    }
-  },
-
-  /**
-   * One instance per request.
-   */
-  REQUEST {
-    <T> InternalFactory<? extends T> scopeFactory(final Key<T> key,
-        final InternalFactory<? extends T> factory) {
-      return new InternalFactory<T>() {
-        public T get(InternalContext context) {
-          Strategy strategy = context.getScopeStrategy();
-          try {
-            return strategy.findInRequest(
-                key, toCallable(context, factory));
-          } catch (Exception e) {
-            throw new RuntimeException(e);
-          }
-        }
-
-        public String toString() {
-          return factory.toString();
-        }
-      };
-    }
-  },
-
-  /**
-   * One instance per session.
-   */
-  SESSION {
-    <T> InternalFactory<? extends T> scopeFactory(final Key<T> key,
-        final InternalFactory<? extends T> factory) {
-      return new InternalFactory<T>() {
-        public T get(InternalContext context) {
-          Strategy strategy = context.getScopeStrategy();
-          try {
-            return strategy.findInSession(
-                key, toCallable(context, factory));
-          } catch (Exception e) {
-            throw new RuntimeException(e);
-          }
-        }
-
-        public String toString() {
-          return factory.toString();
-        }
-      };
-    }
-  },
-
-  /**
-   * One instance per wizard.
-   */
-  WIZARD {
-    <T> InternalFactory<? extends T> scopeFactory(final Key<T> key,
-        final InternalFactory<? extends T> factory) {
-      return new InternalFactory<T>() {
-        public T get(InternalContext context) {
-          Strategy strategy = context.getScopeStrategy();
-          try {
-            return strategy.findInWizard(
-                key, toCallable(context, factory));
-          } catch (Exception e) {
-            throw new RuntimeException(e);
-          }
-        }
-
-        public String toString() {
-          return factory.toString();
-        }
-      };
-    }
-  };
-
-  <T> Callable<? extends T> toCallable(final InternalContext context,
-      final InternalFactory<? extends T> factory) {
-    return new Callable<T>() {
-      public T call() throws Exception {
-        return factory.get(context);
-      }
-    };
-  }
-
-  /**
-   * Wraps factory with scoping logic.
-   */
-  abstract <T> InternalFactory<? extends T> scopeFactory(
-      Key<T> key, InternalFactory<? extends T> factory);
-
-  /**
-   * Pluggable scoping strategy. Enables users to provide custom
-   * implementations of request, session, and wizard scopes. Implement and
-   * pass to {@link
-   * Container#setScopeStrategy(com.google.inject.Scope.Strategy)}.
-   */
-  public interface Strategy {
-
-    /**
-     * Finds an object for the given type and name in the request scope.
-     * Creates a new object if necessary using the given factory.
-     */
-    <T> T findInRequest(Key<T> key,
-        Callable<? extends T> factory) throws Exception;
-
-    /**
-     * Finds an object for the given type and name in the session scope.
-     * Creates a new object if necessary using the given factory.
-     */
-    <T> T findInSession(Key<T> key,
-        Callable<? extends T> factory) throws Exception;
-
-    /**
-     * Finds an object for the given type and name in the wizard scope.
-     * Creates a new object if necessary using the given factory.
-     */
-    <T> T findInWizard(Key<T> key,
-        Callable<? extends T> factory) throws Exception;
-  }
+  public <T> Factory<T> scope(Key<T> key, Factory<T> creator);
 }
diff --git a/src/com/google/inject/Scoped.java b/src/com/google/inject/Scoped.java
index cf14329..acc7be4 100644
--- a/src/com/google/inject/Scoped.java
+++ b/src/com/google/inject/Scoped.java
@@ -22,8 +22,9 @@
 import java.lang.annotation.Target;
 
 /**
- * Annotates a scoped implementation class.
+ * Annotates an implementation class with the name of its scope.
  *
+ * @see com.google.inject.ContainerBuilder#put(String, Scope)
  * @author crazybob
  */
 @Target(ElementType.TYPE)
@@ -31,7 +32,7 @@
 public @interface Scoped {
 
   /**
-   * Scope.
+   * Scope name.
    */
-  Scope value();
+  String value();
 }
diff --git a/src/com/google/inject/Scopes.java b/src/com/google/inject/Scopes.java
new file mode 100644
index 0000000..51e99b5
--- /dev/null
+++ b/src/com/google/inject/Scopes.java
@@ -0,0 +1,21 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package com.google.inject;
+
+/**
+ * Scope constants.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public class Scopes {
+
+  /**
+   * Default scope's name. One instance per injection.
+   */
+  public static final String DEFAULT = Key.DEFAULT_NAME;
+
+  /**
+   * Singleton scope's name. One instance per {@link Container}.
+   */
+  public static final String SINGLETON = "singleton";
+}
\ No newline at end of file
diff --git a/src/com/google/inject/SingletonScope.java b/src/com/google/inject/SingletonScope.java
new file mode 100644
index 0000000..bb327bd
--- /dev/null
+++ b/src/com/google/inject/SingletonScope.java
@@ -0,0 +1,39 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package com.google.inject;
+
+/**
+ * Singleton scope. Returns one instance per {@link Container}.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+class SingletonScope implements Scope {
+
+  static final Scope INSTANCE = new SingletonScope();
+
+  private SingletonScope() {}
+
+  public <T> Factory<T> scope(Key<T> key, final Factory<T> creator) {
+    return new Factory<T>() {
+
+      T instance;
+
+      public T get() {
+        // Use a pretty coarse lock. We don't want to run into deadlocks when
+        // two threads try to load circularly-dependent singletons.
+        // Maybe one of these days we will identify independent graphs of
+        // singletons and offer to load them in parallel.
+        synchronized (Container.class) {
+          if (instance == null) {
+            instance = creator.get();
+          }
+          return instance;
+        }
+      }
+
+      public String toString() {
+        return creator.toString();
+      }
+    };
+  }
+}
diff --git a/src/com/google/inject/TypeToken.java b/src/com/google/inject/TypeToken.java
index ef2ec1e..05bac06 100644
--- a/src/com/google/inject/TypeToken.java
+++ b/src/com/google/inject/TypeToken.java
@@ -22,7 +22,8 @@
 import java.lang.reflect.ParameterizedType;
 
 /**
- * Represents a generic type {@code T}.
+ * Represents a generic type {@code T}. Due to erasure, Java doesn't provide
+ * a way to represent generic types. This class enables that.
  *
  * <p>Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
  * as a value (as opposed to identity) comparison.