You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2006/07/07 00:40:19 UTC

svn commit: r419727 - in /tapestry/tapestry5/tapestry-core/trunk: ./ src/main/java/org/apache/tapestry/internal/ioc/ src/main/java/org/apache/tapestry/ioc/ src/main/java/org/apache/tapestry/ioc/annotations/ src/main/java/org/apache/tapestry/test/ src/s...

Author: hlship
Date: Thu Jul  6 15:40:18 2006
New Revision: 419727

URL: http://svn.apache.org/viewvc?rev=419727&view=rev
Log:
Initial documentation concerning Tapestry IoC.
Support a Log for each service, anonymously injectable, or via ServiceResources.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/InjectService.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/index.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
Modified:
    tapestry/tapestry5/tapestry-core/trunk/pom.xml
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceResources.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/pom.xml?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/pom.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/pom.xml Thu Jul  6 15:40:18 2006
@@ -92,7 +92,9 @@
             -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <!-- Had a classloader problem with version 2.0.3 -->
+                <version>2.0</version>
                 <configuration>
                     <tags>
                         <tag>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/ioc/BasicServiceCreator.java Thu Jul  6 15:40:18 2006
@@ -15,10 +15,10 @@
 package org.apache.tapestry.internal.ioc;
 
 import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
 
+import org.apache.commons.logging.Log;
 import org.apache.tapestry.ioc.ErrorLog;
 import org.apache.tapestry.ioc.ServiceResources;
 import org.apache.tapestry.ioc.def.ServiceDef;
@@ -55,6 +55,7 @@
         _parameterDefaults.put(String.class, _serviceId);
         _parameterDefaults.put(ServiceResources.class, resources);
         _parameterDefaults.put(ErrorLog.class, _log);
+        _parameterDefaults.put(Log.class, resources.getServiceLog());
         _parameterDefaults.put(Class.class, serviceDef.getServiceInterface());
     }
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceResources.java?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceResources.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/ServiceResources.java Thu Jul  6 15:40:18 2006
@@ -14,6 +14,8 @@
 
 package org.apache.tapestry.ioc;
 
+import org.apache.commons.logging.Log;
+
 /**
  * Contains resources that may be provided to a service when it initializes, which includes other
  * services visible to the service.
@@ -47,4 +49,12 @@
 
     /** Returns an error log appropriate for the service. */
     ErrorLog getErrorLog();
+
+    /**
+     * Returns a Log object appropriate for logging messages. Use of {@link #getErrorLog()} is
+     * better, but that's only for error situations, not ordinary logging (for debug of
+     * informational purposes).
+     */
+
+    Log getServiceLog();
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/InjectService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/InjectService.java?rev=419727&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/InjectService.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ioc/annotations/InjectService.java Thu Jul  6 15:40:18 2006
@@ -0,0 +1,39 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// 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.
+
+package org.apache.tapestry.ioc.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Documented
+/**
+ * Annotation used with parameters of builder methods to identify the service to be injected into
+ * the builder method via the parameter.
+ */
+public @interface InjectService {
+
+    /**
+     * The id of the service to inject; either a fully qualified id, or the unqualified id of a
+     * service within the same module.
+     */
+    String value();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/BaseTestCase.java Thu Jul  6 15:40:18 2006
@@ -187,4 +187,11 @@
         return newMock(ServiceDef.class);
     }
 
