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.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 }