001    package org.apache.turbine.pipeline;
002    
003    
004    /*
005     * Licensed to the Apache Software Foundation (ASF) under one
006     * or more contributor license agreements.  See the NOTICE file
007     * distributed with this work for additional information
008     * regarding copyright ownership.  The ASF licenses this file
009     * to you under the Apache License, Version 2.0 (the
010     * "License"); you may not use this file except in compliance
011     * with the License.  You may obtain a copy of the License at
012     *
013     *   http://www.apache.org/licenses/LICENSE-2.0
014     *
015     * Unless required by applicable law or agreed to in writing,
016     * software distributed under the License is distributed on an
017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018     * KIND, either express or implied.  See the License for the
019     * specific language governing permissions and limitations
020     * under the License.
021     */
022    
023    
024    import java.io.IOException;
025    
026    import org.apache.turbine.util.RunData;
027    import org.apache.turbine.util.TurbineException;
028    
029    /**
030     * Flexible implementation of a {@link org.apache.turbine.Pipeline}.
031     * Originally based on code from Catalina and ideas from Apache httpd.
032     *
033     * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
034     * @author <a href="mailto:jvanzyl@zenplex.com">Jason van Zyl</a>
035     * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
036     */
037    public class TurbinePipeline
038        implements Pipeline, ValveContext
039    {
040        /**
041         * The "Turbine Classic" pipeline.
042         */
043        public static String CLASSIC_PIPELINE =
044            "WEB-INF/conf/turbine-classic-pipeline.xml";
045    
046        /**
047         * Name of this pipeline.
048         */
049        protected String name;
050    
051        /**
052         * The set of Valves associated with this Pipeline.
053         */
054        protected Valve[] valves = new Valve[0];
055    
056        /**
057         * The per-thread execution state for processing through this
058         * pipeline.  The actual value is a java.lang.Integer object
059         * containing the subscript into the <code>values</code> array, or
060         * a subscript equal to <code>values.length</code> if the basic
061         * Valve is currently being processed.
062         */
063        protected ThreadLocal<Integer> state= new ThreadLocal<Integer>();
064    
065        /**
066         * @see org.apache.turbine.Pipeline#initialize()
067         */
068        public void initialize()
069            throws Exception
070        {
071            if (state==null)
072            {
073                state = new ThreadLocal<Integer>();
074            }
075    
076            // Valve implementations are added to this Pipeline using the
077            // Mapper.
078    
079            // Initialize the valves
080            for (int i = 0; i < valves.length; i++)
081            {
082                valves[i].initialize();
083            }
084        }
085    
086        /**
087         * Set the name of this pipeline.
088         *
089         * @param name Name of this pipeline.
090         */
091        public void setName(String name)
092        {
093            this.name = name;
094        }
095    
096        /**
097         * Get the name of this pipeline.
098         *
099         * @return String Name of this pipeline.
100         */
101        public String getName()
102        {
103            return name;
104        }
105    
106        /**
107         * @see org.apache.turbine.Pipeline#addValve(Valve)
108         */
109        public void addValve(Valve valve)
110        {
111            // Add this Valve to the set associated with this Pipeline
112            synchronized (valves)
113            {
114                Valve[] results = new Valve[valves.length + 1];
115                System.arraycopy(valves, 0, results, 0, valves.length);
116                results[valves.length] = valve;
117                valves = results;
118            }
119        }
120    
121        /**
122         * @see org.apache.turbine.Pipeline#getValves()
123         */
124        public Valve[] getValves()
125        {
126            synchronized (valves)
127            {
128                Valve[] results = new Valve[valves.length];
129                System.arraycopy(valves, 0, results, 0, valves.length);
130                return results;
131            }
132        }
133    
134        /**
135         * @see org.apache.turbine.Pipeline#removeValve(Valve)
136         */
137        public void removeValve(Valve valve)
138        {
139            synchronized (valves)
140            {
141                // Locate this Valve in our list
142                int index = -1;
143                for (int i = 0; i < valves.length; i++)
144                {
145                    if (valve == valves[i])
146                    {
147                        index = i;
148                        break;
149                    }
150                }
151                if (index < 0)
152                {
153                    return;
154                }
155    
156                // Remove this valve from our list
157                Valve[] results = new Valve[valves.length - 1];
158                int n = 0;
159                for (int i = 0; i < valves.length; i++)
160                {
161                    if (i == index)
162                    {
163                        continue;
164                    }
165                    results[n++] = valves[i];
166                }
167                valves = results;
168            }
169        }
170    
171        /**
172         * @see org.apache.turbine.Pipeline#invoke(RunData)
173         */
174        public void invoke(PipelineData pipelineData)
175            throws TurbineException, IOException
176        {
177            // Initialize the per-thread state for this thread
178            state.set(Integer.valueOf(0));
179    
180            // Invoke the first Valve in this pipeline for this request
181            invokeNext(pipelineData);
182        }
183    
184        /**
185         * @see org.apache.turbine.ValveContext#invokeNext(RunData)
186         */
187        public void invokeNext(PipelineData pipelineData)
188            throws TurbineException, IOException
189        {
190            // Identify the current subscript for the current request thread
191            Integer current = state.get();
192            int subscript = current.intValue();
193    
194            if (subscript < valves.length)
195            {
196                // Invoke the requested Valve for the current request
197                // thread and increment its thread-local state.
198                state.set(Integer.valueOf(subscript + 1));
199                valves[subscript].invoke(pipelineData, this);
200            }
201        }
202    }