View Javadoc

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 }