Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Fixed most broken links, some misspelllings

...

The extensibility comes from the fact that multiple modules may all contribute to the same service configuration:

...

Because Tapestry IoC is highly dynamic (it scans the visible JAR manifest files to identify module classes), the FileServicerDispatcher service may be in one module, and the other contributing modules (such as the one that contributes the Office file services) may be written at a much later date. With no change to the FileServicerDispatcher service or its module class, the new services "plug into" the overall solution, simply by having their JAR's on the runtime classpath.

Naming conventions vs. Annotations

...

If you prefer annotations over naming conventions you can use the @Contribute annotation. As of version 5.2 this annotation that may be placed on a contributor method of a module instead of starting the methods name with "contribute". The value of the annotation is the type of the service to contribute into.

...

In this example, the method will only be invoked when constructing a service configuration where the service itself has both the Red and Blue marker annotations. Tapestry knows which annotations are marker annotations, and which marker annotations apply to the service, via the @Marker annotation on the service implementation.

If the special @Local annotation is present, then contribution is made only to the configuration of a service being constructed in the same module.

...

  • Unordered Collection. Contributions are simply added in and order is not important.
  • Ordered List. Contributions are provided as an ordered list. Contributions must establish the order by giving each contributed object a unique id, by establishing forward and backward dependencies between the values.
  • Map. Contributions provide unique keys and corresponding values.

Unordered Collection

A service builder method can collect an unordered list of values by defining a parameter of type java.util.Collection. Further, you should parameterize the type of collection. Tapestry will identify the parameterized type and ensure that all contributions match.

...

On the contribution side, a service contribution method sees a Configuration object:

Code Block
java
java
  public static void contributeStartup(Configuration<Runnable> configuration)
  {
    configuration.add(new JMSStartup());
    configuration.add(new FileSystemStartup());
  }    

The Configuration interface defines just a single method: add(). This is very intentional: the only thing you can do is add new items. If we passed in a Collection, you might be tempted to check it for values, or remove them ... but that flys in the face of the fact that the order of execution of these service contribution methods is entirely unknown.

...

Again, the order in which service contribution methods are invoked is unknown. Therefore, the order in which objects are added to the configuration is not known. Instead, we enforce an order on the items after all the contributions have been added. As with service decorators, we set the order by giving each contributed object a unique id, and identifying (by id) which items must preceded it in the list, and which must follow.

...

For our service contribution methods, we must provide a parameter of type OrderedConfiguration:

Code Block
java
java
  public static void contributeStartup(OrderedConfiguration<Runnable> configuration)
  {
    configuration.add("JMS", new JMSStartup());
    configuration.add("FileSystem", new FileSystemStartup(), "after:CacheSetup");
  }    

...

For the "FileSystem" contribution, a constraint has been specified, indicating that FileSystem should be ordered after some other contribution named "CacheSetup". Any number of such ordering constraints may be specified (the add() method accepts a variable number of arguments).

...

Null values, once ordered, are editted edited out (the List passed to the service builder method does not include any nulls). Again, they are allowed as placeholders, for the actual contributed objects to organize themselves around.

...

For mapped configurations where the key type is String, a CaseInsensitiveMap will be automatically used (and passed to the service builder method), to help ensure that case insensitivity is automatic and pervasive.

...

All three configuration interfaces have a second method, addInstance(). This method takes a class, not an instance. The class is instantiated and contributed. If the constructor for the class takes dependencies, those are injected as well.

...

In addition to injecting services into a contributor method (via the @InjectService and @Inject annotations), Tapestry will key off of the parameter type to allow other things to be injected.

  • ObjectLocator: access to other services visible to the contributing module
  • org.slf4j.Logger: the Logger for the service being contributed to
    No annotation is needed for these cases.

Configuration Overrides

Since
since

...

5.1

The OrderedConfiguration and MappedConfiguration interfaces now support overrides. An override is a replacement for a normally contributed object. An override must match a contributed object, and each contributed object may be overidden overridden at most once.

The new object replaces the original object; alternately, you may override the original object with null.

...

In Tapestry 5.0, services that wanted to support this kind of override behavior had to implement it on an ad-hoc basis, such as ApplicationDefaults overriding FactoryDefaults. In many cases, that is stil still useful.