Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Wiki Markup
{scrollbar}

Tapestry Inversion of Control Container

Main article: Tapestry IoC

Contents

Table of Contents
excludeContents|Tapestry Inversion of Control Container|Related Articles
printablefalse

 

Div
stylefloat:right
titleRelated Articles
classaui-label
Content by Label
showLabelsfalse
showSpacefalse
titleRelated Articles
cqllabel = "ioc" and space = currentSpace()

Why do I need to define an interface for my services? Why can't I just use the class itself?

First of all: you can do exactly this, but you lose some of the functionality that Tapestry's IoC container provides.

...

The final reason for the service interface / implementation split is to nudge you towards always coding to an interface, which has manifest benefits for code structure, robustness, and testability.

My service starts a thread; how do I know when the application is shutting down, to stop that thread?

This same concern applies to any long-lived resource (a thread, a database connection, a JMS queue connection) that a service may hold onto. Your code needs to know when the application has been undeployed and shutdown. This is actually quite easy, by using a service builder method. In your module class:adding some post-injection logic to your implementation class.

Code Block
controlstrue
languagejava
titleMyServiceImpl.java
linenumberstrue

public class MyServiceImpl publicimplements MyService
{
 buildMyService(ServiceResources resources,private RegistryShutdownHubboolean shutdownHub)
  {shuttingDown;

  private  final MyServiceImpl service = resources.autobuild(MyServiceImpl.class)Thread workerThread;

  public  shutdownHub.addRegistryShutdownListener(new RegistryShutdownListener(MyServiceImpl()
    {
    workerThread  public void registryDidShutdown()= new Thread(. . .);
  }

  . . {.

  @PostInjection
  public void   service.shutdown();
 startupService(RegistryShutdownHub shutdownHub)
  {
     }shutdownHub.addRegistryShutdownListener(new Runnable()
    });{

     return service;
public  }

This code uses the ServiceResources object to build an instance of MyServiceImpl, with all dependencies injected. It also injects Tapestry's RegistryShutdownHub service and adds a listener. The example assumes that the service implementation (but not the service interface) includes a shutdown() method.

A valid alternative to this would be to have MyServiceImpl implement RegistryShutdownListener:

Code Block
controlstrue
linenumberstrue

  public MyService buildMyService(ServiceResources resources, RegistryShutdownHub shutdownHub)
  {
    final MyServiceImpl service = resources.autobuild(MyServiceImpl.class);

    shutdownHub.addRegistryShutdownListener(service);

    return servicevoid run() 
      {
        shuttingDown = true;

        workerThread.interrupt();
      }
    });
  }
}

After Tapestry invokes the constructor of the service implementation, and after it performs any field injections, it invokes post injection methods. The methods must be public and return void. Parameters to a post injection method represent further injections ... in the above example, the RegistryShutdownHub is injected into the PostInjection method, since it is only used inside that one method.

Warning

It is not recommended that MyServiceImpl take RegistryShutdownHub as a constructor parameter and register itself as a listener inside the constructor. Doing so is an example of unsafe publishing, an unlikely but potential thread safety issue.

This same technique will work for any kind of resource that must be cleaned up or destroyed when the registry shuts down.

Note

Be careful not to invoke methods on any service proxy objects as they will also be shutting down with the Registry. A RegistryShutdownListener should not be reliant on anything outside of itself.

How do I make my service startup with the rest of the application, rather than lazily?

Tapestry services are designed to be lazy; they are only fully realized when needed: when the first method on the service interface is invoked.

Sometimes a service does extra work that is desirable at application startup: examples may be registering message handlers with a JMS implementation, or setting up indexing. Since the service's constructor (or @PostInjection methods) are not invoked until the service is realized.

The solution is the @EagerLoad annotation; service implementation classes marked with this annotation are loaded when the Registry is first startup, rather than lazily.

Wiki Markup
{scrollbar}