    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}