    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    }