1 package org.apache.turbine.pipeline;
2
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23
24 import java.io.IOException;
25
26 import org.apache.turbine.util.RunData;
27 import org.apache.turbine.util.TurbineException;
28
29 /**
30 * Flexible implementation of a {@link org.apache.turbine.Pipeline}.
31 * Originally based on code from Catalina and ideas from Apache httpd.
32 *
33 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
34 * @author <a href="mailto:jvanzyl@zenplex.com">Jason van Zyl</a>
35 * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
36 */
37 public class TurbinePipeline
38 implements Pipeline, ValveContext
39 {
40 /**
41 * The "Turbine Classic" pipeline.
42 */
43 public static String CLASSIC_PIPELINE =
44 "WEB-INF/conf/turbine-classic-pipeline.xml";
45
46 /**
47 * Name of this pipeline.
48 */
49 protected String name;
50
51 /**
52 * The set of Valves associated with this Pipeline.
53 */
54 protected Valve[] valves = new Valve[0];
55
56 /**
57 * The per-thread execution state for processing through this
58 * pipeline. The actual value is a java.lang.Integer object
59 * containing the subscript into the <code>values</code> array, or
60 * a subscript equal to <code>values.length</code> if the basic
61 * Valve is currently being processed.
62 */
63 protected ThreadLocal<Integer> state= new ThreadLocal<Integer>();
64
65 /**
66 * @see org.apache.turbine.Pipeline#initialize()
67 */
68 public void initialize()
69 throws Exception
70 {
71 if (state==null)
72 {
73 state = new ThreadLocal<Integer>();
74 }
75
76 // Valve implementations are added to this Pipeline using the
77 // Mapper.
78
79 // Initialize the valves
80 for (int i = 0; i < valves.length; i++)
81 {
82 valves[i].initialize();
83 }
84 }
85
86 /**
87 * Set the name of this pipeline.
88 *
89 * @param name Name of this pipeline.
90 */
91 public void setName(String name)
92 {
93 this.name = name;
94 }
95
96 /**
97 * Get the name of this pipeline.
98 *
99 * @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 }