001package 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 024import java.io.IOException; 025 026import org.apache.turbine.annotation.AnnotationProcessor; 027import org.apache.turbine.util.TurbineException; 028 029/** 030 * Flexible implementation of a {@link org.apache.turbine.pipeline.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 */ 037public class TurbinePipeline 038 implements Pipeline, ValveContext 039{ 040 /** 041 * The "Turbine Classic" pipeline. 042 */ 043 public static final 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.Pipeline#initialize() 067 */ 068 @Override 069 public void initialize() 070 throws Exception 071 { 072 if (state==null) 073 { 074 state = new ThreadLocal<Integer>(); 075 } 076 077 // Valve implementations are added to this Pipeline using the 078 // Mapper. 079 080 // Initialize the valves 081 for (int i = 0; i < valves.length; i++) 082 { 083 AnnotationProcessor.process(valves[i]); 084 valves[i].initialize(); 085 } 086 } 087 088 /** 089 * Set the name of this pipeline. 090 * 091 * @param name Name of this pipeline. 092 */ 093 public void setName(String name) 094 { 095 this.name = name; 096 } 097 098 /** 099 * 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}