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    }