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 015 package org.apache.tapestry5.ioc.internal; 016 017 import java.util.Collections; 018 import java.util.List; 019 020 import org.apache.tapestry5.ioc.Invokable; 021 import org.apache.tapestry5.ioc.ObjectCreator; 022 import org.apache.tapestry5.ioc.ServiceDecorator; 023 import 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 */ 029 public 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 public Object createObject() 053 { 054 Object current = delegate.createObject(); 055 056 List<ServiceDecorator> decorators = registry.findDecoratorsForService(serviceDef); 057 058 // We get the decorators ordered according to their dependencies. However, we want to 059 // process from the last interceptor to the first, so we reverse the list. 060 061 Collections.reverse(decorators); 062 063 for (final ServiceDecorator decorator : decorators) 064 { 065 final Object delegate = current; 066 067 Object interceptor = registry.invoke("Invoking " + decorator, new Invokable<Object>() 068 { 069 public Object invoke() 070 { 071 return decorator.createInterceptor(delegate); 072 } 073 }); 074 075 // Decorator methods may return null; this indicates that the decorator chose not to 076 // decorate. 077 078 if (interceptor != null) 079 current = interceptor; 080 } 081 082 // The stack of interceptors (plus the core service implementation) are "represented" to the 083 // outside world 084 // as the outermost interceptor. That will still be buried inside the service proxy. 085 086 return current; 087 } 088 }