public Object createObject() {
    Object current = coreServiceCreator.createObject();

    List<ServiceDecorator> decorators = module.findDecoratorsForService(serviceId);

    // We get the decorators ordered according to their dependencies. However, we want to
    // process from the last interceptor to the first, so we reverse the list.

    Collections.reverse(decorators);

    for (final ServiceDecorator decorator : decorators) {
      final Object delegate = current;

      Object interceptor =
          tracker.invoke(
              "Invoking " + decorator,
              new Invokable<Object>() {
                public Object invoke() {
                  return decorator.createInterceptor(delegate);
                }
              });

      // Decorator methods may return null; this indicates that the decorator chose not to
      // decorate.

      if (interceptor != null) current = interceptor;
    }

    // The stack of interceptors (plus the core service implementation) are "represented" to the
    // outside world
    // as the outermost interceptor. That will still be buried inside the service proxy.

    return current;
  }
  /**
   * For each thread, the first call will use the delegate {@link
   * org.apache.tapestry5.ioc.ObjectCreator} to create an instance, and later calls will reuse the
   * same per-thread instance. The instance is stored in the {@link
   * org.apache.tapestry5.ioc.services.PerthreadManager} and will be released at the end of the
   * request.
   */
  public Object createObject() {
    if (perThreadValue.exists()) return perThreadValue.get();

    return perThreadValue.set(delegate.createObject());
  }