001package org.apache.turbine.pipeline; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.IOException; 023import java.util.Iterator; 024import java.util.concurrent.CopyOnWriteArrayList; 025 026import javax.xml.bind.annotation.XmlAccessType; 027import javax.xml.bind.annotation.XmlAccessorType; 028import javax.xml.bind.annotation.XmlAttribute; 029import javax.xml.bind.annotation.XmlElement; 030import javax.xml.bind.annotation.XmlElementWrapper; 031import javax.xml.bind.annotation.XmlRootElement; 032import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 033 034import org.apache.turbine.annotation.AnnotationProcessor; 035import org.apache.turbine.util.TurbineException; 036 037/** 038 * Flexible implementation of a {@link org.apache.turbine.pipeline.Pipeline}. 039 * Originally based on code from Catalina and ideas from Apache httpd. 040 * 041 * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> 042 * @author <a href="mailto:jvanzyl@zenplex.com">Jason van Zyl</a> 043 * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a> 044 */ 045@XmlRootElement(name="pipeline") 046@XmlAccessorType(XmlAccessType.NONE) 047public class TurbinePipeline 048 implements Pipeline, ValveContext 049{ 050 /** 051 * The "Turbine Classic" pipeline. 052 */ 053 public static final String CLASSIC_PIPELINE = 054 "/WEB-INF/conf/turbine-classic-pipeline.xml"; 055 056 /** 057 * Name of this pipeline. 058 */ 059 @XmlAttribute 060 private String name; 061 062 /** 063 * The set of Valves associated with this Pipeline. 064 */ 065 private CopyOnWriteArrayList<Valve> valves = new CopyOnWriteArrayList<>(); 066 067 /** 068 * The per-thread execution state for processing through this pipeline. 069 */ 070 private ThreadLocal<Iterator<Valve>> state = new ThreadLocal<>(); 071 072 /** 073 * @see org.apache.turbine.pipeline.Pipeline#initialize() 074 */ 075 @Override 076 public void initialize() 077 throws Exception 078 { 079 // Valve implementations are added to this Pipeline using the 080 // Mapper. 081 082 // Initialize the valves 083 for (Valve v : valves) 084 { 085 AnnotationProcessor.process(v); 086 v.initialize(); 087 } 088 } 089 090 /** 091 * Set the name of this pipeline. 092 * 093 * @param name 094 * Name of this pipeline. 095 */ 096 public void setName(String name) 097 { 098 this.name = name; 099 } 100 101 /** 102 * Get the name of this pipeline. 103 * 104 * @return String Name of this pipeline. 105 */ 106 public String getName() 107 { 108 return name; 109 } 110 111 /** 112 * @see org.apache.turbine.pipeline.Pipeline#addValve(Valve) 113 */ 114 @Override 115 public void addValve(Valve valve) 116 { 117 // Add this Valve to the end of the set associated with this Pipeline 118 valves.add(valve); 119 } 120 121 /** 122 * @see org.apache.turbine.pipeline.Pipeline#getValves() 123 */ 124 @Override 125 @XmlElementWrapper(name="valves") 126 @XmlElement(name="valve") 127 @XmlJavaTypeAdapter(XmlValveAdapter.class) 128 public Valve[] getValves() 129 { 130 return valves.toArray(new Valve[0]); 131 } 132 133 /** 134 * Set new valves during deserialization 135 * 136 * @param valves the valves to set 137 */ 138 protected void setValves(Valve[] valves) 139 { 140 this.valves = new CopyOnWriteArrayList<>(valves); 141 } 142 143 /** 144 * @see org.apache.turbine.pipeline.Pipeline#removeValve(Valve) 145 */ 146 @Override 147 public void removeValve(Valve valve) 148 { 149 valves.remove(valve); 150 } 151 152 /** 153 * @see org.apache.turbine.pipeline.Pipeline#invoke(PipelineData) 154 */ 155 @Override 156 public void invoke(PipelineData pipelineData) 157 throws TurbineException, IOException 158 { 159 // Initialize the per-thread state for this thread 160 state.set(valves.iterator()); 161 162 // Invoke the first Valve in this pipeline for this request 163 invokeNext(pipelineData); 164 } 165 166 /** 167 * @see org.apache.turbine.pipeline.ValveContext#invokeNext(PipelineData) 168 */ 169 @Override 170 public void invokeNext(PipelineData pipelineData) 171 throws TurbineException, IOException 172 { 173 // Identify the current valve for the current request thread 174 Iterator<Valve> current = state.get(); 175 176 if (current.hasNext()) 177 { 178 // Invoke the requested Valve for the current request 179 // thread and increment its thread-local state. 180 current.next().invoke(pipelineData, this); 181 } 182 } 183}