001// Copyright 2006, 2007, 2008, 2009, 2011 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.ioc.internal; 016 017import java.util.Collections; 018import java.util.List; 019 020import org.apache.tapestry5.ioc.Invokable; 021import org.apache.tapestry5.ioc.ObjectCreator; 022import org.apache.tapestry5.ioc.ServiceDecorator; 023import org.apache.tapestry5.ioc.def.ServiceDef3; 024 025/** 026 * Responsible for constructing the interceptor stack, on demand, by invoking an ordered series of decorators ( 027 * {@link org.apache.tapestry5.ioc.def.DecoratorDef} (which are converted into {@link ServiceDecorator}s). 028 */ 029public class InterceptorStackBuilder implements ObjectCreator 030{ 031 private final ServiceDef3 serviceDef; 032 033 private final ObjectCreator delegate; 034 035 private final InternalRegistry registry; 036 037 /** 038 * @param serviceDef 039 * service begin decorated 040 * @param delegate 041 * responsible for creating the object to be decorated 042 * @param registry 043 * access to service decorators 044 */ 045 public InterceptorStackBuilder(ServiceDef3 serviceDef, ObjectCreator delegate, InternalRegistry registry) 046 { 047 this.serviceDef = serviceDef; 048 this.delegate = delegate; 049 this.registry = registry; 050 } 051 052 @Override 053 public Object createObject() 054 { 055 Object current = delegate.createObject(); 056 057 List<ServiceDecorator> decorators = registry.findDecoratorsForService(serviceDef); 058 059 // We get the decorators ordered according to their dependencies. However, we want to 060 // process from the last interceptor to the first, so we reverse the list. 061 062 Collections.reverse(decorators); 063 064 for (final ServiceDecorator decorator : decorators) 065 { 066 final Object delegate = current; 067 068 Object interceptor = registry.invoke("Invoking " + decorator, new Invokable<Object>() 069 { 070 @Override 071 public Object invoke() 072 { 073 return decorator.createInterceptor(delegate); 074 } 075 }); 076 077 // Decorator methods may return null; this indicates that the decorator chose not to 078 // decorate. 079 080 if (interceptor != null) 081 current = interceptor; 082 } 083 084 // The stack of interceptors (plus the core service implementation) are "represented" to the 085 // outside world 086 // as the outermost interceptor. That will still be buried inside the service proxy. 087 088 return current; 089 } 090}