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 }