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

 

Scrollbar

Info

Starting with Tapestry 5.1, Service Decoration is augmented with Service Advice. Advisors are similar but more general, as they work on any service interface, which doesn't have to be known at build time. Decoration is used when the type of the service being decorated is known at build time, and involves supplying a new implementation of the service interface.

...

Service Decoration Methods

Code Block
languagejava
titleAppModule.java (partial)
package org.example.myapp.services;

import org.apache.tapestry5.ioc.services.LoggingDecorator;
import org.slf4j.Logger;

public class MyAppModuleAppModule
{
  public static Indexer build()
  {
    return new IndexerImpl();
  }

  public static <T> T decorateIndexer(Class<T> serviceInterface, T delegate,
    String serviceId, Logger logger,

    LoggingDecorator decorator)
  {
    return decorator.build(serviceInterface, delegate, serviceId, logger);
  }
}

...

Alternately, when targetting services whose type is known at compile time, you may provide a parameter whose type matches the service interface. For example, decorateIndexer() will always be applied to the Indexer service, whose type (Indexer) is known. We could therefore rewrite decorateIndexer() as:

Code Block
java
languagejava
  public static Indexer decorateIndexer(Indexer delegate, Logger logger, LoggingDecorator decorator)
  {
    return decorator.build(Indexer.class, delegate, "Indexer", logger);
  }

Of course, nothing stops you from combining building with decorating inside the service builder method:

Code Block
languagejavajava
titleAppModule (partial)
package org.example.myapp.services;

import org.apache.tapestry5.ioc.services.LoggingDecorator;
import org.slf4j.Logger;

public class MyAppModuleAppModule
{
  public static Indexer build(Logger logger, LoggingDecorator decorator)
  {
    return decorator.build(Indexer.class, logger, new IndexerImpl());
  }
}

...

For example, to target all the services in your module:

Code Block
java
languagejava
  @Match("*")
  public static <T> T decorateLogging(Class<T> serviceInterface, T delegate,
    String serviceId, Logger logger,
    LoggingDecorator decorator)
  {
    return decorator.build(serviceInterface, delegate, serviceId, logger);
  }   

...

By way of an example, we'll show an implementation of the LoggingDecorator service:

Code Block
languagejava
titleLoggingDecoratorImpl.java
public class LoggingDecoratorImpl implements LoggingDecorator
{
    private final AspectDecorator aspectDecorator;

    private final ExceptionTracker exceptionTracker;

    public LoggingDecoratorImpl(AspectDecorator aspectDecorator, ExceptionTracker exceptionTracker)
    {
        this.aspectDecorator = aspectDecorator;
        this.exceptionTracker = exceptionTracker;
    }

    public <T> T build(Class<T> serviceInterface, T delegate, String serviceId, final Logger logger)
    {
        final ServiceLogger serviceLogger = new ServiceLogger(logger, exceptionTracker);

        MethodAdvice advice = new MethodAdvice()
        {
            public void advise(Invocation invocation)
            {
                boolean debug = logger.isDebugEnabled();

                if (debug) serviceLogger.entry(invocation);

                try
                {
                    invocation.proceed();
                }
                catch (RuntimeException ex)
                {
                    if (debug) serviceLogger.fail(invocation, ex);

                    throw ex;
                }

                if (!debug) return;

                if (invocation.isFail())
                {
                    Exception thrown = invocation.getThrown(Exception.class);

                    serviceLogger.fail(invocation, thrown);

                    return;
                }

                serviceLogger.exit(invocation);
            }
        };

        return aspectDecorator.build(serviceInterface, delegate, advice,
                                      String.format("<Logging interceptor for %s(%s)>", serviceId,
                                                    serviceInterface.getName()));
    }
}

...