+    protected final void trainGetServiceLog(ServiceResources resources, Log log)
+    {
+        resources.getServiceLog();
+        setReturnValue(log);
+    
+    }
+
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/index.apt?rev=419727&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/index.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/index.apt Thu Jul  6 15:40:18 2006
@@ -0,0 +1,158 @@
+ ----
+ Tapestry IoC Introduction
+ ----
+ 
+Tapestry Inversion of Control Container
+
+  The inner construction of the Tapestry framework is based on {{{http://www.martinfowler.com/articles/injection.html}inversion of control}},
+  a design approach that allows a working system to be fabricated from many small, easily testable pieces.
+  
+  An additional benefit of using IoC (Inversion of Control) is that, by breaking a complex system into small pieces, it becomes easier to
+  modify and extend the system, but overriding or replacing small pieces of the system.
+  
+  The use of IoC in Tapestry represents an evolution from Tapestry 3 to Tapestry 4 to Tapestry 5.  Tapestry 3 did not use IoC, though it included
+  some weaker mechanisms, such as extensions, that served a similar purpose.  To make large scale changes to the behavior of Tapestry 3 required
+  subclassing key classes and overriding methods.
+  
+  Tapestry 4 introduced the use of the {{{http://hivemind.apache.org/}HiveMind}} IoC container.  In fact, the HiveMind project was created 
+  specifically for use as the IoC container for Tapestry 4.  Tapestry 4 has met its goals for extensibility and configurability, largely
+  because of HiveMind's flexibility.
+  
+  Tapestry 5 extends on this, replacing HiveMind with a new container built into the framework,
+  designed for greater ease of use and expressiveness.
+  
+* Why Not Spring?
+
+  {{{http://www.springframework.org}Spring}} is the most successful IoC container project. The Spring project combines a very good IoC container,
+  integrated {{{http://aspectj.org}AspectJ}} support, and a large number of libraries built on top of the container. Spring is an excellent
+  <application> container, but lacks a number of features necessary for a <framework> container:
+  
+  * Spring does not have the concept of a <namespace>.  The names of beans are simple and unqualified, which could lead to naming conflicts.
+  
+  * Spring beans can be wired together by name (or id), but it is not possible to introduce additional naming abstractions. Tapestry 4's 
+    "infrastructure:" abstraction was the key to allowing easy spot overrides of internal Tapestry services.
+    
+  * Spring has a simple map/list/value configuration scheme, but it is not distributed; it is part of a single bean definition. 
+    HiveMind and Tapestry 5 IoC allow service configuration to be assembled from multiple modules. This is very important
+    for seamless extensibility of the framework.
+  
+* Why Not HiveMind?
+
+  The difficulty of managing the release schedules of two complex frameworks has proven to be an issue. HiveMind's 2.0 release will
+  incorporate similar ideas to Tapestry 5 IoC, but will also maintain legacy support for the existing XML-driven approach.
+  
+  The use of HiveMind is also related to one of the common criticisms of Tapestry 4: startup time. The time it takes to parse and
+  organize all that XML shows up as several seconds of startup time. It is <hoped> that creating a streamlined IoC container that is not
+  driven by XML will alleviate those issues.
+  
+  With the advent of new technologies (in particular, 
+  {{{http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html}JDK 1.5 Annotations}}, 
+  and runtime class generation via 
+  {{{http://www.jboss.org/products/javassist}Javassist}})
+  some of the precepts of HiveMind have been undermined.  That is to say, in HiveMind (and Spring), all that XML is an awkward
+  way to describe a few basic Java operations: instantiating classes and invoking methods on those classes (to inject
+  dependencies into the instantiated instances).  The central concept in Tapestry IoC is to eliminate XML and build an equivalent
+  system around simple objects and methods.
+  
+Goals
+
+  As with Tapestry 5 in general, the goal of Tapestry IoC is greater simplicity, greater power, and an avoidance of XML.
+  
+  The Java language is the easiest and most succinct way to describe object creation and method invocation. Any approximation in
+  XML is ultimately more verbose and unwieldy.  As the {{{module.html}examples}} show, a small amount of Java code is simpler
+  and easier than a big chunk of XML.
+
+  In addition, moving from XML to Java code makes things easier to test; you can unit test the builder methods of your
+  module builder class, but you can't realistically unit test an XML descriptor.
+  
+  Modules should be easily packaged into JAR files and should be zero-configuration (just drop the JAR onto the classpath).
+  
+  Another goal is "developer friendliness". This is a true cross-cutting concern, and one not likely to be packaged
+  into an aspect any time soon. The Tapestry IoC framework is designed to be easy to use and easy to understand.
+  Further, when things go wrong, it actively attempts to help you by careful checks and careful error messages. Further,
+  all user-visible objects implements {{{http://howardlewisship.com/blog/2003/08/importance-of-tostring.html}a reasonable toString() method}},
+  to help you understand what's going when you inevitably try to figure things out in the debugger. 
+  
+  In terms of building services using Tapestry IoC ... the objective here is "lightness", a term borrowed from the board
+  game {{{http://boardgamegeek.com/game/188}Go}}.  In Go, groups of playing stones are "light" (or have "good shape")
+  when the minimum number of them control the maximum area on the board.  Playing "heavy" just gives your opponent a free
+  chance to take control of another section of the board.
+  
+  When building a registry of services, lightness refers to the proper division of responsibility, the seperation of
+  concerns, and the limiting of dependencies between different parts of the system. This style is often
+  called {{{http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html}Law of Demeter}}.
+  Using an IoC container makes it easier to embrace this approach, since one critical concern, which objects are responsible for 
+  instantiating which others, is entirely managed by the container. With this lifecycle concern removed, it becomes very
+  easy to reduce complex chunks of code into small, testable, reusable services.
+  
+  "Light" means:
+  
+  * Small interfaces of two or three methods.
+  
+  * Small methods, with two or three parameters (because dependencies are injected in behind the scenes, rather than
+    passed into the method).
+    
+  * Anonymous communication via events, rather than explicit method invocations. The service implementation can
+    implement an event listener interface.
+  
+  []
+  
+  See {{{http://www.pragmaticprogrammer.com/ppbook/index.shtml}The Pragmatic Programmer}} for more insights into
+  building solid code.
+  
+Terminology
+
+  The basic unit in Tapestry IoC is a <<service>>.  A service consists of a <<service interface>> and a <<service implementation>>.
+  The service interface is an ordinary Java interface.  The service implementation is a Java object that implements the 
+  service interface.  Often there will
+  only be a single service per service interface, but in some situations, there may be many different services and service implementations
+  all sharing the same service interface.
+  
+  Services have a visibility: either public (the default) or private (only visible within the same module).  <Not yet implemented>
+  
+  Services are identified by a unique id, which combines an unqualified id for the service with the containing module's id (see below).
+  Typically, a service id matches the name of the service interface.
+  
+  Services are aggregated into <<modules>>:
+  
+  * A module defines a <<module id>> that is used as a prefix when naming services within the module. This is very much equivalent
+    to a Java package name.  Module ids must be unique within the registry of modules.
+    
+  * A module is defined by a <<module builder>>, a specific class that is intantiated.
+  
+  * Methods on the builder class define the services provided by the module, and the same methods are responsible
+    for instantiating the service implementation.
+    
+  []
+  
+  The methods which define and construct services are called <<builder methods>>.
+  
+  The <<registry>> is the outside world's view of the modules and services. From the registry, it is possible to obtain
+  a service, via its qualified id or by its service interface. 
+    
+  Services may be <<intercepted>>.  Interceptors are new classes that implement the service interface, and wrap around the service implementation.
+  A service may have multiple interceptors, forming a chain of delegation.  
+  
+  Interceptors are defined by additional methods on the module builder. <TBD>.
+  Control is given over the order in which interceptors are applied to a service.
+  
+  A service may have a <<configuration>>. The configuration is either a map, a collection, or an ordered list. The configuration is contructed
+  from <<contributions>> provided by one or more modules. 
+  
+  <Note: In HiveMind, services and configurations were separate, which often lead
+  to linked pairs of similarily named services and configurations. For Tapestry IoC, each service is allowed to have a single configuration,
+  which is normally sufficient.>
+  
+  Services are typically instantiated as needed. In this case, "need" translates to "when a method of the service is invoked".
+  In nearly all cases, a service is represented (to the outside world, or to other services) as a <<proxy>> that implements
+  the service interface. The first time a method is invoked on the proxy, the full service (implementation and interceptors) is
+  constructed. This occurs in a completely <<thread-safe>> manner.
+  
+  Services define a <<lifecycle>> that controls when the service is constructed.  The default lifecycle is <<singleton>>, meaning a single
+  global instance created as needed.  Other lifecycles allow service implementations to be bound to the current thread (i.e., the current
+  request in a servlet application).
+  
+  <<Dependencies>> are other services (or other objects) that are needed by a service implementation. These 
+  dependencies can be <<injected>> into a builder method and provided, from there, to a service implementation via
+  its constructor, or via methods on the service implementation.
+  
\ No newline at end of file

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt?rev=419727&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/module.apt Thu Jul  6 15:40:18 2006
@@ -0,0 +1,137 @@
+ ---
+ Tapestry IoC Modules
+ ---
+ 
+Tapestry IoC Modules
+ 
+  You inform Tapestry about your services and contributions by providing a module builder class.
+
+  The module builder is a plain Java class.  A system of annotations and naming conventions allow
+  Tapestry to determine what services are provided by the module.
+
+  A module bulider defines builder methods, one for each service provided by the module.
+
+  Builder methods are public methods. Here's a trivial example:
+
++-----------------------------------------------------------------------------------+
+package org.example.myapp.services;
+
+public class MyAppModule
+{
+  public Indexer buildIndexer()
+  {
+    return new IndexerImpl();
+  }
+}
++-----------------------------------------------------------------------------------+
+
+  By default, a module's id is the same as its package name (we'll see how to override
+  that shortly).  Here the module id will be org.example.myapp.services.
+
+  Any public method whose name starts with "build" is a builder method, implicitly
+  defining a service within the module.  Here we're defining a service around
+  the Indexer service interface (presumably also in the org.example.myapp.services
+  package).
+
+  The service's unqualified id (the part after the module id) is derived from the method name.
+  Here "build" was stripped of "buildIndexer", leaving "Indexer".  That's the unqualified id.
+  Prefixing with the module id results in the fully qualfied id 
+  org.example.myapp.services.Indexer.
+
+  We could extend this example by adding additional builder methods, or by showing
+  how to inject dependencies. See {{{service.html}the service documentation}} for 
+  more details.
+
+Overriding the Module id
+
+  Adding an {{{../apidocs/org/apache/tapestry/ioc/annotations/Id.html}@Id annnotation}}
+  to the module builder class will control the module's id.
+  
++-----------------------------------------------------------------------------------+
+package org.example.myapp.services;
+
+@Id("myapp")
+public class MyAppModule
+{
+  public Indexer buildIndexer()
+  {
+    return new IndexerImpl();
+  }
+}
++-----------------------------------------------------------------------------------+
+
+  This time, the module's id is "myapp" and the service's id is "myapp.Indexer".
+  
+  Remember that module ids must be unique, no other module builder class, even one
+  in a different package, may declare the id "myapp", or runtime warnings or
+  errors will occur.
+  
+  
+Autoloading modules
+
+  When setting up the registry, Tapestry can automatically locate modules packaged into JARs.
+  It does this by searching for a particular global manifest entry.
+  <Note: Not yet implemented.>
+  
+  
+  The manifest entry name is "Tapestry-Module-Classes".  The value is a comma-seperated list
+  of fully qualified class names of module builder classes.  Whitespace is ignored.
+  
+  Example:
+  
++-----------------------------------------------------------------------------------+
+Manifest-Version: 1.0
+Tapestry-Module-Classes: org.example.mylib.LibModule, org.example.mylib.internal.InternalModule
++-----------------------------------------------------------------------------------+
+
+  If you are using Maven 2, then  the easiest way to get such entries into your JAR's manifest
+  is as simple as some configuration in your pom.xml:
+  
++-----------------------------------------------------------------------------------+
+<project>
+  . . .
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestEntries>
+              <Tapestry-Module-Classes>org.example.mylib.LibModule, 
+                org.example.mylib.internal.InternalModule</Tapestry-Module-Classes>
+            </manifestEntries>
+          </archive>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  . . .
+</project>
++-----------------------------------------------------------------------------------+
+  
+  
+  More details are provided in the 
+  {{{http://maven.apache.org/guides/mini/guide-manifest.html}Maven Manifest Guide}}.
+  
+
+Module Builder Implementation Notes
+
+  Module builder classes are designed to be very, very simple to implement.
+  
+  They must have a no-arguments public constructor.
+  
+  You should <<not>> attempt to cache services. There is really no way to
+  determine in what order methods of the builder class will be invoked. Because
+  services are generally instantiated only as needed, methods will be
+  invoked in an arbitrary order, and some may never be invoked.
+  
+  Again, keep the methods very simple. Use {{{service.html}parameter injection}}
+  to gain access to the dependencies you need. Don't worry about caching, caching of
+  services is the responsibility of Tapestry.
+  
+  Be careful about inheritance. Tapestry will see all <public> methods,
+  even those inherited from base classes.  Tapestry <only> sees public methods.  
+  
+  By convention, module builder class names end in Module.
+  
\ No newline at end of file

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt?rev=419727&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/ioc/service.apt Thu Jul  6 15:40:18 2006
@@ -0,0 +1,144 @@
+ ----
+ Tapestry IoC Services
+ ----
+ 
+Tapestry IoC Services
+
+  Services consist of two main parts: a service interface and a service implementation.
+  
+  The service interface is how the service will be represented throughout the rest of the
+  registry. Since what gets passed around is normally a proxy, you can't expect to cast a service
+  object down to the implementation class (you'll get see ClassCastException instead). In other
+  words, you should be careful to ensure that your service interface is complete, since
+  Tapestry IoC effectively walls you off from backdoors such as casts.
+  
+  Tapestry doesn't know how to instantiate and configure your service; instead it relies
+  on you to provide the code to do so, in a builder method:
+  
++-----------------------------------------------------------------------------------+
+package org.example.myapp.services;
+
+@Id("myapp")
+public class MyAppModule
+{
+  public Indexer buildIndexer()
+  {
+    return new IndexerImpl();
+  }
+}
++-----------------------------------------------------------------------------------+
+
+  Here the service interface is Indexer (presumably inside the org.example.myapp.services package,
+  since there isn't an import).  Tapestry doesn't know about the IndexerImpl class (the
+  service implementation of the Indexer service), but it does know 
+  about the buildIndexer() method.
+  
+Injecting Dependencies
+
+  It's pretty unlikely  that your service will be able to operate in a total vacuum. It will
+  have other dependencies.  For example, let's say the Indexer needs a JobScheduler to control
+  when it executes, and a FileSystem to access files and store indexes.
+  
++-----------------------------------------------------------------------------------+
+  public Indexer buildIndexer(@InjectService("JobScheduler")
+    JobScheduler scheduler, @InjectService("FileSystem")
+    FileSystem fileSystem)
+    {
+      IndexerImpl indexer = new IndexerImpl(fileSystem);
+      
+      scheduler.scheduleDailyJob(indexer);
+      
+      return indexer;
+    }
++-----------------------------------------------------------------------------------+
+
+  Here we've annotated the parameters of the builder method to identify what
+  service to inject for that parameter.  We used unqualified ids ... these are the names
+  of other services within the <same module>: there will be a buildJobScheduler()
+  and a buildFileSystem() builder methods as well.
+  
+  Note that we don't invoke those builder methods ... we just "advertise" that we need
+  the named services.  Tapestry IoC will provide the necessary proxies and, when we start to
+  invoke methods on those proxies, will ensure that the full service, including its
+  interceptors and its dependencies, are ready to go.    
+  
+  If we used fully qualified service ids, such as "org.examples.myapps.jobs.JobScheduler",
+  then we can access services from some other module entirely.
+  
+  <Note: Not yet implemented.>
+  
+Defining Visibility
+
+  Normally, a service can be referenced from any other module, simply by providing a
+  fully qualified service id.
+  
+  In some cases, it is desirable to mark a service a private, in which case, it is only
+  visible within the same module.
+  
+  The {{{../apidocs/org/apache/tapestry/ioc/annotations/Private.html}@Private annotation}} can
+  be attached to a builder method to indicate that the service in question is private.
+
+  <Note: Not yet implemented.>  
+  
+Defining Service Lifecycle
+
+  <TBD>
+    
+Injecting Resources
+
+  In addition to injecting services, Tapestry will key off the parameter type to allow
+  other things to be injected.
+  
+  * java.lang.String: fully qualified service id for the service being created
+  
+  * {{{../apidocs/org/apache/tapestry/ioc/ErrorLog.html}ErrorLog}}: to which errors and warnings can be logged
+  
+  * java.lang.Class: service interface implemented by the service to be constructed
+  
+  * {{{../apidocs/org/apache/tapestry/ioc/ServiceResources.html}ServiceResources}}:  access to other services
+  
+  []
+  
+  No annotation is needed for these cases.
+  
+  Example:
+  
++-----------------------------------------------------------------------------------+
+  public Indexer buildIndexer(String serviceId, Log serviceLog, @InjectService("JobScheduler")
+    JobScheduler scheduler, @InjectService("FileSystem")
+    FileSystem fileSystem)
+    {
+      IndexerImpl indexer = new IndexerImpl(serviceLog, fileSystem);
+      
+      scheduler.scheduleDailyJob(serviceId, indexer);
+      
+      return indexer;
+    }
++-----------------------------------------------------------------------------------+  
+  
+  The order of parameters is completely irrelevant. They can come first or last or be
+  interspersed however you like.
+  
+Unspecified Injection
+
+  When injecting another service, you may choose to not provide the @InjectService annotation.
+  
+  Tapestry will search the registry for service that implements the exact service interface (determined
+  from the parameter type).  If it finds exactly one match, then the corresponding service will be
+  injected.
+  
+  If it finds more than one match, that's an error.  
+  
+  Obviously, this is only useful when you can be sure that there's only one service in the entire registry
+  that implements the service interface.  When you are building a framework for others to use, you should
+  not use this feature ... it's all too likely that some end-user application will create a second service
+  with the same implementation and break your injections.
+  
+  On the other hand, if you are using Tapestry IoC as part of an application, then you can save yourself
+  a small amount of effort and maintenance by letting Tapestry automatically identify dependencies.
+  
+  <Note: Not yet implemented.>
+  
+    
+        
+        
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Thu Jul  6 15:40:18 2006
@@ -37,7 +37,6 @@
     <body>
         <links>
             <item name="Tapestry" href="http://tapestry.apache.org/" />
-            <item name="Hivemind" href="http://jakarta.apache.org/hivemind/" />
             <item name="Apache" href="http://www.apache.org/" />
         </links>
         
@@ -50,7 +49,13 @@
             <item name="Introduction" href="/index.html"/>
             <item name="Upgrade from Tapestry 4" href="/upgrade.html"/>
         </menu> 
-        
+        
+        <menu name="IoC Container">
+            <item name="Introduction" href="ioc/index.html"/>
+            <item name="Modules" href="ioc/module.html"/>
+            <item name="Services" href="ioc/service.html"/>
+        </menu>
+                
         ${reports} 
         
     </body>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java?rev=419727&r1=419726&r2=419727&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/BasicServiceCreatorTest.java Thu Jul  6 15:40:18 2006
@@ -17,10 +17,12 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
+import org.apache.commons.logging.Log;
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.ErrorLog;
 import org.apache.tapestry.ioc.ServiceResources;
+import org.apache.tapestry.ioc.annotations.InjectService;
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -45,6 +47,8 @@
 
     private Class _expectedServiceInterface;
 
+    private Log _expectedLog;
+
     private Method findMethod(String name)
     {
         return findMethod(this, name);
@@ -67,14 +71,11 @@
     {
         ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
-        ErrorLog log = newErrorLog();
+        ErrorLog errorLog = newErrorLog();
+        Log log = newLog();
         _fie = newFieService();
 
-        trainGetServiceId(def, SERVICE_ID);
-
-        trainGetErrorLog(resources, log);
-
-        trainGetServiceInterface(def, FieService.class);
+        trainForConstructor(def, resources, errorLog, log);
 
         replay();
 
@@ -93,25 +94,34 @@
         verify();
     }
 
+    private void trainForConstructor(ServiceDef def, ServiceResources resources, ErrorLog errorLog, Log log)
+    {
+        trainGetServiceId(def, SERVICE_ID);
+
+        trainGetErrorLog(resources, errorLog);
+
+        trainGetServiceLog(resources, log);
+
+        trainGetServiceInterface(def, FieService.class);
+    }
+
     @Test
     public void argsMethod()
     {
         ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
-        ErrorLog log = newErrorLog();
+        ErrorLog errorLog = newErrorLog();
+        Log log = newLog();
 
-        _expectedErrorLog = log;
+        _expectedErrorLog = errorLog;
         _expectedServiceId = SERVICE_ID;
         _expectedServiceInterface = FieService.class;
         _expectedServiceResources = resources;
+        _expectedLog = log;
 
         _fie = newFieService();
 
-        trainGetServiceId(def, SERVICE_ID);
-
-        trainGetErrorLog(resources, log);
-
-        trainGetServiceInterface(def, FieService.class);
+        trainForConstructor(def, resources, errorLog, log);
 
         trainGetBuilderMethod(def, findMethod("build_args"));
 
@@ -131,14 +141,12 @@
     {
         ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
-        ErrorLog log = newErrorLog();
-        _fie = null;
+        ErrorLog errorLog = newErrorLog();
+        Log log = newLog();
 
-        trainGetServiceId(def, SERVICE_ID);
+        _fie = null;
 
-        trainGetErrorLog(resources, log);
-
-        trainGetServiceInterface(def, FieService.class);
+        trainForConstructor(def, resources, errorLog, log);
 
         trainGetBuilderMethod(def, findMethod("build_noargs"));
 
@@ -169,14 +177,12 @@
     {
         ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
-        ErrorLog log = newErrorLog();
-        _fie = null;
+        ErrorLog errorLog = newErrorLog();
+        Log log = newLog();
 
-        trainGetServiceId(def, SERVICE_ID);
-
-        trainGetErrorLog(resources, log);
+        _fie = null;
 
-        trainGetServiceInterface(def, FieService.class);
+        trainForConstructor(def, resources, errorLog, log);
 
         trainGetBuilderMethod(def, findMethod("build_fail"));
 
@@ -211,14 +217,12 @@
     {
         ServiceDef def = newServiceDef();
         ServiceResources resources = newServiceResources();
-        ErrorLog log = newErrorLog();
-        _fie = newFieService();
-
-        trainGetServiceId(def, SERVICE_ID);
+        ErrorLog errorLog = newErrorLog();
+        Log log = newLog();
 
-        trainGetErrorLog(resources, log);
+        _fie = newFieService();
 
-        trainGetServiceInterface(def, FieService.class);
+        trainForConstructor(def, resources, errorLog, log);
 
         Method method = findMethod("build_invalidargs");
 
@@ -228,7 +232,7 @@
 
         trainGetBuilderMethod(def, method);
 
-        log.warn(IOCMessages.unknownBuilderParameter(Object.class, method, SERVICE_ID), null);
+        errorLog.warn(IOCMessages.unknownBuilderParameter(Object.class, method, SERVICE_ID), null);
 
         replay();
 
@@ -257,18 +261,25 @@
         return _fie;
     }
 
+    public FieService build_injected(@InjectService("Foe")
+    FoeService foe)
+    {
+        return _fie;
+    }
+
     public FieService build_fail()
     {
         throw new RuntimeException("Method failed.");
     }
 
     public FieService build_args(String serviceId, ServiceResources resources, ErrorLog errorLog,
-            Class serviceInterface)
+            Class serviceInterface, Log log)
     {
         assertEquals(serviceId, _expectedServiceId);
         assertSame(resources, _expectedServiceResources);
         assertSame(errorLog, _expectedErrorLog);
         assertSame(serviceInterface, _expectedServiceInterface);
+        assertSame(log, _expectedLog);
 
         return _fie;
     }