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.annotation.AnnotationProcessor;
27 import org.apache.turbine.util.TurbineException;
28
29 /**
30 * Flexible implementation of a {@link org.apache.turbine.pipeline.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 final 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.Pipeline#initialize()
67 */
68 @Override
69 public void initialize()
70 throws Exception
71 {
72 if (state==null)
73 {
74 state = new ThreadLocal<Integer>();
75 }
76
77 // Valve implementations are added to this Pipeline using the
78 // Mapper.
79
80 // Initialize the valves
81 for (int i = 0; i < valves.length; i++)
82 {
83 AnnotationProcessor.process(valves[i]);
84 valves[i].initialize();
85 }
86 }
87
88 /**
89 * Set the name of this pipeline.
90 *
91 * @param name Name of this pipeline.
92 */
93 public void setName(String name)
94 {
95 this.name = name;
96 }
97
98 /**
99 * Get the name of this pipeline.
100 *
101 * @return String Name of this pipeline.
102 */
103 public String getName()
104 {
105 return name;
106 }
107
108 /**
109 * @see org.apache.turbine.pipeline.Pipeline#addValve(Valve)
110 */
111 @Override
112 public void addValve(Valve valve)
113 {
114 // Add this Valve to the set associated with this Pipeline
115 synchronized (valves)
116 {
117 Valve[] results = new Valve[valves.length + 1];
118 System.arraycopy(valves, 0, results, 0, valves.length);
119 results[valves.length] = valve;
120 valves = results;
121 }
122 }
123
124 /**
125 * @see org.apache.turbine.pipeline.Pipeline#getValves()
126 */
127 @Override
128 public Valve[] getValves()
129 {
130 synchronized (valves)
131 {
132 Valve[] results = new Valve[valves.length];
133 System.arraycopy(valves, 0, results, 0, valves.length);
134 return results;
135 }
136 }
137
138 /**
139 * @see org.apache.turbine.pipeline.Pipeline#removeValve(Valve)
140 */
141 @Override
142 public void removeValve(Valve valve)
143 {
144 synchronized (valves)
145 {
146 // Locate this Valve in our list
147 int index = -1;
148 for (int i = 0; i < valves.length; i++)
149 {
150 if (valve == valves[i])
151 {
152 index = i;
153 break;
154 }
155 }
156 if (index < 0)
157 {
158 return;
159 }
160
161 // Remove this valve from our list
162 Valve[] results = new Valve[valves.length - 1];
163 int n = 0;
164 for (int i = 0; i < valves.length; i++)
165 {
166 if (i == index)
167 {
168 continue;
169 }
170 results[n++] = valves[i];
171 }
172 valves = results;
173 }
174 }
175
176 /**
177 * @see org.apache.turbine.pipeline.Pipeline#invoke(PipelineData)
178 */
179 @Override
180 public void invoke(PipelineData pipelineData)
181 throws TurbineException, IOException
182 {
183 // Initialize the per-thread state for this thread
184 state.set(Integer.valueOf(0));
185
186 // Invoke the first Valve in this pipeline for this request
187 invokeNext(pipelineData);
188 }
189
190 /**
191 * @see org.apache.turbine.pipeline.ValveContext#invokeNext(PipelineData)
192 */
193 @Override
194 public void invokeNext(PipelineData pipelineData)
195 throws TurbineException, IOException
196 {
197 // Identify the current subscript for the current request thread
198 Integer current = state.get();
199 int subscript = current.intValue();
200
201 if (subscript < valves.length)
202 {
203 // Invoke the requested Valve for the current request
204 // thread and increment its thread-local state.
205 state.set(Integer.valueOf(subscript + 1));
206 valves[subscript].invoke(pipelineData, this);
207 }
208 }
209 }